@fboes/aerofly-custom-missions 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/README.md +2 -7
- package/dist/index.js +168 -101
- package/dist/index.test.js +77 -39
- package/docs/custom_missions_user.tmc +49 -1234
- package/package.json +1 -1
- package/src/index.test.ts +81 -34
- package/src/index.ts +218 -127
- package/types/index.d.ts +71 -30
- package/types/index.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
- Changed handling of checkpoints, as it is obviously possible to have missions without checkpoints
|
|
6
|
+
- Changed actual file generation to improve programmatic adding of entries to file
|
|
7
|
+
- Adding `is_scheduled` and `tutorial_name` property
|
|
8
|
+
- Improved cloud handling
|
|
9
|
+
- Improved handling off unset values
|
|
10
|
+
- Added `cold_and_dark`, `before_start`, `pushback"` as flight setting
|
|
11
|
+
|
|
3
12
|
## 1.2.0
|
|
4
13
|
|
|
5
14
|
- Adding new cloud level `cirrus_cover` / `cirrus_base`
|
|
@@ -13,7 +22,7 @@
|
|
|
13
22
|
## 1.1.0
|
|
14
23
|
|
|
15
24
|
- Added new mission properties `tags`, `isFeatured`, `difficulty`, `distance`, `duration` and translations
|
|
16
|
-
- Added new flight settings `
|
|
25
|
+
- Added new flight settings `winch_launch`, `aerotow`
|
|
17
26
|
- Improved temperature property
|
|
18
27
|
|
|
19
28
|
## 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,16 +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
|
-
let indexString = "
|
|
420
|
+
let indexString = "";
|
|
368
421
|
switch (index) {
|
|
422
|
+
case 0:
|
|
423
|
+
indexString = "cloud";
|
|
424
|
+
break;
|
|
369
425
|
case 1:
|
|
370
426
|
indexString = "cirrus";
|
|
371
427
|
break;
|
|
372
428
|
case 2:
|
|
373
429
|
indexString = "cumulus_mediocris";
|
|
374
430
|
break;
|
|
431
|
+
default:
|
|
432
|
+
return "";
|
|
375
433
|
}
|
|
376
|
-
|
|
434
|
+
// TODO
|
|
435
|
+
return `\
|
|
436
|
+
<[float64][${indexString}_cover][${this.cover ?? 0}]> // ${this.cover_code}
|
|
377
437
|
<[float64][${indexString}_base][${this.base}]> // ${this.base_feet} ft AGL`;
|
|
378
438
|
}
|
|
379
439
|
}
|
|
@@ -399,16 +459,16 @@ export class AeroflyMissionCheckpoint {
|
|
|
399
459
|
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
400
460
|
* @param {number} [additionalAttributes.altitude] The height in meters above or below the WGS
|
|
401
461
|
* 84 reference ellipsoid
|
|
402
|
-
* @param {number
|
|
462
|
+
* @param {?number} [additionalAttributes.altitude_feet] The height in feet above or below the WGS
|
|
403
463
|
* 84 reference ellipsoid. Will overwrite altitude
|
|
404
464
|
* @param {number} [additionalAttributes.direction] of runway, in degree
|
|
405
|
-
* @param {number
|
|
406
|
-
* @param {number
|
|
407
|
-
* @param {number
|
|
408
|
-
* @param {number
|
|
409
|
-
* @param {boolean
|
|
465
|
+
* @param {?number} [additionalAttributes.slope] of runway
|
|
466
|
+
* @param {?number} [additionalAttributes.length] of runway, in meters
|
|
467
|
+
* @param {?number} [additionalAttributes.length_feet] of runway, in feet. Will overwrite length
|
|
468
|
+
* @param {?number} [additionalAttributes.frequency] of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
469
|
+
* @param {?boolean} [additionalAttributes.flyOver] if waypoint is meant to be flown over
|
|
410
470
|
*/
|
|
411
|
-
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = null, direction = null, slope = null, length = null, length_feet = null, frequency = null, flyOver =
|
|
471
|
+
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = null, direction = null, slope = null, length = null, length_feet = null, frequency = null, flyOver = null, } = {}) {
|
|
412
472
|
this.type = type;
|
|
413
473
|
this.name = name;
|
|
414
474
|
this.longitude = longitude;
|
|
@@ -457,11 +517,11 @@ export class AeroflyMissionCheckpoint {
|
|
|
457
517
|
if (!this.frequency) {
|
|
458
518
|
return "None";
|
|
459
519
|
}
|
|
460
|
-
if (this.frequency >
|
|
461
|
-
return String(this.frequency /
|
|
520
|
+
if (this.frequency > 1000000) {
|
|
521
|
+
return String(this.frequency / 1000000) + " MHz";
|
|
462
522
|
}
|
|
463
|
-
if (this.frequency >
|
|
464
|
-
return String(this.frequency /
|
|
523
|
+
if (this.frequency > 1000) {
|
|
524
|
+
return String(this.frequency / 1000) + " kHz";
|
|
465
525
|
}
|
|
466
526
|
return String(this.frequency) + " Hz";
|
|
467
527
|
}
|
|
@@ -470,26 +530,29 @@ export class AeroflyMissionCheckpoint {
|
|
|
470
530
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
471
531
|
*/
|
|
472
532
|
toString(index = 0) {
|
|
473
|
-
const
|
|
533
|
+
const fileSet = new AeroflyConfigFileSet(5, "tmmission_checkpoint", "element", String(index))
|
|
534
|
+
.push("string8u", "type", this.type)
|
|
535
|
+
.push("string8u", "name", this.name)
|
|
536
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
537
|
+
.push("float64", "altitude", this.altitude, `${Math.ceil(this.altitude_feet)} ft`)
|
|
538
|
+
.push("float64", "direction", this.direction ?? (index === 0 ? -1 : 0))
|
|
539
|
+
.push("float64", "slope", this.slope ?? 0);
|
|
474
540
|
if (this.length) {
|
|
475
|
-
|
|
541
|
+
fileSet.push("float64", "length", this.length ?? 0, `${Math.floor(this.length_feet)} ft`);
|
|
476
542
|
}
|
|
477
543
|
if (this.frequency) {
|
|
478
|
-
|
|
544
|
+
fileSet.push("float64", "frequency", this.frequency ?? 0, `${this.frequency_string}`);
|
|
479
545
|
}
|
|
480
|
-
if (this.flyOver !==
|
|
481
|
-
|
|
546
|
+
if (this.flyOver !== null) {
|
|
547
|
+
fileSet.push("bool", "fly_over", this.flyOver);
|
|
482
548
|
}
|
|
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
|
-
>`;
|
|
549
|
+
return fileSet.toString();
|
|
491
550
|
}
|
|
492
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* @class
|
|
554
|
+
* A translation for the mission title and description.
|
|
555
|
+
*/
|
|
493
556
|
export class AeroflyLocalizedText {
|
|
494
557
|
/**
|
|
495
558
|
* @param {string} language ISO 639-1 like
|
|
@@ -518,13 +581,17 @@ export class AeroflyLocalizedText {
|
|
|
518
581
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
519
582
|
*/
|
|
520
583
|
toString(index = 0) {
|
|
521
|
-
return
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
584
|
+
return new AeroflyConfigFileSet(4, "tmmission_definition_localized", "element", String(index))
|
|
585
|
+
.push("string8u", "language", this.language)
|
|
586
|
+
.push("string8", "title", this.title)
|
|
587
|
+
.push("string8", "description", this.description)
|
|
588
|
+
.toString();
|
|
526
589
|
}
|
|
527
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* @class
|
|
593
|
+
* A target plane which the aircraft needs to cross.
|
|
594
|
+
*/
|
|
528
595
|
export class AeroflyMissionTargetPlane {
|
|
529
596
|
/**
|
|
530
597
|
*
|
|
@@ -544,10 +611,10 @@ export class AeroflyMissionTargetPlane {
|
|
|
544
611
|
this.name = name;
|
|
545
612
|
}
|
|
546
613
|
toString() {
|
|
547
|
-
return
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
614
|
+
return new AeroflyConfigFileSet(4, "tmmission_target_plane", this.name)
|
|
615
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
616
|
+
.push("float64", "direction", this.dir)
|
|
617
|
+
.toString();
|
|
551
618
|
}
|
|
552
619
|
}
|
|
553
620
|
export default {
|