@fboes/aerofly-custom-missions 1.0.0 → 1.0.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/.editorconfig +4 -0
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/index.js +151 -155
- package/dist/index.test.js +31 -4
- package/eslint.config.js +20 -22
- package/package.json +2 -2
- package/src/index.test.ts +139 -106
- package/src/index.ts +552 -452
- package/types/index.d.ts +184 -84
- package/types/index.d.ts.map +1 -1
- package/types/index.test.d.ts +1 -1
package/.editorconfig
CHANGED
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ As there are lots of properties for the flight plan as well as explanation for t
|
|
|
129
129
|
- `departure_runway`
|
|
130
130
|
- `destination_runway`
|
|
131
131
|
- `destination`
|
|
132
|
-
- Be aware that all untis for altitude, elevation or distance are measured in meters! In most cases there will be helper functions for defining these values in feet or statute miles (for
|
|
132
|
+
- Be aware that all untis for altitude, elevation or distance are measured in meters! In most cases there will be helper functions for defining these values in feet or statute miles (for visibility).
|
|
133
133
|
|
|
134
134
|
## Status
|
|
135
135
|
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const feetPerMeter = 3.28084;
|
|
2
2
|
const meterPerStatuteMile = 1609.344;
|
|
3
3
|
/**
|
|
4
|
+
* @class
|
|
4
5
|
* A list of flight plans.
|
|
5
6
|
*
|
|
6
7
|
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
@@ -9,13 +10,13 @@ const meterPerStatuteMile = 1609.344;
|
|
|
9
10
|
*/
|
|
10
11
|
export class AeroflyMissionsList {
|
|
11
12
|
/**
|
|
12
|
-
* @param missions
|
|
13
|
+
* @param {AeroflyMission[]} missions in this mission list
|
|
13
14
|
*/
|
|
14
15
|
constructor(missions = []) {
|
|
15
16
|
this.missions = missions;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
|
-
* @returns
|
|
19
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
19
20
|
*/
|
|
20
21
|
toString() {
|
|
21
22
|
const separator = "\n// -----------------------------------------------------------------------------\n";
|
|
@@ -27,6 +28,7 @@ export class AeroflyMissionsList {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
31
|
+
* @class
|
|
30
32
|
* A single flighplan, containing aircraft and weather data as well.
|
|
31
33
|
*
|
|
32
34
|
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
@@ -35,71 +37,46 @@ export class AeroflyMissionsList {
|
|
|
35
37
|
*/
|
|
36
38
|
export class AeroflyMission {
|
|
37
39
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @param
|
|
40
|
-
* @param additionalAttributes
|
|
40
|
+
* @param {string} title of this flight plan
|
|
41
|
+
* @param {object} [additionalAttributes] allows to set additional attributes on creation
|
|
42
|
+
* @param {string} [additionalAttributes.description] text, mission briefing, etc
|
|
43
|
+
* @param {"taxi"|"takeoff"|"cruise"|"approach"|"landing"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
44
|
+
* @param {{name:string,livery:string,icao:string}} [additionalAttributes.aircraft] for this mission
|
|
45
|
+
* @param {string} [additionalAttributes.callsign] of aircraft, uppercased
|
|
46
|
+
* @param {object} [additionalAttributes.origin] position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
47
|
+
* @param {object} [additionalAttributes.destination] position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
48
|
+
* @param {AeroflyMissionConditions} [additionalAttributes.conditions] like time and weather for mission
|
|
49
|
+
* @param {AeroflyMissionCheckpoint[]} [additionalAttributes.checkpoints] form the actual flight plan
|
|
41
50
|
*/
|
|
42
|
-
constructor(title,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Uppercase callsign of aircraft
|
|
61
|
-
*/
|
|
62
|
-
this.callsign = "";
|
|
63
|
-
/**
|
|
64
|
-
* Starting position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
65
|
-
*/
|
|
66
|
-
this.origin = {
|
|
67
|
-
icao: "",
|
|
68
|
-
longitude: 0,
|
|
69
|
-
latitude: 0,
|
|
70
|
-
dir: 0,
|
|
71
|
-
alt: 0,
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* Intended end position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
75
|
-
*/
|
|
76
|
-
this.destination = {
|
|
77
|
-
icao: "",
|
|
78
|
-
longitude: 0,
|
|
79
|
-
latitude: 0,
|
|
80
|
-
dir: 0,
|
|
81
|
-
alt: 0,
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* Time and weather for mission
|
|
85
|
-
*/
|
|
86
|
-
this.conditions = new AeroflyMissionConditions();
|
|
87
|
-
/**
|
|
88
|
-
* The actual flight plan
|
|
89
|
-
*/
|
|
90
|
-
this.checkpoints = [];
|
|
51
|
+
constructor(title, { description = "", flightSetting = "taxi", aircraft = {
|
|
52
|
+
name: "c172",
|
|
53
|
+
livery: "",
|
|
54
|
+
icao: "",
|
|
55
|
+
}, callsign = "", origin = {
|
|
56
|
+
icao: "",
|
|
57
|
+
longitude: 0,
|
|
58
|
+
latitude: 0,
|
|
59
|
+
dir: 0,
|
|
60
|
+
alt: 0,
|
|
61
|
+
}, destination = {
|
|
62
|
+
icao: "",
|
|
63
|
+
longitude: 0,
|
|
64
|
+
latitude: 0,
|
|
65
|
+
dir: 0,
|
|
66
|
+
alt: 0,
|
|
67
|
+
}, conditions = new AeroflyMissionConditions(), checkpoints = [], } = {}) {
|
|
91
68
|
this.title = title;
|
|
92
|
-
this.checkpoints =
|
|
93
|
-
this.description =
|
|
94
|
-
this.flightSetting =
|
|
95
|
-
this.aircraft =
|
|
96
|
-
this.callsign =
|
|
97
|
-
this.origin =
|
|
98
|
-
this.destination =
|
|
99
|
-
this.conditions =
|
|
69
|
+
this.checkpoints = checkpoints;
|
|
70
|
+
this.description = description;
|
|
71
|
+
this.flightSetting = flightSetting;
|
|
72
|
+
this.aircraft = aircraft;
|
|
73
|
+
this.callsign = callsign;
|
|
74
|
+
this.origin = origin;
|
|
75
|
+
this.destination = destination;
|
|
76
|
+
this.conditions = conditions;
|
|
100
77
|
}
|
|
101
78
|
/**
|
|
102
|
-
* @returns indexed checkpoints
|
|
79
|
+
* @returns {string} indexed checkpoints
|
|
103
80
|
*/
|
|
104
81
|
getCheckpointsString() {
|
|
105
82
|
return this.checkpoints
|
|
@@ -110,7 +87,7 @@ export class AeroflyMission {
|
|
|
110
87
|
}
|
|
111
88
|
/**
|
|
112
89
|
* @throws {Error} on missing waypoints
|
|
113
|
-
* @returns
|
|
90
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
114
91
|
*/
|
|
115
92
|
toString() {
|
|
116
93
|
if (this.checkpoints.length < 2) {
|
|
@@ -159,6 +136,7 @@ ${this.getCheckpointsString()}
|
|
|
159
136
|
}
|
|
160
137
|
}
|
|
161
138
|
/**
|
|
139
|
+
* @class
|
|
162
140
|
* Time and weather data for the given flight plan
|
|
163
141
|
*
|
|
164
142
|
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
@@ -167,51 +145,43 @@ ${this.getCheckpointsString()}
|
|
|
167
145
|
*/
|
|
168
146
|
export class AeroflyMissionConditions {
|
|
169
147
|
/**
|
|
170
|
-
* @param additionalAttributes allows to set additional attributes on creation
|
|
148
|
+
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
149
|
+
* @param {Date} [additionalAttributes.time] of flight plan. Relevant is the UTC part, so
|
|
150
|
+
* consider setting this date in UTC.
|
|
151
|
+
* @param {{direction: number, speed: number, gusts: number}} [additionalAttributes.wind] state
|
|
152
|
+
* @param {number} [additionalAttributes.turbulenceStrength] 0..1, percentage
|
|
153
|
+
* @param {number} [additionalAttributes.thermalStrength] 0..1, percentage
|
|
154
|
+
* @param {number} [additionalAttributes.visibility] in meters
|
|
155
|
+
* @param {number?} [additionalAttributes.visibility_sm] in statute miles
|
|
156
|
+
* @param {AeroflyMissionConditionsCloud[]} [additionalAttributes.clouds] for the whole flight
|
|
171
157
|
*/
|
|
172
|
-
constructor(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.time = new Date();
|
|
178
|
-
/**
|
|
179
|
-
* Current wind state
|
|
180
|
-
*/
|
|
181
|
-
this.wind = {
|
|
182
|
-
direction: 0,
|
|
183
|
-
speed: 0,
|
|
184
|
-
gusts: 0,
|
|
185
|
-
};
|
|
186
|
-
/**
|
|
187
|
-
* 0..1, percentage
|
|
188
|
-
*/
|
|
189
|
-
this.turbulenceStrength = 0;
|
|
190
|
-
/**
|
|
191
|
-
* 0..1, percentage
|
|
192
|
-
*/
|
|
193
|
-
this.thermalStrength = 0;
|
|
158
|
+
constructor({ time = new Date(), wind = {
|
|
159
|
+
direction: 0,
|
|
160
|
+
speed: 0,
|
|
161
|
+
gusts: 0,
|
|
162
|
+
}, turbulenceStrength = 0, thermalStrength = 0, visibility = 25_000, visibility_sm = null, clouds = [], } = {}) {
|
|
194
163
|
/**
|
|
195
|
-
*
|
|
164
|
+
* @property {AeroflyMissionConditionsCloud[]} clouds for the whole flight
|
|
196
165
|
*/
|
|
197
|
-
this.visibility = 25000;
|
|
198
166
|
this.clouds = [];
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
this.
|
|
203
|
-
this.
|
|
204
|
-
this.
|
|
205
|
-
this.
|
|
167
|
+
if (visibility_sm) {
|
|
168
|
+
visibility = visibility_sm * meterPerStatuteMile;
|
|
169
|
+
}
|
|
170
|
+
this.time = time;
|
|
171
|
+
this.wind = wind;
|
|
172
|
+
this.turbulenceStrength = turbulenceStrength;
|
|
173
|
+
this.thermalStrength = thermalStrength;
|
|
174
|
+
this.visibility = visibility;
|
|
175
|
+
this.clouds = clouds;
|
|
206
176
|
}
|
|
207
177
|
/**
|
|
208
|
-
* @returns the Aerofly value for UTC hours + minutes/60 + seconds/3600. Ignores milliseconds ;)
|
|
178
|
+
* @returns {number} the Aerofly value for UTC hours + minutes/60 + seconds/3600. Ignores milliseconds ;)
|
|
209
179
|
*/
|
|
210
180
|
get time_hours() {
|
|
211
181
|
return this.time.getUTCHours() + this.time.getUTCMinutes() / 60 + this.time.getUTCSeconds() / 3600;
|
|
212
182
|
}
|
|
213
183
|
/**
|
|
214
|
-
* @returns Time representation like "20:15:00"
|
|
184
|
+
* @returns {string} Time representation like "20:15:00"
|
|
215
185
|
*/
|
|
216
186
|
get time_presentational() {
|
|
217
187
|
return [this.time.getUTCHours(), this.time.getUTCMinutes(), this.time.getUTCSeconds()]
|
|
@@ -221,13 +191,19 @@ export class AeroflyMissionConditions {
|
|
|
221
191
|
.join(":");
|
|
222
192
|
}
|
|
223
193
|
/**
|
|
224
|
-
* @param visibility_sm `this.visibility` in statute miles instead of meters
|
|
194
|
+
* @param {number} visibility_sm `this.visibility` in statute miles instead of meters
|
|
225
195
|
*/
|
|
226
196
|
set visibility_sm(visibility_sm) {
|
|
227
197
|
this.visibility = visibility_sm * meterPerStatuteMile;
|
|
228
198
|
}
|
|
229
199
|
/**
|
|
230
|
-
* @returns
|
|
200
|
+
* @returns {number} `this.visibility` in statute miles instead of meters
|
|
201
|
+
*/
|
|
202
|
+
get visibility_sm() {
|
|
203
|
+
return this.visibility / meterPerStatuteMile;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* @returns {string}
|
|
231
207
|
*/
|
|
232
208
|
getCloudsString() {
|
|
233
209
|
return this.clouds
|
|
@@ -237,7 +213,7 @@ export class AeroflyMissionConditions {
|
|
|
237
213
|
.join("\n");
|
|
238
214
|
}
|
|
239
215
|
/**
|
|
240
|
-
* @returns
|
|
216
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
241
217
|
*/
|
|
242
218
|
toString() {
|
|
243
219
|
if (this.clouds.length < 1) {
|
|
@@ -255,12 +231,13 @@ export class AeroflyMissionConditions {
|
|
|
255
231
|
<[float64][wind_gusts][${this.wind.gusts}]> // kts
|
|
256
232
|
<[float64][turbulence_strength][${this.turbulenceStrength}]>
|
|
257
233
|
<[float64][thermal_strength][${this.thermalStrength}]>
|
|
258
|
-
<[float64][visibility][${this.visibility}]> // ${this.
|
|
234
|
+
<[float64][visibility][${this.visibility}]> // ${this.visibility_sm} SM
|
|
259
235
|
${this.getCloudsString()}
|
|
260
236
|
>`;
|
|
261
237
|
}
|
|
262
238
|
}
|
|
263
239
|
/**
|
|
240
|
+
* @class
|
|
264
241
|
* A cloud layer for the current flight plan's weather data
|
|
265
242
|
*
|
|
266
243
|
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
@@ -269,29 +246,35 @@ ${this.getCloudsString()}
|
|
|
269
246
|
*/
|
|
270
247
|
export class AeroflyMissionConditionsCloud {
|
|
271
248
|
/**
|
|
272
|
-
* @param cover 0..1, percentage
|
|
273
|
-
* @param base in meters AGL
|
|
249
|
+
* @param {number} cover 0..1, percentage
|
|
250
|
+
* @param {number} base altitude in meters AGL
|
|
274
251
|
*/
|
|
275
252
|
constructor(cover, base) {
|
|
276
253
|
this.cover = cover;
|
|
277
254
|
this.base = base;
|
|
278
255
|
}
|
|
279
256
|
/**
|
|
280
|
-
* @param cover 0..1, percentage
|
|
281
|
-
* @param base_feet
|
|
257
|
+
* @param {number} cover 0..1, percentage
|
|
258
|
+
* @param {number} base_feet altitude, but in feet AGL instead of meters AGL
|
|
282
259
|
* @returns {AeroflyMissionConditionsCloud}
|
|
283
260
|
*/
|
|
284
261
|
static createInFeet(cover, base_feet) {
|
|
285
262
|
return new AeroflyMissionConditionsCloud(cover, base_feet / feetPerMeter);
|
|
286
263
|
}
|
|
287
264
|
/**
|
|
288
|
-
* @param base_feet `this.base` in feet instead of meters
|
|
265
|
+
* @param {number} base_feet `this.base` in feet instead of meters
|
|
289
266
|
*/
|
|
290
267
|
set base_feet(base_feet) {
|
|
291
268
|
this.base = base_feet / feetPerMeter;
|
|
292
269
|
}
|
|
293
270
|
/**
|
|
294
|
-
* @returns
|
|
271
|
+
* @returns {number} `this.base` in feet instead of meters
|
|
272
|
+
*/
|
|
273
|
+
get base_feet() {
|
|
274
|
+
return this.base * feetPerMeter;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* @returns {string} Cloud coverage as text representation like "OVC" for `this.cover`
|
|
295
278
|
*/
|
|
296
279
|
get cover_code() {
|
|
297
280
|
if (this.cover < 1 / 8) {
|
|
@@ -309,17 +292,18 @@ export class AeroflyMissionConditionsCloud {
|
|
|
309
292
|
return "OVC";
|
|
310
293
|
}
|
|
311
294
|
/**
|
|
312
|
-
* @param index if used in an array will se the array index
|
|
313
|
-
* @returns
|
|
295
|
+
* @param {number} index if used in an array will se the array index
|
|
296
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
314
297
|
*/
|
|
315
298
|
toString(index = 0) {
|
|
316
299
|
const indexString = index === 0 ? "" : String(index + 1);
|
|
317
300
|
const comment = index === 0 ? "" : "//";
|
|
318
301
|
return ` ${comment}<[float64][cloud_cover${indexString}][${this.cover ?? 0}]> // ${this.cover_code}
|
|
319
|
-
${comment}<[float64][cloud_base${indexString}][${this.base}]> // ${this.
|
|
302
|
+
${comment}<[float64][cloud_base${indexString}][${this.base}]> // ${this.base_feet} ft AGL`;
|
|
320
303
|
}
|
|
321
304
|
}
|
|
322
305
|
/**
|
|
306
|
+
* @class
|
|
323
307
|
* A single way point for the given flight plan
|
|
324
308
|
*
|
|
325
309
|
* The purpose of this class is to collect data needed for Aerofly FS4's
|
|
@@ -328,83 +312,95 @@ export class AeroflyMissionConditionsCloud {
|
|
|
328
312
|
*/
|
|
329
313
|
export class AeroflyMissionCheckpoint {
|
|
330
314
|
/**
|
|
331
|
-
* @param name ICAO code for airport, runway designator, navaid
|
|
315
|
+
* @param {string} name ICAO code for airport, runway designator, navaid
|
|
332
316
|
* designator, fix name, or custom name
|
|
333
|
-
* @param type Type of checkpoint, like "departure_runway"
|
|
334
|
-
* @param longitude easting, using the World Geodetic
|
|
317
|
+
* @param {"origin"|"departure_runway"|"departure"|"waypoint"|"arrival"|"approach"|"destination_runway"|"destination"} type Type of checkpoint, like "departure_runway"
|
|
318
|
+
* @param {number} longitude easting, using the World Geodetic
|
|
335
319
|
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
336
320
|
* of decimal degrees; -180..180
|
|
337
|
-
* @param latitude northing, using the World Geodetic
|
|
321
|
+
* @param {number} latitude northing, using the World Geodetic
|
|
338
322
|
* System 1984 (WGS 84) [WGS84] datum, with longitude and latitude units
|
|
339
323
|
* of decimal degrees; -90..90
|
|
340
|
-
* @param additionalAttributes allows to set additional attributes on creation
|
|
324
|
+
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
325
|
+
* @param {number} [additionalAttributes.altitude] The height in meters above or below the WGS
|
|
326
|
+
* 84 reference ellipsoid
|
|
327
|
+
* @param {number?} [additionalAttributes.altitude_feet] The height in feet above or below the WGS
|
|
328
|
+
* 84 reference ellipsoid
|
|
329
|
+
* @param {number} [additionalAttributes.direction] of runway, in degree
|
|
330
|
+
* @param {number?} [additionalAttributes.slope] of runway
|
|
331
|
+
* @param {number?} [additionalAttributes.length] of runway, in meters
|
|
332
|
+
* @param {number?} [additionalAttributes.length_feet] of runway, in feet
|
|
333
|
+
* @param {number?} [additionalAttributes.frequency] of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
341
334
|
*/
|
|
342
|
-
constructor(name, type, longitude, latitude,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
* For runways: in degree
|
|
350
|
-
*/
|
|
351
|
-
this.direction = null;
|
|
352
|
-
/**
|
|
353
|
-
* For runways
|
|
354
|
-
*/
|
|
355
|
-
this.slope = null;
|
|
356
|
-
/**
|
|
357
|
-
* For runways: in meters
|
|
358
|
-
*/
|
|
359
|
-
this.length = null;
|
|
360
|
-
/**
|
|
361
|
-
* For runways and navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
362
|
-
*/
|
|
363
|
-
this.frequency = null;
|
|
335
|
+
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = null, direction = null, slope = null, length = null, length_feet = null, frequency = null, } = {}) {
|
|
336
|
+
if (altitude_feet) {
|
|
337
|
+
altitude = altitude_feet / feetPerMeter;
|
|
338
|
+
}
|
|
339
|
+
if (length_feet) {
|
|
340
|
+
length = length_feet / feetPerMeter;
|
|
341
|
+
}
|
|
364
342
|
this.type = type;
|
|
365
343
|
this.name = name;
|
|
366
344
|
this.longitude = longitude;
|
|
367
345
|
this.latitude = latitude;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
this.
|
|
372
|
-
this.
|
|
373
|
-
this.slope = additionalAttributes.slope ?? this.slope;
|
|
374
|
-
this.length = additionalAttributes.length ?? this.length;
|
|
375
|
-
this.frequency = additionalAttributes.frequency ?? this.frequency;
|
|
346
|
+
this.altitude = altitude;
|
|
347
|
+
this.direction = direction;
|
|
348
|
+
this.slope = slope;
|
|
349
|
+
this.length = length;
|
|
350
|
+
this.frequency = frequency;
|
|
376
351
|
}
|
|
377
352
|
/**
|
|
378
|
-
* @param altitude_feet
|
|
353
|
+
* @param {number} altitude_feet
|
|
379
354
|
*/
|
|
380
355
|
set altitude_feet(altitude_feet) {
|
|
381
356
|
this.altitude = altitude_feet / feetPerMeter;
|
|
382
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* @returns {number} altitude_feet
|
|
360
|
+
*/
|
|
361
|
+
get altitude_feet() {
|
|
362
|
+
return this.altitude * feetPerMeter;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* @param {number} length_feet
|
|
366
|
+
*/
|
|
367
|
+
set length_feet(length_feet) {
|
|
368
|
+
this.length = length_feet / feetPerMeter;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* @returns {number} length_feet
|
|
372
|
+
*/
|
|
373
|
+
get length_feet() {
|
|
374
|
+
return (this.length ?? 0) * feetPerMeter;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* @returns {string}
|
|
378
|
+
*/
|
|
383
379
|
get frequency_string() {
|
|
384
380
|
if (!this.frequency) {
|
|
385
381
|
return "None";
|
|
386
382
|
}
|
|
387
|
-
if (this.frequency >
|
|
388
|
-
return String(this.frequency /
|
|
383
|
+
if (this.frequency > 1_000_000) {
|
|
384
|
+
return String(this.frequency / 1_000_000) + " MHz";
|
|
389
385
|
}
|
|
390
|
-
if (this.frequency >
|
|
391
|
-
return String(this.frequency /
|
|
386
|
+
if (this.frequency > 1_000) {
|
|
387
|
+
return String(this.frequency / 1_000) + " kHz";
|
|
392
388
|
}
|
|
393
389
|
return String(this.frequency) + " Hz";
|
|
394
390
|
}
|
|
395
391
|
/**
|
|
396
|
-
* @param index if used in an array will se the array index
|
|
397
|
-
* @returns
|
|
392
|
+
* @param {number} index if used in an array will se the array index
|
|
393
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
398
394
|
*/
|
|
399
395
|
toString(index = 0) {
|
|
400
396
|
return ` <[tmmission_checkpoint][element][${index}]
|
|
401
397
|
<[string8u][type][${this.type}]>
|
|
402
398
|
<[string8u][name][${this.name}]>
|
|
403
399
|
<[vector2_float64][lon_lat][${this.longitude} ${this.latitude}]>
|
|
404
|
-
<[float64][altitude][${this.altitude}]> // ${this.
|
|
400
|
+
<[float64][altitude][${this.altitude}]> // ${this.altitude_feet} ft
|
|
405
401
|
<[float64][direction][${this.direction ?? (index === 0 ? -1 : 0)}]>
|
|
406
402
|
<[float64][slope][${this.slope ?? 0}]>
|
|
407
|
-
<[float64][length][${this.length ?? 0}]> // ${
|
|
403
|
+
<[float64][length][${this.length ?? 0}]> // ${this.length_feet} ft
|
|
408
404
|
<[float64][frequency][${this.frequency ?? 0}]> // ${this.frequency_string}
|
|
409
405
|
>`;
|
|
410
406
|
}
|
package/dist/index.test.js
CHANGED
|
@@ -7,8 +7,26 @@ import { strict as assert } from "node:assert";
|
|
|
7
7
|
}
|
|
8
8
|
{
|
|
9
9
|
const conditions = new AeroflyMissionConditions();
|
|
10
|
-
conditions.visibility =
|
|
11
|
-
assert.deepStrictEqual(conditions.visibility,
|
|
10
|
+
conditions.visibility = 15_000;
|
|
11
|
+
assert.deepStrictEqual(conditions.visibility, 15_000);
|
|
12
|
+
conditions.visibility_sm = 10;
|
|
13
|
+
assert.notDeepStrictEqual(conditions.visibility, 10);
|
|
14
|
+
assert.deepStrictEqual(Math.round(conditions.visibility_sm), 10);
|
|
15
|
+
console.log("✅ AeroflyMissionConditions test successful");
|
|
16
|
+
}
|
|
17
|
+
{
|
|
18
|
+
const conditions = new AeroflyMissionConditions({
|
|
19
|
+
visibility: 15_000,
|
|
20
|
+
});
|
|
21
|
+
assert.deepStrictEqual(conditions.visibility, 15_000);
|
|
22
|
+
console.log("✅ AeroflyMissionConditions test successful");
|
|
23
|
+
}
|
|
24
|
+
{
|
|
25
|
+
const conditions = new AeroflyMissionConditions({
|
|
26
|
+
visibility_sm: 10,
|
|
27
|
+
});
|
|
28
|
+
assert.notDeepStrictEqual(conditions.visibility, 10);
|
|
29
|
+
assert.deepStrictEqual(Math.round(conditions.visibility_sm), 10);
|
|
12
30
|
console.log("✅ AeroflyMissionConditions test successful");
|
|
13
31
|
}
|
|
14
32
|
{
|
|
@@ -21,6 +39,9 @@ import { strict as assert } from "node:assert";
|
|
|
21
39
|
const cloud = new AeroflyMissionConditionsCloud(1, 1000);
|
|
22
40
|
assert.deepStrictEqual(cloud.cover, 1);
|
|
23
41
|
assert.deepStrictEqual(cloud.base, 1000);
|
|
42
|
+
cloud.base_feet = 1000;
|
|
43
|
+
assert.notDeepStrictEqual(cloud.base, 1000);
|
|
44
|
+
assert.deepStrictEqual(Math.round(cloud.base_feet), 1000);
|
|
24
45
|
console.log("✅ AeroflyMissionConditionsCloud test successful");
|
|
25
46
|
}
|
|
26
47
|
{
|
|
@@ -39,6 +60,12 @@ import { strict as assert } from "node:assert";
|
|
|
39
60
|
AeroflyMissionConditionsCloud.createInFeet(0.2, 7500),
|
|
40
61
|
],
|
|
41
62
|
});
|
|
63
|
+
assert.strictEqual(conditions.wind.direction, 190);
|
|
64
|
+
assert.strictEqual(conditions.wind.speed, 11);
|
|
65
|
+
assert.strictEqual(conditions.wind.gusts, 22);
|
|
66
|
+
assert.strictEqual(conditions.turbulenceStrength, 1);
|
|
67
|
+
assert.strictEqual(conditions.thermalStrength, 0.31200000000000006);
|
|
68
|
+
assert.strictEqual(conditions.visibility, 14484.096000000001);
|
|
42
69
|
const checkpoints = [
|
|
43
70
|
new AeroflyMissionCheckpoint("KCCR", "origin", -122.057, 37.9897, {
|
|
44
71
|
altitude: 8,
|
|
@@ -88,9 +115,9 @@ import { strict as assert } from "node:assert";
|
|
|
88
115
|
assert.strictEqual(missionList.missions.length, 1);
|
|
89
116
|
assert.strictEqual(missionList.missions[0].aircraft.name, "c172");
|
|
90
117
|
assert.strictEqual(missionList.missions[0].aircraft.icao, "C172");
|
|
91
|
-
console.dir(missionList.missions[0], { depth: null });
|
|
118
|
+
//console.dir(missionList.missions[0], { depth: null });
|
|
92
119
|
const missionListString = missionList.toString();
|
|
93
|
-
console.log(missionListString);
|
|
120
|
+
//console.log(missionListString);
|
|
94
121
|
assert.ok(missionListString.includes("[origin]"));
|
|
95
122
|
assert.ok(missionListString.includes("[tmmission_definition]"));
|
|
96
123
|
assert.ok(missionListString.includes("[list_tmmission_checkpoint]"));
|
package/eslint.config.js
CHANGED
|
@@ -4,28 +4,26 @@ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"
|
|
|
4
4
|
import jsdoc from "eslint-plugin-jsdoc";
|
|
5
5
|
|
|
6
6
|
export default [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
{
|
|
8
|
+
languageOptions: {
|
|
9
|
+
globals: {
|
|
10
|
+
...globals.browser,
|
|
11
|
+
...globals.node,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
13
14
|
},
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
pluginJs.configs.recommended,
|
|
16
|
+
eslintPluginPrettierRecommended,
|
|
17
|
+
jsdoc.configs["flat/recommended"],
|
|
18
|
+
{
|
|
19
|
+
files: ["**/*.js"],
|
|
20
|
+
plugins: {
|
|
21
|
+
jsdoc,
|
|
22
|
+
},
|
|
23
|
+
rules: {
|
|
24
|
+
"jsdoc/require-description": 0,
|
|
25
|
+
"jsdoc/require-param-description": 0,
|
|
26
|
+
"jsdoc/require-returns-description": 0,
|
|
27
|
+
},
|
|
22
28
|
},
|
|
23
|
-
rules: {
|
|
24
|
-
"jsdoc/require-description": 0,
|
|
25
|
-
"jsdoc/require-param-description": 0,
|
|
26
|
-
"jsdoc/require-returns-description": 0,
|
|
27
|
-
"jsdoc/require-param-type": 0,
|
|
28
|
-
"jsdoc/require-returns-type": 0,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
29
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fboes/aerofly-custom-missions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Builder for Aerofly FS4 Custom Missions Files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"eslint": "npx eslint **/*.js --fix",
|
|
11
11
|
"tsc": "npx tsc --build",
|
|
12
12
|
"tsc-watch": "npx tsc --watch",
|
|
13
|
-
"build": "npm run
|
|
13
|
+
"build": "npm run tsc && npm run eslint && npm run prettier"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"aerofly-fs4",
|