@fboes/aerofly-custom-missions 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +1 -5
- package/.eslintrc.json +24 -0
- package/CHANGELOG.md +59 -21
- package/dist/dto/AeroflyLocalizedText.js +44 -0
- package/dist/dto/AeroflyMission.js +173 -0
- package/dist/dto/AeroflyMissionCheckpoint.js +127 -0
- package/dist/dto/AeroflyMissionConditions.js +124 -0
- package/dist/dto/AeroflyMissionConditionsCloud.js +90 -0
- package/dist/dto/AeroflyMissionTargetPlane.js +35 -0
- package/dist/dto/AeroflyMissionsList.js +36 -0
- package/dist/index.js +7 -634
- package/dist/index.test.js +17 -11
- package/dist/node/AeroflyConfigurationNode.js +82 -0
- package/docs/custom_missions_user.tmc +3 -6
- package/docs/custom_missions_user.xml +100 -0
- package/package.json +9 -10
- package/src/dto/AeroflyLocalizedText.ts +74 -0
- package/src/dto/AeroflyMission.ts +372 -0
- package/src/dto/AeroflyMissionCheckpoint.ts +234 -0
- package/src/dto/AeroflyMissionConditions.ts +189 -0
- package/src/dto/AeroflyMissionConditionsCloud.ts +111 -0
- package/src/dto/AeroflyMissionTargetPlane.ts +62 -0
- package/src/dto/AeroflyMissionsList.ts +52 -0
- package/src/index.test.ts +22 -25
- package/src/index.ts +7 -1099
- package/src/node/AeroflyConfigurationNode.ts +89 -0
- package/types/AeroflyMissionCheckpoint.d.ts +140 -0
- package/types/AeroflyMissionTargetPlane.d.ts +40 -0
- package/types/dto/AeroflyConfigFileSet.d.ts +10 -0
- package/types/dto/AeroflyConfigFileSet.d.ts.map +1 -0
- package/types/dto/AeroflyConfiguration.interface.d.ts +4 -0
- package/types/dto/AeroflyConfiguration.interface.d.ts.map +1 -0
- package/types/dto/AeroflyLocalizedText.d.ts +58 -0
- package/types/dto/AeroflyLocalizedText.d.ts.map +1 -0
- package/types/dto/AeroflyMission.d.ts +163 -0
- package/types/dto/AeroflyMission.d.ts.map +1 -0
- package/types/dto/AeroflyMissionCheckpoint.d.ts +126 -0
- package/types/dto/AeroflyMissionCheckpoint.d.ts.map +1 -0
- package/types/dto/AeroflyMissionConditions.d.ts +102 -0
- package/types/dto/AeroflyMissionConditions.d.ts.map +1 -0
- package/types/dto/AeroflyMissionConditionsCloud.d.ts +57 -0
- package/types/dto/AeroflyMissionConditionsCloud.d.ts.map +1 -0
- package/types/dto/AeroflyMissionTargetPlane.d.ts +45 -0
- package/types/dto/AeroflyMissionTargetPlane.d.ts.map +1 -0
- package/types/dto/AeroflyMissionsList.d.ts +30 -0
- package/types/dto/AeroflyMissionsList.d.ts.map +1 -0
- package/types/dto/basicTypes.d.ts +1 -0
- package/types/index.d.ts +7 -585
- package/types/index.d.ts.map +1 -1
- package/types/node/AeroflyConfigurationNode.d.ts +14 -0
- package/types/node/AeroflyConfigurationNode.d.ts.map +1 -0
- package/eslint.config.js +0 -29
package/src/index.ts
CHANGED
|
@@ -1,1099 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
9
|
-
* of decimal degrees; -180..180
|
|
10
|
-
* @property latitude northing, using the World Geodetic
|
|
11
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
12
|
-
* of decimal degrees; -90..90
|
|
13
|
-
* @property dir in degree
|
|
14
|
-
* @property alt the height in meters above or below the WGS
|
|
15
|
-
* 84 reference ellipsoid
|
|
16
|
-
*/
|
|
17
|
-
export type AeroflyMissionPosition = {
|
|
18
|
-
icao: string;
|
|
19
|
-
longitude: number;
|
|
20
|
-
latitude: number;
|
|
21
|
-
dir: number;
|
|
22
|
-
alt: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* State of aircraft systems. Configures power settings, flap positions etc
|
|
27
|
-
*/
|
|
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";
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Types of checkpoints. Required are usually "origin", "departure_runway" at the start and "destination_runway", "destination" at the end.
|
|
42
|
-
*/
|
|
43
|
-
export type AeroflyMissionCheckpointType =
|
|
44
|
-
| "origin"
|
|
45
|
-
| "departure_runway"
|
|
46
|
-
| "departure"
|
|
47
|
-
| "waypoint"
|
|
48
|
-
| "arrival"
|
|
49
|
-
| "approach"
|
|
50
|
-
| "destination_runway"
|
|
51
|
-
| "destination";
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Data for the aircraft to use on this mission
|
|
55
|
-
* @property name lowercase Aerofly aircraft ID
|
|
56
|
-
* @property icao ICAO aircraft code
|
|
57
|
-
* @property livery (not used yet)
|
|
58
|
-
*/
|
|
59
|
-
export type AeroflyMissionAircraft = {
|
|
60
|
-
name: string;
|
|
61
|
-
icao: string;
|
|
62
|
-
livery: string;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Weather data for wind
|
|
67
|
-
* @property direction in degree
|
|
68
|
-
* @property speed in kts
|
|
69
|
-
* @property gusts in kts
|
|
70
|
-
*/
|
|
71
|
-
export type AeroflyMissionConditionsWind = {
|
|
72
|
-
direction: number;
|
|
73
|
-
speed: number;
|
|
74
|
-
gusts: number;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Cloud coverage codes
|
|
79
|
-
*/
|
|
80
|
-
export type AeroflyMissionConditionsCloudCoverCode = "CLR" | "FEW" | "SCT" | "BKN" | "OVC";
|
|
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
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @class
|
|
120
|
-
* A list of flight plans.
|
|
121
|
-
*
|
|
122
|
-
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
123
|
-
* `custom_missions_user.tmc` flight plan file format, and export the structure
|
|
124
|
-
* for this file via the `toString()` method.
|
|
125
|
-
*/
|
|
126
|
-
export class AeroflyMissionsList {
|
|
127
|
-
/**
|
|
128
|
-
* @property {AeroflyMission[]} missions in this mission list
|
|
129
|
-
*/
|
|
130
|
-
missions: AeroflyMission[];
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* @param {AeroflyMission[]} missions in this mission list
|
|
134
|
-
*/
|
|
135
|
-
constructor(missions: AeroflyMission[] = []) {
|
|
136
|
-
this.missions = missions;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
141
|
-
*/
|
|
142
|
-
toString(): string {
|
|
143
|
-
const separator = "\n// -----------------------------------------------------------------------------\n";
|
|
144
|
-
return `\
|
|
145
|
-
<[file][][]
|
|
146
|
-
<[tmmissions_list][][]
|
|
147
|
-
<[list_tmmission_definition][missions][]${separator + this.missions.join(separator) + separator} >
|
|
148
|
-
>
|
|
149
|
-
>`;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* @class
|
|
155
|
-
* A single flighplan, containing aircraft and weather data as well.
|
|
156
|
-
*
|
|
157
|
-
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
158
|
-
* `custom_missions_user.tmc` flight plan file format, and export the structure
|
|
159
|
-
* for this file via the `toString()` method.
|
|
160
|
-
*/
|
|
161
|
-
export class AeroflyMission {
|
|
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;
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* @property {string} title of this flight plan
|
|
169
|
-
*/
|
|
170
|
-
title: string;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* @property {string} description text, mission briefing, etc
|
|
174
|
-
*/
|
|
175
|
-
description: string;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* @property {AeroflyLocalizedText[]} localizedTexts for title and description
|
|
179
|
-
*/
|
|
180
|
-
localizedTexts: AeroflyLocalizedText[];
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* @property {string[]} tags
|
|
184
|
-
*/
|
|
185
|
-
tags: string[];
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* @property {?boolean} isFeatured makes this mission pop up in "Challenges"
|
|
189
|
-
*/
|
|
190
|
-
isFeatured: boolean | null;
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* @property {?number} difficulty values between 0.00 and 2.00 have been encountered, but they seem to be without limit
|
|
194
|
-
*/
|
|
195
|
-
difficulty: number | null;
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* @property {"cold_and_dark"|"before_start"|"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"|"pushback"} flightSetting of aircraft, like "taxi", "cruise"
|
|
199
|
-
*/
|
|
200
|
-
flightSetting: AeroflyMissionSetting;
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* @property {object} aircraft for this mission
|
|
204
|
-
*/
|
|
205
|
-
aircraft: AeroflyMissionAircraft;
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* @property {string} callsign of aircraft, uppercased
|
|
209
|
-
*/
|
|
210
|
-
callsign: string;
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* @property {object} origin position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
214
|
-
*/
|
|
215
|
-
origin: AeroflyMissionPosition;
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* @property {object} destination position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
219
|
-
*/
|
|
220
|
-
destination: AeroflyMissionPosition;
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* @property {?number} distance in meters
|
|
224
|
-
*/
|
|
225
|
-
distance: number | null;
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* @property {?number} duration in seconds
|
|
229
|
-
*/
|
|
230
|
-
duration: number | null;
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* @property {?boolean} isScheduled marks this flight as "Scheduled flight".
|
|
234
|
-
*/
|
|
235
|
-
isScheduled: boolean | null;
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @property {?AeroflyMissionTargetPlane} finish as finish condition
|
|
239
|
-
*/
|
|
240
|
-
finish: AeroflyMissionTargetPlane | null;
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* @property {AeroflyMissionConditions} conditions like time and weather for mission
|
|
244
|
-
*/
|
|
245
|
-
conditions: AeroflyMissionConditions;
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* @property {AeroflyMissionConditions} checkpoints form the actual flight plan
|
|
249
|
-
*/
|
|
250
|
-
checkpoints: AeroflyMissionCheckpoint[];
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* @param {string} title of this flight plan
|
|
254
|
-
* @param {object} [additionalAttributes] allows to set additional attributes on creation
|
|
255
|
-
* @param {string} [additionalAttributes.description] text, mission briefing, etc
|
|
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/
|
|
258
|
-
* @param {string[]} [additionalAttributes.tags]
|
|
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"
|
|
262
|
-
* @param {{name:string,livery:string,icao:string}} [additionalAttributes.aircraft] for this mission
|
|
263
|
-
* @param {string} [additionalAttributes.callsign] of aircraft, uppercased
|
|
264
|
-
* @param {object} [additionalAttributes.origin] position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
265
|
-
* @param {object} [additionalAttributes.destination] position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
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".
|
|
269
|
-
* @param {?AeroflyMissionTargetPlane} [additionalAttributes.finish] as finish condition
|
|
270
|
-
* @param {AeroflyMissionConditions} [additionalAttributes.conditions] like time and weather for mission
|
|
271
|
-
* @param {AeroflyMissionCheckpoint[]} [additionalAttributes.checkpoints] form the actual flight plan
|
|
272
|
-
*/
|
|
273
|
-
constructor(
|
|
274
|
-
title: string,
|
|
275
|
-
{
|
|
276
|
-
tutorialName = null,
|
|
277
|
-
description = "",
|
|
278
|
-
localizedTexts = [],
|
|
279
|
-
tags = [],
|
|
280
|
-
isFeatured = null,
|
|
281
|
-
difficulty = null,
|
|
282
|
-
flightSetting = "taxi",
|
|
283
|
-
aircraft = {
|
|
284
|
-
name: "c172",
|
|
285
|
-
icao: "",
|
|
286
|
-
livery: "",
|
|
287
|
-
},
|
|
288
|
-
callsign = "",
|
|
289
|
-
origin = {
|
|
290
|
-
icao: "",
|
|
291
|
-
longitude: 0,
|
|
292
|
-
latitude: 0,
|
|
293
|
-
dir: 0,
|
|
294
|
-
alt: 0,
|
|
295
|
-
},
|
|
296
|
-
destination = {
|
|
297
|
-
icao: "",
|
|
298
|
-
longitude: 0,
|
|
299
|
-
latitude: 0,
|
|
300
|
-
dir: 0,
|
|
301
|
-
alt: 0,
|
|
302
|
-
},
|
|
303
|
-
distance = null,
|
|
304
|
-
duration = null,
|
|
305
|
-
isScheduled = null,
|
|
306
|
-
finish = null,
|
|
307
|
-
conditions = new AeroflyMissionConditions(),
|
|
308
|
-
checkpoints = [],
|
|
309
|
-
}: {
|
|
310
|
-
tutorialName?: string | null;
|
|
311
|
-
description?: string;
|
|
312
|
-
localizedTexts?: AeroflyLocalizedText[];
|
|
313
|
-
tags?: string[];
|
|
314
|
-
isFeatured?: boolean | null;
|
|
315
|
-
difficulty?: number | null;
|
|
316
|
-
flightSetting?: AeroflyMissionSetting;
|
|
317
|
-
aircraft?: AeroflyMissionAircraft;
|
|
318
|
-
callsign?: string;
|
|
319
|
-
origin?: AeroflyMissionPosition;
|
|
320
|
-
destination?: AeroflyMissionPosition;
|
|
321
|
-
distance?: number | null;
|
|
322
|
-
duration?: number | null;
|
|
323
|
-
isScheduled?: boolean | null;
|
|
324
|
-
finish?: AeroflyMissionTargetPlane | null;
|
|
325
|
-
conditions?: AeroflyMissionConditions;
|
|
326
|
-
checkpoints?: AeroflyMissionCheckpoint[];
|
|
327
|
-
} = {},
|
|
328
|
-
) {
|
|
329
|
-
this.tutorialName = tutorialName;
|
|
330
|
-
this.title = title;
|
|
331
|
-
this.checkpoints = checkpoints;
|
|
332
|
-
this.description = description;
|
|
333
|
-
this.localizedTexts = localizedTexts;
|
|
334
|
-
this.tags = tags;
|
|
335
|
-
this.isFeatured = isFeatured;
|
|
336
|
-
this.difficulty = difficulty;
|
|
337
|
-
this.flightSetting = flightSetting;
|
|
338
|
-
this.aircraft = aircraft;
|
|
339
|
-
this.callsign = callsign;
|
|
340
|
-
this.origin = origin;
|
|
341
|
-
this.destination = destination;
|
|
342
|
-
this.distance = distance;
|
|
343
|
-
this.duration = duration;
|
|
344
|
-
this.isScheduled = isScheduled;
|
|
345
|
-
this.finish = finish;
|
|
346
|
-
this.conditions = conditions;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* @returns {string} indexed checkpoints
|
|
351
|
-
*/
|
|
352
|
-
getCheckpointsString(): string {
|
|
353
|
-
return this.checkpoints
|
|
354
|
-
.map((c: AeroflyMissionCheckpoint, index: number): string => {
|
|
355
|
-
return c.toString(index);
|
|
356
|
-
})
|
|
357
|
-
.join("\n");
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* @returns {string} indexed checkpoints
|
|
362
|
-
*/
|
|
363
|
-
getLocalizedTextsString(): string {
|
|
364
|
-
return this.localizedTexts
|
|
365
|
-
.map((c: AeroflyLocalizedText, index: number): string => {
|
|
366
|
-
return c.toString(index);
|
|
367
|
-
})
|
|
368
|
-
.join("\n");
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* @throws {Error} on missing waypoints
|
|
373
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
374
|
-
*/
|
|
375
|
-
toString(): string {
|
|
376
|
-
if (!this.origin.icao) {
|
|
377
|
-
const firstCheckpoint = this.checkpoints[0];
|
|
378
|
-
this.origin = {
|
|
379
|
-
icao: firstCheckpoint.name,
|
|
380
|
-
longitude: firstCheckpoint.longitude,
|
|
381
|
-
latitude: firstCheckpoint.latitude,
|
|
382
|
-
dir: this.origin.dir,
|
|
383
|
-
alt: firstCheckpoint.altitude,
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (!this.destination.icao) {
|
|
388
|
-
const lastCheckpoint = this.checkpoints[this.checkpoints.length - 1];
|
|
389
|
-
this.destination = {
|
|
390
|
-
icao: lastCheckpoint.name,
|
|
391
|
-
longitude: lastCheckpoint.longitude,
|
|
392
|
-
latitude: lastCheckpoint.latitude,
|
|
393
|
-
dir: lastCheckpoint.direction ?? 0,
|
|
394
|
-
alt: lastCheckpoint.altitude,
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
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
|
-
}
|
|
410
|
-
if (this.localizedTexts.length > 0) {
|
|
411
|
-
fileSet.pushRaw(
|
|
412
|
-
new AeroflyConfigFileSet(4, "list_tmmission_definition_localized", "localized_text")
|
|
413
|
-
.pushRaw(this.getLocalizedTextsString())
|
|
414
|
-
.toString(),
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
if (this.tags.length > 0) {
|
|
418
|
-
fileSet.push("string8u", "tags", this.tags.join(" "));
|
|
419
|
-
}
|
|
420
|
-
if (this.difficulty !== null) {
|
|
421
|
-
fileSet.push("float64", "difficulty", this.difficulty);
|
|
422
|
-
}
|
|
423
|
-
if (this.isFeatured !== null) {
|
|
424
|
-
fileSet.push("bool", "is_featured", this.isFeatured);
|
|
425
|
-
}
|
|
426
|
-
|
|
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`);
|
|
450
|
-
}
|
|
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");
|
|
456
|
-
}
|
|
457
|
-
if (this.finish !== null) {
|
|
458
|
-
fileSet.pushRaw(this.finish.toString());
|
|
459
|
-
}
|
|
460
|
-
|
|
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();
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* @class
|
|
476
|
-
* Time and weather data for the given flight plan
|
|
477
|
-
*
|
|
478
|
-
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
479
|
-
* `custom_missions_user.tmc` flight plan file format, and export the structure
|
|
480
|
-
* for this file via the `toString()` method.
|
|
481
|
-
*/
|
|
482
|
-
export class AeroflyMissionConditions {
|
|
483
|
-
/**
|
|
484
|
-
* @property {Date} time of flight plan. Relevant is the UTC part, so
|
|
485
|
-
* consider setting this date in UTC.
|
|
486
|
-
*/
|
|
487
|
-
time: Date;
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* @property {object} wind state
|
|
491
|
-
*/
|
|
492
|
-
wind: AeroflyMissionConditionsWind;
|
|
493
|
-
|
|
494
|
-
/**
|
|
495
|
-
* @property {number} 0..1, percentage
|
|
496
|
-
*/
|
|
497
|
-
turbulenceStrength: number;
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* @property {number} 0..1, percentage
|
|
501
|
-
*/
|
|
502
|
-
thermalStrength: number;
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* @property {number} visibility in meters
|
|
506
|
-
*/
|
|
507
|
-
visibility: number;
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* @property {AeroflyMissionConditionsCloud[]} clouds for the whole flight
|
|
511
|
-
*/
|
|
512
|
-
clouds: AeroflyMissionConditionsCloud[] = [];
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
516
|
-
* @param {Date} [additionalAttributes.time] of flight plan. Relevant is the UTC part, so
|
|
517
|
-
* consider setting this date in UTC.
|
|
518
|
-
* @param {{direction: number, speed: number, gusts: number}} [additionalAttributes.wind] state
|
|
519
|
-
* @param {number} [additionalAttributes.turbulenceStrength] 0..1, percentage
|
|
520
|
-
* @param {number} [additionalAttributes.thermalStrength] 0..1, percentage
|
|
521
|
-
* @param {number} [additionalAttributes.visibility] in meters
|
|
522
|
-
* @param {?number} [additionalAttributes.visibility_sm] in statute miles, will overwrite visibility
|
|
523
|
-
* @param {?number} [additionalAttributes.temperature] in °C, will overwrite thermalStrength
|
|
524
|
-
* @param {AeroflyMissionConditionsCloud[]} [additionalAttributes.clouds] for the whole flight
|
|
525
|
-
*/
|
|
526
|
-
constructor({
|
|
527
|
-
time = new Date(),
|
|
528
|
-
wind = {
|
|
529
|
-
direction: 0,
|
|
530
|
-
speed: 0,
|
|
531
|
-
gusts: 0,
|
|
532
|
-
},
|
|
533
|
-
turbulenceStrength = 0,
|
|
534
|
-
thermalStrength = 0,
|
|
535
|
-
visibility = 25_000,
|
|
536
|
-
visibility_sm = null,
|
|
537
|
-
temperature = null,
|
|
538
|
-
clouds = [],
|
|
539
|
-
}: {
|
|
540
|
-
time?: Date;
|
|
541
|
-
wind?: {
|
|
542
|
-
direction: number;
|
|
543
|
-
speed: number;
|
|
544
|
-
gusts: number;
|
|
545
|
-
};
|
|
546
|
-
turbulenceStrength?: number;
|
|
547
|
-
thermalStrength?: number;
|
|
548
|
-
visibility?: number;
|
|
549
|
-
visibility_sm?: number | null;
|
|
550
|
-
temperature?: number | null;
|
|
551
|
-
clouds?: AeroflyMissionConditionsCloud[];
|
|
552
|
-
} = {}) {
|
|
553
|
-
this.time = time;
|
|
554
|
-
this.wind = wind;
|
|
555
|
-
this.turbulenceStrength = turbulenceStrength;
|
|
556
|
-
this.thermalStrength = thermalStrength;
|
|
557
|
-
this.visibility = visibility;
|
|
558
|
-
this.clouds = clouds;
|
|
559
|
-
|
|
560
|
-
if (visibility_sm) {
|
|
561
|
-
this.visibility_sm = visibility_sm;
|
|
562
|
-
}
|
|
563
|
-
if (temperature) {
|
|
564
|
-
this.temperature = temperature;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* @returns {number} the Aerofly value for UTC hours + minutes/60 + seconds/3600. Ignores milliseconds ;)
|
|
570
|
-
*/
|
|
571
|
-
get time_hours(): number {
|
|
572
|
-
return this.time.getUTCHours() + this.time.getUTCMinutes() / 60 + this.time.getUTCSeconds() / 3600;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* @returns {string} Time representation like "20:15:00"
|
|
577
|
-
*/
|
|
578
|
-
get time_presentational(): string {
|
|
579
|
-
return [this.time.getUTCHours(), this.time.getUTCMinutes(), this.time.getUTCSeconds()]
|
|
580
|
-
.map((t) => {
|
|
581
|
-
return String(t).padStart(2, "0");
|
|
582
|
-
})
|
|
583
|
-
.join(":");
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* @param {number} visibility_sm `this.visibility` in statute miles instead of meters
|
|
588
|
-
*/
|
|
589
|
-
set visibility_sm(visibility_sm: number) {
|
|
590
|
-
this.visibility = visibility_sm * meterPerStatuteMile;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* @returns {number} `this.visibility` in statute miles instead of meters
|
|
595
|
-
*/
|
|
596
|
-
get visibility_sm(): number {
|
|
597
|
-
return this.visibility / meterPerStatuteMile;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Will set `this.thermalStrength`
|
|
602
|
-
* @param {number} temperature in °C
|
|
603
|
-
*/
|
|
604
|
-
set temperature(temperature: number) {
|
|
605
|
-
// Range from -15°C to 35°C
|
|
606
|
-
this.thermalStrength = Math.max(0, (temperature + 15) / 50) ** 2;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* @returns {number} in °C
|
|
611
|
-
*/
|
|
612
|
-
get temperature(): number {
|
|
613
|
-
return Math.sqrt(this.thermalStrength) * 50 - 15;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* @returns {string}
|
|
618
|
-
*/
|
|
619
|
-
getCloudsString(): string {
|
|
620
|
-
return this.clouds
|
|
621
|
-
.map((c: AeroflyMissionConditionsCloud, index: number): string => {
|
|
622
|
-
return c.toString(index);
|
|
623
|
-
})
|
|
624
|
-
.join("\n");
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
629
|
-
*/
|
|
630
|
-
toString(): string {
|
|
631
|
-
if (this.clouds.length < 1) {
|
|
632
|
-
this.clouds = [new AeroflyMissionConditionsCloud(0, 0)];
|
|
633
|
-
}
|
|
634
|
-
|
|
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();
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
* @class
|
|
657
|
-
* A cloud layer for the current flight plan's weather data
|
|
658
|
-
*
|
|
659
|
-
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
660
|
-
* `custom_missions_user.tmc` flight plan file format, and export the structure
|
|
661
|
-
* for this file via the `toString()` method.
|
|
662
|
-
*/
|
|
663
|
-
export class AeroflyMissionConditionsCloud {
|
|
664
|
-
/**
|
|
665
|
-
* @property {number} cover 0..1, percentage
|
|
666
|
-
*/
|
|
667
|
-
cover: number;
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* @property {number} base altitude in meters AGL
|
|
671
|
-
*/
|
|
672
|
-
base: number;
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* @param {number} cover 0..1, percentage
|
|
676
|
-
* @param {number} base altitude in meters AGL
|
|
677
|
-
*/
|
|
678
|
-
constructor(cover: number, base: number) {
|
|
679
|
-
this.cover = cover;
|
|
680
|
-
this.base = base;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* @param {number} cover 0..1, percentage
|
|
685
|
-
* @param {number} base_feet altitude, but in feet AGL instead of meters AGL
|
|
686
|
-
* @returns {AeroflyMissionConditionsCloud}
|
|
687
|
-
*/
|
|
688
|
-
static createInFeet(cover: number, base_feet: number): AeroflyMissionConditionsCloud {
|
|
689
|
-
return new AeroflyMissionConditionsCloud(cover, base_feet / feetPerMeter);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* @param {number} base_feet `this.base` in feet instead of meters
|
|
694
|
-
*/
|
|
695
|
-
set base_feet(base_feet: number) {
|
|
696
|
-
this.base = base_feet / feetPerMeter;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/**
|
|
700
|
-
* @returns {number} `this.base` in feet instead of meters
|
|
701
|
-
*/
|
|
702
|
-
get base_feet(): number {
|
|
703
|
-
return this.base * feetPerMeter;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* @returns {string} Cloud coverage as text representation like "OVC" for `this.cover`
|
|
708
|
-
*/
|
|
709
|
-
get cover_code(): AeroflyMissionConditionsCloudCoverCode {
|
|
710
|
-
if (this.cover < 1 / 8) {
|
|
711
|
-
return "CLR";
|
|
712
|
-
} else if (this.cover <= 2 / 8) {
|
|
713
|
-
return "FEW";
|
|
714
|
-
} else if (this.cover <= 4 / 8) {
|
|
715
|
-
return "SCT";
|
|
716
|
-
} else if (this.cover <= 7 / 8) {
|
|
717
|
-
return "BKN";
|
|
718
|
-
}
|
|
719
|
-
return "OVC";
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* @param {number} index if used in an array will se the array index
|
|
724
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
725
|
-
*/
|
|
726
|
-
toString(index: number = 0): string {
|
|
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 ? '//' : '';
|
|
742
|
-
|
|
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`;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
/**
|
|
750
|
-
* @class
|
|
751
|
-
* A single way point for the given flight plan
|
|
752
|
-
*
|
|
753
|
-
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
754
|
-
* `custom_missions_user.tmc` flight plan file format, and export the structure
|
|
755
|
-
* for this file via the `toString()` method.
|
|
756
|
-
*/
|
|
757
|
-
export class AeroflyMissionCheckpoint {
|
|
758
|
-
/**
|
|
759
|
-
* @property {"origin"|"departure_runway"|"departure"|"waypoint"|"arrival"|"approach"|"destination_runway"|"destination"} type of checkpoint, like "departure_runway"
|
|
760
|
-
*/
|
|
761
|
-
type: AeroflyMissionCheckpointType;
|
|
762
|
-
|
|
763
|
-
/**
|
|
764
|
-
* @property {string} name ICAO code for airport, runway designator, navaid
|
|
765
|
-
* designator, fix name, or custom name
|
|
766
|
-
*/
|
|
767
|
-
name: string;
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* @property {number} longitude easting, using the World Geodetic
|
|
771
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
772
|
-
* of decimal degrees; -180..180
|
|
773
|
-
*/
|
|
774
|
-
longitude: number;
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* @property {number} latitude northing, using the World Geodetic
|
|
778
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
779
|
-
* of decimal degrees; -90..90
|
|
780
|
-
*/
|
|
781
|
-
latitude: number;
|
|
782
|
-
|
|
783
|
-
/**
|
|
784
|
-
* @property {number} altitude The height in meters above or below the WGS
|
|
785
|
-
* 84 reference ellipsoid
|
|
786
|
-
*/
|
|
787
|
-
altitude: number;
|
|
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
|
-
|
|
796
|
-
/**
|
|
797
|
-
* @property {?number} direction of runway, in degree
|
|
798
|
-
*/
|
|
799
|
-
direction: number | null;
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* @property {?number} slope of runway
|
|
803
|
-
*/
|
|
804
|
-
slope: number | null;
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* @property {?number} length of runway, in meters
|
|
808
|
-
*/
|
|
809
|
-
length: number | null;
|
|
810
|
-
|
|
811
|
-
/**
|
|
812
|
-
* @property {?number} frequency of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
813
|
-
*/
|
|
814
|
-
frequency: number | null;
|
|
815
|
-
|
|
816
|
-
/**
|
|
817
|
-
* @property {?boolean} flyOver if waypoint is meant to be flown over
|
|
818
|
-
*/
|
|
819
|
-
flyOver: boolean | null;
|
|
820
|
-
|
|
821
|
-
/**
|
|
822
|
-
* @param {string} name ICAO code for airport, runway designator, navaid
|
|
823
|
-
* designator, fix name, or custom name
|
|
824
|
-
* @param {"origin"|"departure_runway"|"departure"|"waypoint"|"arrival"|"approach"|"destination_runway"|"destination"} type Type of checkpoint, like "departure_runway"
|
|
825
|
-
* @param {number} longitude easting, using the World Geodetic
|
|
826
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
827
|
-
* of decimal degrees; -180..180
|
|
828
|
-
* @param {number} latitude northing, using the World Geodetic
|
|
829
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
830
|
-
* of decimal degrees; -90..90
|
|
831
|
-
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
832
|
-
* @param {number} [additionalAttributes.altitude] The height in meters above or below the WGS
|
|
833
|
-
* 84 reference ellipsoid
|
|
834
|
-
* @param {?number} [additionalAttributes.altitude_feet] The height in feet above or below the WGS
|
|
835
|
-
* 84 reference ellipsoid. Will overwrite altitude
|
|
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
|
|
845
|
-
*/
|
|
846
|
-
constructor(
|
|
847
|
-
name: string,
|
|
848
|
-
type: AeroflyMissionCheckpointType,
|
|
849
|
-
longitude: number,
|
|
850
|
-
latitude: number,
|
|
851
|
-
{
|
|
852
|
-
altitude = 0,
|
|
853
|
-
altitude_feet = null,
|
|
854
|
-
altitudeConstraint = null,
|
|
855
|
-
direction = null,
|
|
856
|
-
slope = null,
|
|
857
|
-
length = null,
|
|
858
|
-
length_feet = null,
|
|
859
|
-
frequency = null,
|
|
860
|
-
flyOver = null,
|
|
861
|
-
}: {
|
|
862
|
-
altitude?: number;
|
|
863
|
-
altitude_feet?: number | null;
|
|
864
|
-
altitudeConstraint?: boolean | null;
|
|
865
|
-
direction?: number | null;
|
|
866
|
-
slope?: number | null;
|
|
867
|
-
length?: number | null;
|
|
868
|
-
length_feet?: number | null;
|
|
869
|
-
frequency?: number | null;
|
|
870
|
-
flyOver?: boolean | null;
|
|
871
|
-
} = {},
|
|
872
|
-
) {
|
|
873
|
-
this.type = type;
|
|
874
|
-
this.name = name;
|
|
875
|
-
this.longitude = longitude;
|
|
876
|
-
this.latitude = latitude;
|
|
877
|
-
this.altitude = altitude;
|
|
878
|
-
this.altitudeConstraint = altitudeConstraint;
|
|
879
|
-
this.direction = direction;
|
|
880
|
-
this.slope = slope;
|
|
881
|
-
this.length = length;
|
|
882
|
-
this.frequency = frequency;
|
|
883
|
-
this.flyOver = flyOver;
|
|
884
|
-
|
|
885
|
-
if (altitude_feet) {
|
|
886
|
-
this.altitude_feet = altitude_feet;
|
|
887
|
-
}
|
|
888
|
-
if (length_feet) {
|
|
889
|
-
this.length_feet = length_feet;
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
/**
|
|
894
|
-
* @param {number} altitude_feet
|
|
895
|
-
*/
|
|
896
|
-
set altitude_feet(altitude_feet: number) {
|
|
897
|
-
this.altitude = altitude_feet / feetPerMeter;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* @returns {number} altitude_feet
|
|
902
|
-
*/
|
|
903
|
-
get altitude_feet(): number {
|
|
904
|
-
return this.altitude * feetPerMeter;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* @param {number} length_feet
|
|
909
|
-
*/
|
|
910
|
-
set length_feet(length_feet: number) {
|
|
911
|
-
this.length = length_feet / feetPerMeter;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/**
|
|
915
|
-
* @returns {number} length_feet
|
|
916
|
-
*/
|
|
917
|
-
get length_feet(): number {
|
|
918
|
-
return (this.length ?? 0) * feetPerMeter;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* @returns {string}
|
|
923
|
-
*/
|
|
924
|
-
get frequency_string(): string {
|
|
925
|
-
if (!this.frequency) {
|
|
926
|
-
return "None";
|
|
927
|
-
}
|
|
928
|
-
if (this.frequency > 1_000_000) {
|
|
929
|
-
return String(this.frequency / 1_000_000) + " MHz";
|
|
930
|
-
}
|
|
931
|
-
if (this.frequency > 1_000) {
|
|
932
|
-
return String(this.frequency / 1_000) + " kHz";
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
return String(this.frequency) + " Hz";
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
/**
|
|
939
|
-
* @param {number} index if used in an array will se the array index
|
|
940
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
941
|
-
*/
|
|
942
|
-
toString(index: number = 0): string {
|
|
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
|
-
}
|
|
954
|
-
if (this.length) {
|
|
955
|
-
fileSet.push("float64", "length", this.length ?? 0, `${Math.floor(this.length_feet)} ft`);
|
|
956
|
-
}
|
|
957
|
-
if (this.frequency) {
|
|
958
|
-
fileSet.push("float64", "frequency", this.frequency ?? 0, `${this.frequency_string}`);
|
|
959
|
-
}
|
|
960
|
-
if (this.flyOver !== null) {
|
|
961
|
-
fileSet.push("bool", "fly_over", this.flyOver);
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
return fileSet.toString();
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* @class
|
|
970
|
-
* A translation for the mission title and description.
|
|
971
|
-
*/
|
|
972
|
-
export class AeroflyLocalizedText {
|
|
973
|
-
/**
|
|
974
|
-
* @property {string} language ISO 639-1 like
|
|
975
|
-
* - br
|
|
976
|
-
* - cn
|
|
977
|
-
* - de
|
|
978
|
-
* - es
|
|
979
|
-
* - fr
|
|
980
|
-
* - id
|
|
981
|
-
* - it
|
|
982
|
-
* - jp
|
|
983
|
-
* - kr
|
|
984
|
-
* - pl
|
|
985
|
-
* - sv
|
|
986
|
-
* - tr
|
|
987
|
-
*/
|
|
988
|
-
language: string;
|
|
989
|
-
|
|
990
|
-
/**
|
|
991
|
-
* @property {string} title of this flight plan
|
|
992
|
-
*/
|
|
993
|
-
title: string;
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* @property {string} description text, mission briefing, etc
|
|
997
|
-
*/
|
|
998
|
-
description: string;
|
|
999
|
-
|
|
1000
|
-
/**
|
|
1001
|
-
* @param {string} language ISO 639-1 like
|
|
1002
|
-
* - br
|
|
1003
|
-
* - cn
|
|
1004
|
-
* - de
|
|
1005
|
-
* - es
|
|
1006
|
-
* - fr
|
|
1007
|
-
* - id
|
|
1008
|
-
* - it
|
|
1009
|
-
* - jp
|
|
1010
|
-
* - kr
|
|
1011
|
-
* - pl
|
|
1012
|
-
* - sv
|
|
1013
|
-
* - tr
|
|
1014
|
-
* @param {string} title of this flight plan
|
|
1015
|
-
* @param {string} description text, mission briefing, etc
|
|
1016
|
-
*/
|
|
1017
|
-
constructor(language: string, title: string, description: string) {
|
|
1018
|
-
this.language = language;
|
|
1019
|
-
this.title = title;
|
|
1020
|
-
this.description = description;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
* @param {number} index if used in an array will se the array index
|
|
1025
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
1026
|
-
*/
|
|
1027
|
-
toString(index: number = 0): string {
|
|
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();
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* @class
|
|
1038
|
-
* A target plane which the aircraft needs to cross.
|
|
1039
|
-
*/
|
|
1040
|
-
export class AeroflyMissionTargetPlane {
|
|
1041
|
-
/**
|
|
1042
|
-
* @property {number} longitude easting, using the World Geodetic
|
|
1043
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
1044
|
-
* of decimal degrees; -180..180
|
|
1045
|
-
*/
|
|
1046
|
-
longitude: number;
|
|
1047
|
-
|
|
1048
|
-
/**
|
|
1049
|
-
* @property {number} latitude northing, using the World Geodetic
|
|
1050
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
1051
|
-
* of decimal degrees; -90..90
|
|
1052
|
-
*/
|
|
1053
|
-
latitude: number;
|
|
1054
|
-
|
|
1055
|
-
/**
|
|
1056
|
-
* @property {number} dir in degree
|
|
1057
|
-
*/
|
|
1058
|
-
dir: number;
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* @property {string} name of property
|
|
1062
|
-
*/
|
|
1063
|
-
name: string;
|
|
1064
|
-
|
|
1065
|
-
/**
|
|
1066
|
-
*
|
|
1067
|
-
* @param {number} longitude easting, using the World Geodetic
|
|
1068
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
1069
|
-
* of decimal degrees; -180..180
|
|
1070
|
-
* @param {number}latitude northing, using the World Geodetic
|
|
1071
|
-
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
1072
|
-
* of decimal degrees; -90..90
|
|
1073
|
-
* @param {number} dir in degree
|
|
1074
|
-
* @param {string} name of property
|
|
1075
|
-
*/
|
|
1076
|
-
constructor(longitude: number, latitude: number, dir: number, name: string = "finish") {
|
|
1077
|
-
this.longitude = longitude;
|
|
1078
|
-
this.latitude = latitude;
|
|
1079
|
-
this.dir = dir;
|
|
1080
|
-
this.name = name;
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
toString(): string {
|
|
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();
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
export default {
|
|
1092
|
-
AeroflyMissionsList,
|
|
1093
|
-
AeroflyMission,
|
|
1094
|
-
AeroflyMissionConditions,
|
|
1095
|
-
AeroflyMissionConditionsCloud,
|
|
1096
|
-
AeroflyMissionCheckpoint,
|
|
1097
|
-
AeroflyLocalizedText,
|
|
1098
|
-
AeroflyMissionTargetPlane,
|
|
1099
|
-
};
|
|
1
|
+
export { AeroflyLocalizedText } from "./dto/AeroflyLocalizedText.js";
|
|
2
|
+
export { AeroflyMission } from "./dto/AeroflyMission.js";
|
|
3
|
+
export { AeroflyMissionCheckpoint } from "./dto/AeroflyMissionCheckpoint.js";
|
|
4
|
+
export { AeroflyMissionConditions } from "./dto/AeroflyMissionConditions.js";
|
|
5
|
+
export { AeroflyMissionConditionsCloud } from "./dto/AeroflyMissionConditionsCloud.js";
|
|
6
|
+
export { AeroflyMissionsList } from "./dto/AeroflyMissionsList.js";
|
|
7
|
+
export { AeroflyMissionTargetPlane } from "./dto/AeroflyMissionTargetPlane.js";
|