@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.2
|
|
4
|
+
|
|
5
|
+
- Added altitude constraint property
|
|
6
|
+
- Improved handling of cloud layers
|
|
7
|
+
|
|
8
|
+
## 1.2.1
|
|
9
|
+
|
|
10
|
+
- Changed handling of checkpoints, as it is obviously possible to have missions without checkpoints
|
|
11
|
+
- Changed actual file generation to improve programmatic adding of entries to file
|
|
12
|
+
- Adding `is_scheduled` and `tutorial_name` property
|
|
13
|
+
- Improved cloud handling
|
|
14
|
+
- Improved handling off unset values
|
|
15
|
+
- Added `cold_and_dark`, `before_start`, `pushback"` as flight setting
|
|
16
|
+
|
|
3
17
|
## 1.2.0
|
|
4
18
|
|
|
5
19
|
- Adding new cloud level `cirrus_cover` / `cirrus_base`
|
|
@@ -13,7 +27,7 @@
|
|
|
13
27
|
## 1.1.0
|
|
14
28
|
|
|
15
29
|
- Added new mission properties `tags`, `isFeatured`, `difficulty`, `distance`, `duration` and translations
|
|
16
|
-
- Added new flight settings `
|
|
30
|
+
- Added new flight settings `winch_launch`, `aerotow`
|
|
17
31
|
- Improved temperature property
|
|
18
32
|
|
|
19
33
|
## 1.0.4
|
package/README.md
CHANGED
|
@@ -171,19 +171,14 @@ The `tags` property of a single mission can contain multiple values. The followi
|
|
|
171
171
|
- `destination`
|
|
172
172
|
- Be aware that all units for altitude, elevation or distance are measured in meters! In most cases there will be helper functions for defining these values in feet (for length, altitude, elevation) or statute miles (for visibility).
|
|
173
173
|
|
|
174
|
-
There are also some unsupported properties, which are present in Aerofly FS4, but as of yet will not be generated by this library:
|
|
175
|
-
|
|
176
|
-
```
|
|
177
|
-
<[string8][tutorial_name][c172]> // Opens https://www.aerofly.com/aircraft-tutorials/${tutorial_name}
|
|
178
|
-
<[bool][is_scheduled][true]>
|
|
179
|
-
```
|
|
180
|
-
|
|
181
174
|
### Known issues
|
|
182
175
|
|
|
183
176
|
- `AeroflyMissionConditions.time`: Even though a date property is available in Aerofly FS 4, [the custom missions cannot change the date in Aerofly FS 4](https://www.aerofly.com/community/forum/index.php?thread/22487-more-settings-for-environment-conditions/&pageNo=1). This is obviously as the date cannot be changed inside the simulation.
|
|
184
177
|
- `AeroflyMissionConditions.clouds`: Even though Aerofly FS 4 is able to handle three levels of clouds, the custom missions can only set two levels in Aerofly FS 4. This is obviously as the third cloud layer cannot be changed inside the simulation.
|
|
185
178
|
- `AeroflyMissionCheckpoint.type`: Even though internal flight plans of Aerofly FS 4 have types `"departure"|"arrival"|"approach"`, [Aerofly FS 4 dumps SIDs and STARs on loading a custom missions](https://www.aerofly.com/community/forum/index.php?thread/22156-flight-plans/).
|
|
186
179
|
- `AeroflyMission.aircraft.livery`: Even though Aerofly FS 4 knows multiple liveries per plane, [the custom missions file is not able to set liveries to any other but the standard livery](https://www.aerofly.com/community/forum/index.php?thread/19105-user-created-custom-missions/).
|
|
180
|
+
- `AeroflyMission.isScheduled`: Even though for regular missions this will mark these as a "Scheduled flight", [custom missions cannot be created as "Scheduled flights"](https://www.aerofly.com/community/forum/index.php?thread/23101-challenge-guides/&postID=147354#post147432).
|
|
181
|
+
- `AeroflyMission.isFeatured`: Even though for regular missions this will mark these as a featured missions, custom missions cannot be created as featured missions.
|
|
187
182
|
|
|
188
183
|
## Status
|
|
189
184
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _AeroflyConfigFileSet_indent;
|
|
1
13
|
const feetPerMeter = 3.28084;
|
|
2
14
|
const meterPerStatuteMile = 1609.344;
|
|
15
|
+
export class AeroflyConfigFileSet {
|
|
16
|
+
constructor(indent, type, name, value = "") {
|
|
17
|
+
_AeroflyConfigFileSet_indent.set(this, void 0);
|
|
18
|
+
__classPrivateFieldSet(this, _AeroflyConfigFileSet_indent, indent, "f");
|
|
19
|
+
this.elements = [`${this.indent}<[${type}][${name}][${value}]`];
|
|
20
|
+
}
|
|
21
|
+
get indent() {
|
|
22
|
+
return " ".repeat(__classPrivateFieldGet(this, _AeroflyConfigFileSet_indent, "f"));
|
|
23
|
+
}
|
|
24
|
+
push(type, name, value, comment = "") {
|
|
25
|
+
if (value instanceof Array) {
|
|
26
|
+
value = value.join(" ");
|
|
27
|
+
}
|
|
28
|
+
else if (typeof value === "boolean") {
|
|
29
|
+
value = value ? "true" : "false";
|
|
30
|
+
}
|
|
31
|
+
let tag = `${this.indent} <[${type}][${name}][${value}]>`;
|
|
32
|
+
if (comment) {
|
|
33
|
+
tag += ` // ${comment}`;
|
|
34
|
+
}
|
|
35
|
+
return this.pushRaw(tag);
|
|
36
|
+
}
|
|
37
|
+
pushRaw(s) {
|
|
38
|
+
this.elements.push(s);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
toString() {
|
|
42
|
+
return this.elements.join("\n") + "\n" + `${this.indent}>`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
_AeroflyConfigFileSet_indent = new WeakMap();
|
|
3
46
|
/**
|
|
4
47
|
* @class
|
|
5
48
|
* A list of flight plans.
|
|
@@ -20,7 +63,8 @@ export class AeroflyMissionsList {
|
|
|
20
63
|
*/
|
|
21
64
|
toString() {
|
|
22
65
|
const separator = "\n// -----------------------------------------------------------------------------\n";
|
|
23
|
-
return
|
|
66
|
+
return `\
|
|
67
|
+
<[file][][]
|
|
24
68
|
<[tmmissions_list][][]
|
|
25
69
|
<[list_tmmission_definition][missions][]${separator + this.missions.join(separator) + separator} >
|
|
26
70
|
>
|
|
@@ -41,21 +85,23 @@ export class AeroflyMission {
|
|
|
41
85
|
* @param {object} [additionalAttributes] allows to set additional attributes on creation
|
|
42
86
|
* @param {string} [additionalAttributes.description] text, mission briefing, etc
|
|
43
87
|
* @param {AeroflyLocalizedText[]} [additionalAttributes.localizedTexts] translations for title and description
|
|
88
|
+
* @param {?string} [additionalAttributes.tutorialName] will create a link to a tutorial page at https://www.aerofly.com/aircraft-tutorials/
|
|
44
89
|
* @param {string[]} [additionalAttributes.tags]
|
|
45
|
-
* @param {boolean} [additionalAttributes.isFeatured] makes this mission pop up in "Challenges"
|
|
46
|
-
* @param {number
|
|
47
|
-
* @param {"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
90
|
+
* @param {?boolean} [additionalAttributes.isFeatured] makes this mission pop up in "Challenges"
|
|
91
|
+
* @param {?number} [additionalAttributes.difficulty] values between 0.00 and 2.00 have been encountered, but they seem to be without limit
|
|
92
|
+
* @param {"cold_and_dark"|"before_start"|"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"|"pushback"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
48
93
|
* @param {{name:string,livery:string,icao:string}} [additionalAttributes.aircraft] for this mission
|
|
49
94
|
* @param {string} [additionalAttributes.callsign] of aircraft, uppercased
|
|
50
95
|
* @param {object} [additionalAttributes.origin] position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
51
96
|
* @param {object} [additionalAttributes.destination] position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
52
|
-
* @param {number} [additionalAttributes.distance] in meters
|
|
53
|
-
* @param {number} [additionalAttributes.duration] in seconds
|
|
97
|
+
* @param {?number} [additionalAttributes.distance] in meters
|
|
98
|
+
* @param {?number} [additionalAttributes.duration] in seconds
|
|
99
|
+
* @param {?boolean} [additionalAttributes.isScheduled] marks this flight as "Scheduled flight".
|
|
54
100
|
* @param {?AeroflyMissionTargetPlane} [additionalAttributes.finish] as finish condition
|
|
55
101
|
* @param {AeroflyMissionConditions} [additionalAttributes.conditions] like time and weather for mission
|
|
56
102
|
* @param {AeroflyMissionCheckpoint[]} [additionalAttributes.checkpoints] form the actual flight plan
|
|
57
103
|
*/
|
|
58
|
-
constructor(title, { description = "", localizedTexts = [], tags = [], isFeatured =
|
|
104
|
+
constructor(title, { tutorialName = null, description = "", localizedTexts = [], tags = [], isFeatured = null, difficulty = null, flightSetting = "taxi", aircraft = {
|
|
59
105
|
name: "c172",
|
|
60
106
|
icao: "",
|
|
61
107
|
livery: "",
|
|
@@ -71,7 +117,8 @@ export class AeroflyMission {
|
|
|
71
117
|
latitude: 0,
|
|
72
118
|
dir: 0,
|
|
73
119
|
alt: 0,
|
|
74
|
-
}, distance =
|
|
120
|
+
}, distance = null, duration = null, isScheduled = null, finish = null, conditions = new AeroflyMissionConditions(), checkpoints = [], } = {}) {
|
|
121
|
+
this.tutorialName = tutorialName;
|
|
75
122
|
this.title = title;
|
|
76
123
|
this.checkpoints = checkpoints;
|
|
77
124
|
this.description = description;
|
|
@@ -86,6 +133,7 @@ export class AeroflyMission {
|
|
|
86
133
|
this.destination = destination;
|
|
87
134
|
this.distance = distance;
|
|
88
135
|
this.duration = duration;
|
|
136
|
+
this.isScheduled = isScheduled;
|
|
89
137
|
this.finish = finish;
|
|
90
138
|
this.conditions = conditions;
|
|
91
139
|
}
|
|
@@ -114,9 +162,6 @@ export class AeroflyMission {
|
|
|
114
162
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
115
163
|
*/
|
|
116
164
|
toString() {
|
|
117
|
-
if (this.checkpoints.length < 2) {
|
|
118
|
-
throw Error("this.checkpoints.length < 2");
|
|
119
|
-
}
|
|
120
165
|
if (!this.origin.icao) {
|
|
121
166
|
const firstCheckpoint = this.checkpoints[0];
|
|
122
167
|
this.origin = {
|
|
@@ -137,52 +182,60 @@ export class AeroflyMission {
|
|
|
137
182
|
alt: lastCheckpoint.altitude,
|
|
138
183
|
};
|
|
139
184
|
}
|
|
140
|
-
const
|
|
185
|
+
const fileSet = new AeroflyConfigFileSet(3, "tmmission_definition", "mission");
|
|
186
|
+
fileSet.push("string8", "title", this.title);
|
|
187
|
+
fileSet.push("string8", "description", this.description);
|
|
188
|
+
if (this.tutorialName !== null) {
|
|
189
|
+
fileSet.push("string8", "tutorial_name", this.tutorialName, `Opens https://www.aerofly.com/aircraft-tutorials/${this.tutorialName}`);
|
|
190
|
+
}
|
|
141
191
|
if (this.localizedTexts.length > 0) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
192
|
+
fileSet.pushRaw(new AeroflyConfigFileSet(4, "list_tmmission_definition_localized", "localized_text")
|
|
193
|
+
.pushRaw(this.getLocalizedTextsString())
|
|
194
|
+
.toString());
|
|
145
195
|
}
|
|
146
196
|
if (this.tags.length > 0) {
|
|
147
|
-
|
|
197
|
+
fileSet.push("string8u", "tags", this.tags.join(" "));
|
|
198
|
+
}
|
|
199
|
+
if (this.difficulty !== null) {
|
|
200
|
+
fileSet.push("float64", "difficulty", this.difficulty);
|
|
201
|
+
}
|
|
202
|
+
if (this.isFeatured !== null) {
|
|
203
|
+
fileSet.push("bool", "is_featured", this.isFeatured);
|
|
148
204
|
}
|
|
149
|
-
|
|
150
|
-
|
|
205
|
+
fileSet.push("string8", "flight_setting", this.flightSetting);
|
|
206
|
+
fileSet.push("string8u", "aircraft_name", this.aircraft.name);
|
|
207
|
+
/*if (this.aircraft.livery) {
|
|
208
|
+
fileSet.push("string8", "aircraft_livery", this.aircraft.livery);
|
|
209
|
+
}*/
|
|
210
|
+
fileSet.push("stringt8c", "aircraft_icao", this.aircraft.icao);
|
|
211
|
+
fileSet.push("stringt8c", "callsign", this.callsign);
|
|
212
|
+
fileSet.push("stringt8c", "origin_icao", this.origin.icao);
|
|
213
|
+
fileSet.push("tmvector2d", "origin_lon_lat", [this.origin.longitude, this.origin.latitude]);
|
|
214
|
+
fileSet.push("float64", "origin_alt", this.origin.alt, `${Math.ceil(this.origin.alt * feetPerMeter)} ft MSL`);
|
|
215
|
+
fileSet.push("float64", "origin_dir", this.origin.dir);
|
|
216
|
+
fileSet.push("stringt8c", "destination_icao", this.destination.icao);
|
|
217
|
+
fileSet.push("tmvector2d", "destination_lon_lat", [this.destination.longitude, this.destination.latitude]);
|
|
218
|
+
fileSet.push("float64", "destination_alt", this.destination.alt, `${Math.ceil(this.destination.alt * feetPerMeter)} ft MSL`);
|
|
219
|
+
fileSet.push("float64", "destination_dir", this.destination.dir);
|
|
220
|
+
if (this.distance !== null) {
|
|
221
|
+
fileSet.push("float64", "distance", this.distance, `${Math.round(this.distance / 1000)} km`);
|
|
151
222
|
}
|
|
152
|
-
if (this.
|
|
153
|
-
|
|
223
|
+
if (this.duration !== null) {
|
|
224
|
+
fileSet.push("float64", "duration", this.duration, `${Math.round(this.duration / 60)} min`);
|
|
154
225
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
moreOptionalProperties.push(` <[float64] [distance] [${this.distance}]> // ${Math.ceil(this.distance / 1000)} km`);
|
|
226
|
+
if (this.isScheduled !== null) {
|
|
227
|
+
fileSet.push("bool", "is_scheduled", this.isScheduled ? "true" : "false");
|
|
158
228
|
}
|
|
159
|
-
if (this.
|
|
160
|
-
|
|
229
|
+
if (this.finish !== null) {
|
|
230
|
+
fileSet.pushRaw(this.finish.toString());
|
|
161
231
|
}
|
|
162
|
-
|
|
163
|
-
|
|
232
|
+
fileSet.pushRaw(this.conditions.toString());
|
|
233
|
+
if (this.checkpoints.length > 0) {
|
|
234
|
+
fileSet.pushRaw(new AeroflyConfigFileSet(4, "list_tmmission_checkpoint", "checkpoints")
|
|
235
|
+
.pushRaw(this.getCheckpointsString())
|
|
236
|
+
.toString());
|
|
164
237
|
}
|
|
165
|
-
return
|
|
166
|
-
<[string8][title][${this.title}]>
|
|
167
|
-
<[string8][description][${this.description}]>${optionalProperties.length > 0 ? "\n" + optionalProperties.join("\n") : ""}
|
|
168
|
-
<[string8] [flight_setting] [${this.flightSetting}]>
|
|
169
|
-
<[string8u] [aircraft_name] [${this.aircraft.name}]>
|
|
170
|
-
//<[string8u][aircraft_livery] [${this.aircraft.livery}]>
|
|
171
|
-
<[stringt8c] [aircraft_icao] [${this.aircraft.icao}]>
|
|
172
|
-
<[stringt8c] [callsign] [${this.callsign}]>
|
|
173
|
-
<[stringt8c] [origin_icao] [${this.origin.icao}]>
|
|
174
|
-
<[tmvector2d][origin_lon_lat] [${this.origin.longitude} ${this.origin.latitude}]>
|
|
175
|
-
<[float64] [origin_alt] [${this.origin.alt}]> // ${Math.ceil(this.origin.alt * feetPerMeter)} ft MSL
|
|
176
|
-
<[float64] [origin_dir] [${this.origin.dir}]>
|
|
177
|
-
<[stringt8c] [destination_icao] [${this.destination.icao}]>
|
|
178
|
-
<[tmvector2d][destination_lon_lat][${this.destination.longitude} ${this.destination.latitude}]>
|
|
179
|
-
<[float64] [destination_alt] [${this.destination.alt}]> // ${Math.ceil(this.destination.alt * feetPerMeter)} ft MSL
|
|
180
|
-
<[float64] [destination_dir] [${this.destination.dir}]>${moreOptionalProperties.length > 0 ? "\n" + moreOptionalProperties.join("\n") : ""}
|
|
181
|
-
${this.conditions}
|
|
182
|
-
<[list_tmmission_checkpoint][checkpoints][]
|
|
183
|
-
${this.getCheckpointsString()}
|
|
184
|
-
>
|
|
185
|
-
>`;
|
|
238
|
+
return fileSet.toString();
|
|
186
239
|
}
|
|
187
240
|
}
|
|
188
241
|
/**
|
|
@@ -202,15 +255,15 @@ export class AeroflyMissionConditions {
|
|
|
202
255
|
* @param {number} [additionalAttributes.turbulenceStrength] 0..1, percentage
|
|
203
256
|
* @param {number} [additionalAttributes.thermalStrength] 0..1, percentage
|
|
204
257
|
* @param {number} [additionalAttributes.visibility] in meters
|
|
205
|
-
* @param {number
|
|
206
|
-
* @param {number
|
|
258
|
+
* @param {?number} [additionalAttributes.visibility_sm] in statute miles, will overwrite visibility
|
|
259
|
+
* @param {?number} [additionalAttributes.temperature] in °C, will overwrite thermalStrength
|
|
207
260
|
* @param {AeroflyMissionConditionsCloud[]} [additionalAttributes.clouds] for the whole flight
|
|
208
261
|
*/
|
|
209
262
|
constructor({ time = new Date(), wind = {
|
|
210
263
|
direction: 0,
|
|
211
264
|
speed: 0,
|
|
212
265
|
gusts: 0,
|
|
213
|
-
}, turbulenceStrength = 0, thermalStrength = 0, visibility =
|
|
266
|
+
}, turbulenceStrength = 0, thermalStrength = 0, visibility = 25000, visibility_sm = null, temperature = null, clouds = [], } = {}) {
|
|
214
267
|
/**
|
|
215
268
|
* @property {AeroflyMissionConditionsCloud[]} clouds for the whole flight
|
|
216
269
|
*/
|
|
@@ -287,21 +340,21 @@ export class AeroflyMissionConditions {
|
|
|
287
340
|
if (this.clouds.length < 1) {
|
|
288
341
|
this.clouds = [new AeroflyMissionConditionsCloud(0, 0)];
|
|
289
342
|
}
|
|
290
|
-
return
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
343
|
+
return new AeroflyConfigFileSet(4, "tmmission_conditions", "conditions")
|
|
344
|
+
.pushRaw(new AeroflyConfigFileSet(5, "tm_time_utc", "time")
|
|
345
|
+
.push("int32", "time_year", this.time.getUTCFullYear())
|
|
346
|
+
.push("int32", "time_month", this.time.getUTCMonth() + 1)
|
|
347
|
+
.push("int32", "time_day", this.time.getUTCDate())
|
|
348
|
+
.push("float64", "time_hours", this.time_hours, `${this.time_presentational} UTC`)
|
|
349
|
+
.toString())
|
|
350
|
+
.push("float64", "wind_direction", this.wind.direction)
|
|
351
|
+
.push("float64", "wind_speed", this.wind.speed, "kts")
|
|
352
|
+
.push("float64", "wind_gusts", this.wind.gusts, "kts")
|
|
353
|
+
.push("float64", "turbulence_strength", this.turbulenceStrength)
|
|
354
|
+
.push("float64", "thermal_strength", this.thermalStrength, `${this.temperature} °C`)
|
|
355
|
+
.push("float64", "visibility", this.visibility, `${this.visibility_sm} SM`)
|
|
356
|
+
.pushRaw(this.getCloudsString())
|
|
357
|
+
.toString();
|
|
305
358
|
}
|
|
306
359
|
}
|
|
307
360
|
/**
|
|
@@ -364,17 +417,23 @@ export class AeroflyMissionConditionsCloud {
|
|
|
364
417
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
365
418
|
*/
|
|
366
419
|
toString(index = 0) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
420
|
+
const getIndexString = (index) => {
|
|
421
|
+
switch (index) {
|
|
422
|
+
case 0:
|
|
423
|
+
return "cloud";
|
|
424
|
+
case 1:
|
|
425
|
+
return "cirrus";
|
|
426
|
+
case 2:
|
|
427
|
+
return "cumulus_mediocris";
|
|
428
|
+
default:
|
|
429
|
+
return "more_clouds";
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
const indexString = getIndexString(index);
|
|
433
|
+
const comment = index > 1 ? '//' : '';
|
|
434
|
+
return `\
|
|
435
|
+
${comment}<[float64][${indexString}_cover][${this.cover ?? 0}]> // ${this.cover_code}
|
|
436
|
+
${comment}<[float64][${indexString}_base][${this.base}]> // ${this.base_feet} ft AGL`;
|
|
378
437
|
}
|
|
379
438
|
}
|
|
380
439
|
/**
|
|
@@ -399,21 +458,25 @@ export class AeroflyMissionCheckpoint {
|
|
|
399
458
|
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
400
459
|
* @param {number} [additionalAttributes.altitude] The height in meters above or below the WGS
|
|
401
460
|
* 84 reference ellipsoid
|
|
402
|
-
* @param {number
|
|
461
|
+
* @param {?number} [additionalAttributes.altitude_feet] The height in feet above or below the WGS
|
|
403
462
|
* 84 reference ellipsoid. Will overwrite altitude
|
|
404
|
-
* @param {number} [additionalAttributes.
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
* @param {
|
|
408
|
-
* @param {number
|
|
409
|
-
* @param {
|
|
463
|
+
* @param {number} [additionalAttributes.altitudeConstraint] The altitude given in `altitude`
|
|
464
|
+
* will be interpreted as mandatory flight plan altitude instead of
|
|
465
|
+
* suggestion.
|
|
466
|
+
* @param {boolean} [additionalAttributes.direction] of runway, in degree
|
|
467
|
+
* @param {?number} [additionalAttributes.slope] of runway
|
|
468
|
+
* @param {?number} [additionalAttributes.length] of runway, in meters
|
|
469
|
+
* @param {?number} [additionalAttributes.length_feet] of runway, in feet. Will overwrite length
|
|
470
|
+
* @param {?number} [additionalAttributes.frequency] of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
471
|
+
* @param {?boolean} [additionalAttributes.flyOver] if waypoint is meant to be flown over
|
|
410
472
|
*/
|
|
411
|
-
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = null, direction = null, slope = null, length = null, length_feet = null, frequency = null, flyOver =
|
|
473
|
+
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = null, altitudeConstraint = null, direction = null, slope = null, length = null, length_feet = null, frequency = null, flyOver = null, } = {}) {
|
|
412
474
|
this.type = type;
|
|
413
475
|
this.name = name;
|
|
414
476
|
this.longitude = longitude;
|
|
415
477
|
this.latitude = latitude;
|
|
416
478
|
this.altitude = altitude;
|
|
479
|
+
this.altitudeConstraint = altitudeConstraint;
|
|
417
480
|
this.direction = direction;
|
|
418
481
|
this.slope = slope;
|
|
419
482
|
this.length = length;
|
|
@@ -457,11 +520,11 @@ export class AeroflyMissionCheckpoint {
|
|
|
457
520
|
if (!this.frequency) {
|
|
458
521
|
return "None";
|
|
459
522
|
}
|
|
460
|
-
if (this.frequency >
|
|
461
|
-
return String(this.frequency /
|
|
523
|
+
if (this.frequency > 1000000) {
|
|
524
|
+
return String(this.frequency / 1000000) + " MHz";
|
|
462
525
|
}
|
|
463
|
-
if (this.frequency >
|
|
464
|
-
return String(this.frequency /
|
|
526
|
+
if (this.frequency > 1000) {
|
|
527
|
+
return String(this.frequency / 1000) + " kHz";
|
|
465
528
|
}
|
|
466
529
|
return String(this.frequency) + " Hz";
|
|
467
530
|
}
|
|
@@ -470,26 +533,32 @@ export class AeroflyMissionCheckpoint {
|
|
|
470
533
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
471
534
|
*/
|
|
472
535
|
toString(index = 0) {
|
|
473
|
-
const
|
|
536
|
+
const fileSet = new AeroflyConfigFileSet(5, "tmmission_checkpoint", "element", String(index))
|
|
537
|
+
.push("string8u", "type", this.type)
|
|
538
|
+
.push("string8u", "name", this.name)
|
|
539
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
540
|
+
.push("float64", "altitude", this.altitude, `${Math.ceil(this.altitude_feet)} ft`)
|
|
541
|
+
.push("float64", "direction", this.direction ?? (index === 0 ? -1 : 0))
|
|
542
|
+
.push("float64", "slope", this.slope ?? 0);
|
|
543
|
+
if (this.altitudeConstraint !== null) {
|
|
544
|
+
fileSet.push("bool", "alt_cst", this.altitudeConstraint);
|
|
545
|
+
}
|
|
474
546
|
if (this.length) {
|
|
475
|
-
|
|
547
|
+
fileSet.push("float64", "length", this.length ?? 0, `${Math.floor(this.length_feet)} ft`);
|
|
476
548
|
}
|
|
477
549
|
if (this.frequency) {
|
|
478
|
-
|
|
550
|
+
fileSet.push("float64", "frequency", this.frequency ?? 0, `${this.frequency_string}`);
|
|
479
551
|
}
|
|
480
|
-
if (this.flyOver !==
|
|
481
|
-
|
|
552
|
+
if (this.flyOver !== null) {
|
|
553
|
+
fileSet.push("bool", "fly_over", this.flyOver);
|
|
482
554
|
}
|
|
483
|
-
return
|
|
484
|
-
<[string8u][type][${this.type}]>
|
|
485
|
-
<[string8u][name][${this.name}]>
|
|
486
|
-
<[vector2_float64][lon_lat][${this.longitude} ${this.latitude}]>
|
|
487
|
-
<[float64][altitude][${this.altitude}]> // ${Math.ceil(this.altitude_feet)} ft
|
|
488
|
-
<[float64][direction][${this.direction ?? (index === 0 ? -1 : 0)}]>
|
|
489
|
-
<[float64][slope][${this.slope ?? 0}]>${optionalProperties.length > 0 ? "\n" + optionalProperties.join("\n") : ""}
|
|
490
|
-
>`;
|
|
555
|
+
return fileSet.toString();
|
|
491
556
|
}
|
|
492
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* @class
|
|
560
|
+
* A translation for the mission title and description.
|
|
561
|
+
*/
|
|
493
562
|
export class AeroflyLocalizedText {
|
|
494
563
|
/**
|
|
495
564
|
* @param {string} language ISO 639-1 like
|
|
@@ -518,13 +587,17 @@ export class AeroflyLocalizedText {
|
|
|
518
587
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
519
588
|
*/
|
|
520
589
|
toString(index = 0) {
|
|
521
|
-
return
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
590
|
+
return new AeroflyConfigFileSet(4, "tmmission_definition_localized", "element", String(index))
|
|
591
|
+
.push("string8u", "language", this.language)
|
|
592
|
+
.push("string8", "title", this.title)
|
|
593
|
+
.push("string8", "description", this.description)
|
|
594
|
+
.toString();
|
|
526
595
|
}
|
|
527
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* @class
|
|
599
|
+
* A target plane which the aircraft needs to cross.
|
|
600
|
+
*/
|
|
528
601
|
export class AeroflyMissionTargetPlane {
|
|
529
602
|
/**
|
|
530
603
|
*
|
|
@@ -544,10 +617,10 @@ export class AeroflyMissionTargetPlane {
|
|
|
544
617
|
this.name = name;
|
|
545
618
|
}
|
|
546
619
|
toString() {
|
|
547
|
-
return
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
620
|
+
return new AeroflyConfigFileSet(4, "tmmission_target_plane", this.name)
|
|
621
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
622
|
+
.push("float64", "direction", this.dir)
|
|
623
|
+
.toString();
|
|
551
624
|
}
|
|
552
625
|
}
|
|
553
626
|
export default {
|