@fboes/aerofly-custom-missions 1.2.3 → 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/CHANGELOG.md +56 -22
- package/dist/dto/AeroflyLocalizedText.js +12 -8
- package/dist/dto/AeroflyMission.js +53 -51
- package/dist/dto/AeroflyMissionCheckpoint.js +26 -20
- package/dist/dto/AeroflyMissionConditions.js +26 -24
- package/dist/dto/AeroflyMissionConditionsCloud.js +18 -8
- package/dist/dto/AeroflyMissionTargetPlane.js +10 -5
- package/dist/dto/AeroflyMissionsList.js +15 -7
- package/dist/index.test.js +14 -15
- 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 +1 -1
- package/src/dto/AeroflyLocalizedText.ts +13 -8
- package/src/dto/AeroflyMission.ts +76 -81
- package/src/dto/AeroflyMissionCheckpoint.ts +31 -32
- package/src/dto/AeroflyMissionConditions.ts +37 -44
- package/src/dto/AeroflyMissionConditionsCloud.ts +19 -8
- package/src/dto/AeroflyMissionTargetPlane.ts +11 -5
- package/src/dto/AeroflyMissionsList.ts +23 -7
- package/src/index.test.ts +15 -16
- package/src/node/AeroflyConfigurationNode.ts +89 -0
- package/types/dto/AeroflyConfigFileSet.d.ts +1 -1
- 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 +7 -3
- package/types/dto/AeroflyLocalizedText.d.ts.map +1 -1
- package/types/dto/AeroflyMission.d.ts +27 -72
- package/types/dto/AeroflyMission.d.ts.map +1 -1
- package/types/dto/AeroflyMissionCheckpoint.d.ts +17 -43
- package/types/dto/AeroflyMissionCheckpoint.d.ts.map +1 -1
- package/types/dto/AeroflyMissionConditions.d.ts +16 -30
- package/types/dto/AeroflyMissionConditions.d.ts.map +1 -1
- package/types/dto/AeroflyMissionConditionsCloud.d.ts +9 -3
- package/types/dto/AeroflyMissionConditionsCloud.d.ts.map +1 -1
- package/types/dto/AeroflyMissionTargetPlane.d.ts +6 -1
- package/types/dto/AeroflyMissionTargetPlane.d.ts.map +1 -1
- package/types/dto/AeroflyMissionsList.d.ts +7 -1
- package/types/dto/AeroflyMissionsList.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.test.d.ts +1 -1
- package/types/node/AeroflyConfigurationNode.d.ts +14 -0
- package/types/node/AeroflyConfigurationNode.d.ts.map +1 -0
- package/dist/dto/AeroflyConfigFileSet.js +0 -43
- package/src/dto/AeroflyConfigFileSet.ts +0 -35
package/.editorconfig
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,56 +1,90 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
This changelog documents all notable changes to the Aerofly Custom Missions project. Each version entry includes a list of changes, with the most recent version at the top.
|
|
4
|
+
|
|
5
|
+
## 1.3.0
|
|
6
|
+
|
|
7
|
+
- Changed TMC code generation with nodes
|
|
8
|
+
|
|
3
9
|
## 1.2.3
|
|
4
10
|
|
|
5
|
-
- Internal restructuring
|
|
11
|
+
- Internal restructuring of mission generation logic
|
|
12
|
+
- Optimized waypoint handling and validation
|
|
13
|
+
- Improved error handling for mission parsing
|
|
6
14
|
|
|
7
15
|
## 1.2.2
|
|
8
16
|
|
|
9
|
-
- Added altitude constraint property
|
|
10
|
-
- Improved handling of cloud layers
|
|
17
|
+
- Added altitude constraint property for waypoints
|
|
18
|
+
- Improved handling of cloud layers with better validation
|
|
11
19
|
|
|
12
20
|
## 1.2.1
|
|
13
21
|
|
|
14
|
-
- Changed handling of checkpoints
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
22
|
+
- Changed handling of checkpoints to support missions without checkpoints
|
|
23
|
+
- Improved file generation for programmatic mission creation
|
|
24
|
+
- Added new properties:
|
|
25
|
+
- `is_scheduled` for mission scheduling
|
|
26
|
+
- `tutorial_name` for tutorial identification
|
|
27
|
+
- Enhanced cloud handling with better validation
|
|
28
|
+
- Improved handling of unset values with default fallbacks
|
|
29
|
+
- Added new flight settings:
|
|
30
|
+
- `cold_and_dark`
|
|
31
|
+
- `before_start`
|
|
32
|
+
- `pushback`
|
|
20
33
|
|
|
21
34
|
## 1.2.0
|
|
22
35
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
36
|
+
- Added new cloud level properties:
|
|
37
|
+
- `cirrus_cover` for high-altitude cloud coverage
|
|
38
|
+
- `cirrus_base` for cirrus cloud base altitude
|
|
39
|
+
- Added new waypoint property `fly_over` for precise waypoint navigation
|
|
40
|
+
- Added `finish` property to mark mission completion points
|
|
26
41
|
|
|
27
42
|
## 1.1.1
|
|
28
43
|
|
|
29
|
-
-
|
|
44
|
+
- Fixed styling issues in mission display
|
|
45
|
+
- Improved UI consistency across different mission types
|
|
46
|
+
- Enhanced error message formatting
|
|
30
47
|
|
|
31
48
|
## 1.1.0
|
|
32
49
|
|
|
33
|
-
- Added new mission properties
|
|
34
|
-
-
|
|
35
|
-
-
|
|
50
|
+
- Added new mission metadata properties:
|
|
51
|
+
- `tags` for mission categorization
|
|
52
|
+
- `isFeatured` for highlighting special missions
|
|
53
|
+
- `difficulty` for mission complexity rating
|
|
54
|
+
- `distance` for mission length in kilometers
|
|
55
|
+
- `duration` for estimated completion time
|
|
56
|
+
- Multi-language support for mission descriptions
|
|
57
|
+
- Added new flight settings:
|
|
58
|
+
- `winch_launch` for glider operations
|
|
59
|
+
- `aerotow` for towed aircraft operations
|
|
60
|
+
- Improved temperature property with better unit handling
|
|
36
61
|
|
|
37
62
|
## 1.0.4
|
|
38
63
|
|
|
39
|
-
- Added documentation for known issues
|
|
40
|
-
- Added
|
|
64
|
+
- Added comprehensive documentation for known issues and workarounds
|
|
65
|
+
- Added `AeroflyMissionConditions.temperature` property with Celsius support
|
|
66
|
+
- Improved error handling for weather conditions
|
|
41
67
|
|
|
42
68
|
## 1.0.3
|
|
43
69
|
|
|
44
|
-
-
|
|
70
|
+
- Enhanced API documentation with examples
|
|
71
|
+
- Added detailed parameter descriptions
|
|
72
|
+
- Improved code documentation
|
|
45
73
|
|
|
46
74
|
## 1.0.2
|
|
47
75
|
|
|
48
|
-
- Added
|
|
76
|
+
- Added shorthand properties for common mission parameters
|
|
77
|
+
- Improved property access methods
|
|
78
|
+
- Enhanced mission validation
|
|
49
79
|
|
|
50
80
|
## 1.0.1
|
|
51
81
|
|
|
52
|
-
-
|
|
82
|
+
- Added initial API documentation
|
|
83
|
+
- Improved code comments
|
|
84
|
+
- Added basic usage examples
|
|
53
85
|
|
|
54
86
|
## 1.0.0
|
|
55
87
|
|
|
56
|
-
- Initial
|
|
88
|
+
- Initial release of Aerofly Custom Missions
|
|
89
|
+
- Basic mission creation and editing functionality
|
|
90
|
+
- Support for essential mission parameters
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
2
2
|
/**
|
|
3
3
|
* @class
|
|
4
4
|
* A translation for the mission title and description.
|
|
@@ -27,14 +27,18 @@ export class AeroflyLocalizedText {
|
|
|
27
27
|
this.description = description;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* @
|
|
30
|
+
* @returns {AeroflyConfigurationNode} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
31
|
+
*/
|
|
32
|
+
getElement() {
|
|
33
|
+
return new AeroflyConfigurationNode("tmmission_definition_localized", "element")
|
|
34
|
+
.appendChild("string8u", "language", this.language)
|
|
35
|
+
.appendChild("string8", "title", this.title)
|
|
36
|
+
.appendChild("string8", "description", this.description);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
31
39
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
32
40
|
*/
|
|
33
|
-
toString(
|
|
34
|
-
return
|
|
35
|
-
.push("string8u", "language", this.language)
|
|
36
|
-
.push("string8", "title", this.title)
|
|
37
|
-
.push("string8", "description", this.description)
|
|
38
|
-
.toString();
|
|
41
|
+
toString() {
|
|
42
|
+
return this.getElement().toString();
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
2
2
|
import { AeroflyMissionConditions } from "./AeroflyMissionConditions.js";
|
|
3
3
|
export const feetPerMeter = 3.28084;
|
|
4
4
|
export const meterPerStatuteMile = 1609.344;
|
|
@@ -17,7 +17,7 @@ export class AeroflyMission {
|
|
|
17
17
|
* @param {string} [additionalAttributes.description] text, mission briefing, etc
|
|
18
18
|
* @param {AeroflyLocalizedText[]} [additionalAttributes.localizedTexts] translations for title and description
|
|
19
19
|
* @param {?string} [additionalAttributes.tutorialName] will create a link to a tutorial page at https://www.aerofly.com/aircraft-tutorials/
|
|
20
|
-
* @param {string[]} [additionalAttributes.tags]
|
|
20
|
+
* @param {string[]} [additionalAttributes.tags] free-text tags
|
|
21
21
|
* @param {?boolean} [additionalAttributes.isFeatured] makes this mission pop up in "Challenges"
|
|
22
22
|
* @param {?number} [additionalAttributes.difficulty] values between 0.00 and 2.00 have been encountered, but they seem to be without limit
|
|
23
23
|
* @param {"cold_and_dark"|"before_start"|"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"|"pushback"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
@@ -69,30 +69,27 @@ export class AeroflyMission {
|
|
|
69
69
|
this.conditions = conditions;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* @returns {
|
|
72
|
+
* @returns {AeroflyConfigurationNode[]} indexed checkpoints
|
|
73
73
|
*/
|
|
74
|
-
|
|
75
|
-
return this.checkpoints
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
})
|
|
79
|
-
.join("\n");
|
|
74
|
+
getCheckpointElements() {
|
|
75
|
+
return this.checkpoints.map((c, index) => {
|
|
76
|
+
return c.getElement(index);
|
|
77
|
+
});
|
|
80
78
|
}
|
|
81
79
|
/**
|
|
82
|
-
* @returns {
|
|
80
|
+
* @returns {AeroflyConfigurationNode[]} indexed checkpoints
|
|
83
81
|
*/
|
|
84
|
-
|
|
85
|
-
return this.localizedTexts
|
|
86
|
-
.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
getLocalizedTextElements() {
|
|
83
|
+
return this.localizedTexts.map((c, index) => {
|
|
84
|
+
const el = c.getElement();
|
|
85
|
+
el.value = String(index);
|
|
86
|
+
return el;
|
|
87
|
+
});
|
|
90
88
|
}
|
|
91
89
|
/**
|
|
92
|
-
* @
|
|
93
|
-
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
90
|
+
* @returns {AeroflyConfigurationNode} for this mission
|
|
94
91
|
*/
|
|
95
|
-
|
|
92
|
+
getElement() {
|
|
96
93
|
if (!this.origin.icao) {
|
|
97
94
|
const firstCheckpoint = this.checkpoints[0];
|
|
98
95
|
this.origin = {
|
|
@@ -113,59 +110,64 @@ export class AeroflyMission {
|
|
|
113
110
|
alt: lastCheckpoint.altitude,
|
|
114
111
|
};
|
|
115
112
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
const element = new AeroflyConfigurationNode("tmmission_definition", "mission");
|
|
114
|
+
element.appendChild("string8", "title", this.title);
|
|
115
|
+
element.appendChild("string8", "description", this.description);
|
|
119
116
|
if (this.tutorialName !== null) {
|
|
120
|
-
|
|
117
|
+
element.appendChild("string8", "tutorial_name", this.tutorialName, `Opens https://www.aerofly.com/aircraft-tutorials/${this.tutorialName}`);
|
|
121
118
|
}
|
|
122
119
|
if (this.localizedTexts.length > 0) {
|
|
123
|
-
|
|
124
|
-
.pushRaw(this.getLocalizedTextsString())
|
|
125
|
-
.toString());
|
|
120
|
+
element.append(new AeroflyConfigurationNode("list_tmmission_definition_localized", "localized_text").append(...this.getLocalizedTextElements()));
|
|
126
121
|
}
|
|
127
122
|
if (this.tags.length > 0) {
|
|
128
|
-
|
|
123
|
+
element.appendChild("string8u", "tags", this.tags);
|
|
129
124
|
}
|
|
130
125
|
if (this.difficulty !== null) {
|
|
131
|
-
|
|
126
|
+
element.appendChild("float64", "difficulty", this.difficulty);
|
|
132
127
|
}
|
|
133
128
|
if (this.isFeatured !== null) {
|
|
134
|
-
|
|
129
|
+
element.appendChild("bool", "is_featured", this.isFeatured);
|
|
135
130
|
}
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
element.appendChild("string8", "flight_setting", this.flightSetting);
|
|
132
|
+
element.appendChild("string8u", "aircraft_name", this.aircraft.name);
|
|
138
133
|
/*if (this.aircraft.livery) {
|
|
139
|
-
|
|
134
|
+
mission.createChild("string8", "aircraft_livery", this.aircraft.livery);
|
|
140
135
|
}*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
136
|
+
element.appendChild("stringt8c", "aircraft_icao", this.aircraft.icao);
|
|
137
|
+
element.appendChild("stringt8c", "callsign", this.callsign);
|
|
138
|
+
element.appendChild("stringt8c", "origin_icao", this.origin.icao);
|
|
139
|
+
element.appendChild("tmvector2d", "origin_lon_lat", [this.origin.longitude, this.origin.latitude]);
|
|
140
|
+
element.appendChild("float64", "origin_alt", this.origin.alt, `${Math.ceil(this.origin.alt * feetPerMeter)} ft MSL`);
|
|
141
|
+
element.appendChild("float64", "origin_dir", this.origin.dir);
|
|
142
|
+
element.appendChild("stringt8c", "destination_icao", this.destination.icao);
|
|
143
|
+
element.appendChild("tmvector2d", "destination_lon_lat", [
|
|
144
|
+
this.destination.longitude,
|
|
145
|
+
this.destination.latitude,
|
|
146
|
+
]);
|
|
147
|
+
element.appendChild("float64", "destination_alt", this.destination.alt, `${Math.ceil(this.destination.alt * feetPerMeter)} ft MSL`);
|
|
148
|
+
element.appendChild("float64", "destination_dir", this.destination.dir);
|
|
151
149
|
if (this.distance !== null) {
|
|
152
|
-
|
|
150
|
+
element.appendChild("float64", "distance", this.distance, `${Math.round(this.distance / 1000)} km`);
|
|
153
151
|
}
|
|
154
152
|
if (this.duration !== null) {
|
|
155
|
-
|
|
153
|
+
element.appendChild("float64", "duration", this.duration, `${Math.round(this.duration / 60)} min`);
|
|
156
154
|
}
|
|
157
155
|
if (this.isScheduled !== null) {
|
|
158
|
-
|
|
156
|
+
element.appendChild("bool", "is_scheduled", this.isScheduled);
|
|
159
157
|
}
|
|
160
158
|
if (this.finish !== null) {
|
|
161
|
-
|
|
159
|
+
element.append(this.finish.getElement());
|
|
162
160
|
}
|
|
163
|
-
|
|
161
|
+
element.append(this.conditions.getElement());
|
|
164
162
|
if (this.checkpoints.length > 0) {
|
|
165
|
-
|
|
166
|
-
.pushRaw(this.getCheckpointsString())
|
|
167
|
-
.toString());
|
|
163
|
+
element.append(new AeroflyConfigurationNode("list_tmmission_checkpoint", "checkpoints").append(...this.getCheckpointElements()));
|
|
168
164
|
}
|
|
169
|
-
return
|
|
165
|
+
return element;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
169
|
+
*/
|
|
170
|
+
toString() {
|
|
171
|
+
return this.getElement().toString();
|
|
170
172
|
}
|
|
171
173
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
2
2
|
import { feetPerMeter } from "./AeroflyMission.js";
|
|
3
3
|
/**
|
|
4
4
|
* @class
|
|
@@ -34,7 +34,7 @@ export class AeroflyMissionCheckpoint {
|
|
|
34
34
|
* @param {?number} [additionalAttributes.frequency] of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
35
35
|
* @param {?boolean} [additionalAttributes.flyOver] if waypoint is meant to be flown over
|
|
36
36
|
*/
|
|
37
|
-
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet =
|
|
37
|
+
constructor(name, type, longitude, latitude, { altitude = 0, altitude_feet = 0, altitudeConstraint = null, direction = null, slope = null, length = null, length_feet = 0, frequency = null, flyOver = null, } = {}) {
|
|
38
38
|
this.type = type;
|
|
39
39
|
this.name = name;
|
|
40
40
|
this.longitude = longitude;
|
|
@@ -54,7 +54,7 @@ export class AeroflyMissionCheckpoint {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* @param {number} altitude_feet
|
|
57
|
+
* @param {number} altitude_feet in feet
|
|
58
58
|
*/
|
|
59
59
|
set altitude_feet(altitude_feet) {
|
|
60
60
|
this.altitude = altitude_feet / feetPerMeter;
|
|
@@ -66,7 +66,7 @@ export class AeroflyMissionCheckpoint {
|
|
|
66
66
|
return this.altitude * feetPerMeter;
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
* @param {number} length_feet
|
|
69
|
+
* @param {number} length_feet in feet
|
|
70
70
|
*/
|
|
71
71
|
set length_feet(length_feet) {
|
|
72
72
|
this.length = length_feet / feetPerMeter;
|
|
@@ -78,7 +78,7 @@ export class AeroflyMissionCheckpoint {
|
|
|
78
78
|
return (this.length ?? 0) * feetPerMeter;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
|
-
* @returns {string}
|
|
81
|
+
* @returns {string} with MHz / kHz attached
|
|
82
82
|
*/
|
|
83
83
|
get frequency_string() {
|
|
84
84
|
if (!this.frequency) {
|
|
@@ -93,29 +93,35 @@ export class AeroflyMissionCheckpoint {
|
|
|
93
93
|
return String(this.frequency) + " Hz";
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
|
-
* @param {number} index
|
|
97
|
-
* @returns {
|
|
96
|
+
* @param {number} index default: 0
|
|
97
|
+
* @returns {AeroflyConfigurationNode} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
98
98
|
*/
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
.
|
|
102
|
-
.
|
|
103
|
-
.
|
|
104
|
-
.
|
|
105
|
-
.
|
|
106
|
-
.
|
|
99
|
+
getElement(index = 0) {
|
|
100
|
+
const element = new AeroflyConfigurationNode("tmmission_checkpoint", "element", String(index))
|
|
101
|
+
.appendChild("string8u", "type", this.type)
|
|
102
|
+
.appendChild("string8u", "name", this.name)
|
|
103
|
+
.appendChild("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
104
|
+
.appendChild("float64", "altitude", this.altitude, `${Math.ceil(this.altitude_feet)} ft`)
|
|
105
|
+
.appendChild("float64", "direction", this.direction ?? (index === 0 ? -1 : 0))
|
|
106
|
+
.appendChild("float64", "slope", this.slope ?? 0);
|
|
107
107
|
if (this.altitudeConstraint !== null) {
|
|
108
|
-
|
|
108
|
+
element.appendChild("bool", "alt_cst", this.altitudeConstraint);
|
|
109
109
|
}
|
|
110
110
|
if (this.length) {
|
|
111
|
-
|
|
111
|
+
element.appendChild("float64", "length", this.length ?? 0, `${Math.floor(this.length_feet)} ft`);
|
|
112
112
|
}
|
|
113
113
|
if (this.frequency) {
|
|
114
|
-
|
|
114
|
+
element.appendChild("float64", "frequency", this.frequency ?? 0, `${this.frequency_string}`);
|
|
115
115
|
}
|
|
116
116
|
if (this.flyOver !== null) {
|
|
117
|
-
|
|
117
|
+
element.appendChild("bool", "fly_over", this.flyOver);
|
|
118
118
|
}
|
|
119
|
-
return
|
|
119
|
+
return element;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
123
|
+
*/
|
|
124
|
+
toString() {
|
|
125
|
+
return this.getElement().toString();
|
|
120
126
|
}
|
|
121
127
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
2
2
|
import { meterPerStatuteMile } from "./AeroflyMission.js";
|
|
3
3
|
import { AeroflyMissionConditionsCloud } from "./AeroflyMissionConditionsCloud.js";
|
|
4
4
|
/**
|
|
@@ -26,7 +26,7 @@ export class AeroflyMissionConditions {
|
|
|
26
26
|
direction: 0,
|
|
27
27
|
speed: 0,
|
|
28
28
|
gusts: 0,
|
|
29
|
-
}, turbulenceStrength = 0, thermalStrength = 0, visibility =
|
|
29
|
+
}, turbulenceStrength = 0, thermalStrength = 0, visibility = 25000, visibility_sm = 0, temperature = 0, clouds = [], } = {}) {
|
|
30
30
|
/**
|
|
31
31
|
* @property {AeroflyMissionConditionsCloud[]} clouds for the whole flight
|
|
32
32
|
*/
|
|
@@ -87,36 +87,38 @@ export class AeroflyMissionConditions {
|
|
|
87
87
|
return Math.sqrt(this.thermalStrength) * 50 - 15;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
-
* @returns {
|
|
90
|
+
* @returns {AeroflyConfigurationNode[]} cloud elements
|
|
91
91
|
*/
|
|
92
|
-
|
|
92
|
+
getCloudElements() {
|
|
93
93
|
return this.clouds
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
})
|
|
97
|
-
.join("\n");
|
|
94
|
+
.slice(0, 2) // Aerofly FS4 supports max 2 cloud layers
|
|
95
|
+
.flatMap((c, index) => c.getElements(index));
|
|
98
96
|
}
|
|
99
97
|
/**
|
|
100
98
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
101
99
|
*/
|
|
102
|
-
|
|
100
|
+
getElement() {
|
|
103
101
|
if (this.clouds.length < 1) {
|
|
104
102
|
this.clouds = [new AeroflyMissionConditionsCloud(0, 0)];
|
|
105
103
|
}
|
|
106
|
-
return new
|
|
107
|
-
.
|
|
108
|
-
.
|
|
109
|
-
.
|
|
110
|
-
.
|
|
111
|
-
.
|
|
112
|
-
.
|
|
113
|
-
.
|
|
114
|
-
.
|
|
115
|
-
.
|
|
116
|
-
.
|
|
117
|
-
.
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
104
|
+
return new AeroflyConfigurationNode("tmmission_conditions", "conditions")
|
|
105
|
+
.append(new AeroflyConfigurationNode("tm_time_utc", "time")
|
|
106
|
+
.appendChild("int32", "time_year", this.time.getUTCFullYear())
|
|
107
|
+
.appendChild("int32", "time_month", this.time.getUTCMonth() + 1)
|
|
108
|
+
.appendChild("int32", "time_day", this.time.getUTCDate())
|
|
109
|
+
.appendChild("float64", "time_hours", this.time_hours, `${this.time_presentational} UTC`))
|
|
110
|
+
.appendChild("float64", "wind_direction", this.wind.direction)
|
|
111
|
+
.appendChild("float64", "wind_speed", this.wind.speed, "kts")
|
|
112
|
+
.appendChild("float64", "wind_gusts", this.wind.gusts, "kts")
|
|
113
|
+
.appendChild("float64", "turbulence_strength", this.turbulenceStrength)
|
|
114
|
+
.appendChild("float64", "thermal_strength", this.thermalStrength, `${this.temperature} °C`)
|
|
115
|
+
.appendChild("float64", "visibility", this.visibility, `${this.visibility_sm} SM`)
|
|
116
|
+
.append(...this.getCloudElements());
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
120
|
+
*/
|
|
121
|
+
toString() {
|
|
122
|
+
return this.getElement().toString();
|
|
121
123
|
}
|
|
122
124
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
1
2
|
import { feetPerMeter } from "./AeroflyMission.js";
|
|
2
3
|
/**
|
|
3
4
|
* @class
|
|
@@ -19,7 +20,7 @@ export class AeroflyMissionConditionsCloud {
|
|
|
19
20
|
/**
|
|
20
21
|
* @param {number} cover 0..1, percentage
|
|
21
22
|
* @param {number} base_feet altitude, but in feet AGL instead of meters AGL
|
|
22
|
-
* @returns {AeroflyMissionConditionsCloud}
|
|
23
|
+
* @returns {AeroflyMissionConditionsCloud} self
|
|
23
24
|
*/
|
|
24
25
|
static createInFeet(cover, base_feet) {
|
|
25
26
|
return new AeroflyMissionConditionsCloud(cover, base_feet / feetPerMeter);
|
|
@@ -55,10 +56,10 @@ export class AeroflyMissionConditionsCloud {
|
|
|
55
56
|
return "OVC";
|
|
56
57
|
}
|
|
57
58
|
/**
|
|
58
|
-
* @param {number} index if used in an array will
|
|
59
|
-
* @returns {
|
|
59
|
+
* @param {number} index if used in an array will set the array index
|
|
60
|
+
* @returns {AeroflyConfigurationNode[]} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
60
61
|
*/
|
|
61
|
-
|
|
62
|
+
getElements(index = 0) {
|
|
62
63
|
const getIndexString = (index) => {
|
|
63
64
|
switch (index) {
|
|
64
65
|
case 0:
|
|
@@ -72,9 +73,18 @@ export class AeroflyMissionConditionsCloud {
|
|
|
72
73
|
}
|
|
73
74
|
};
|
|
74
75
|
const indexString = getIndexString(index);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
return [
|
|
77
|
+
new AeroflyConfigurationNode("float64", `${indexString}_cover`, this.cover ?? 0, this.cover_code),
|
|
78
|
+
new AeroflyConfigurationNode("float64", `${indexString}_base`, this.base, `${this.base_feet} ft AGL`),
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @param {number} index if used in an array will set the array index
|
|
83
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
84
|
+
*/
|
|
85
|
+
toString(index = 0) {
|
|
86
|
+
return this.getElements()
|
|
87
|
+
.map((element) => element.toString(index))
|
|
88
|
+
.join("\n");
|
|
79
89
|
}
|
|
80
90
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
2
2
|
/**
|
|
3
3
|
* @class
|
|
4
4
|
* A target plane which the aircraft needs to cross.
|
|
@@ -21,10 +21,15 @@ export class AeroflyMissionTargetPlane {
|
|
|
21
21
|
this.dir = dir;
|
|
22
22
|
this.name = name;
|
|
23
23
|
}
|
|
24
|
+
getElement() {
|
|
25
|
+
return new AeroflyConfigurationNode("tmmission_target_plane", this.name)
|
|
26
|
+
.appendChild("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
27
|
+
.appendChild("float64", "direction", this.dir);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
31
|
+
*/
|
|
24
32
|
toString() {
|
|
25
|
-
return
|
|
26
|
-
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
27
|
-
.push("float64", "direction", this.dir)
|
|
28
|
-
.toString();
|
|
33
|
+
return this.getElement().toString();
|
|
29
34
|
}
|
|
30
35
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AeroflyConfigurationNode } from "../node/AeroflyConfigurationNode.js";
|
|
1
2
|
/**
|
|
2
3
|
* @class
|
|
3
4
|
* A list of flight plans.
|
|
@@ -13,16 +14,23 @@ export class AeroflyMissionsList {
|
|
|
13
14
|
constructor(missions = []) {
|
|
14
15
|
this.missions = missions;
|
|
15
16
|
}
|
|
17
|
+
getElement() {
|
|
18
|
+
return new AeroflyConfigurationNode("file", "").append(new AeroflyConfigurationNode("tmmissions_list", "").append(new AeroflyConfigurationNode("list_tmmission_definition", "missions").append(...this.missions.map((m) => {
|
|
19
|
+
const mission = m.getElement();
|
|
20
|
+
mission._comment = `End of ${mission.name}`;
|
|
21
|
+
return mission;
|
|
22
|
+
}))));
|
|
23
|
+
}
|
|
16
24
|
/**
|
|
17
25
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
18
26
|
*/
|
|
19
27
|
toString() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
return this.getElement().toString();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @returns {string} XML represenation of this mission list
|
|
32
|
+
*/
|
|
33
|
+
toXmlString() {
|
|
34
|
+
return this.getElement().toXmlString();
|
|
27
35
|
}
|
|
28
36
|
}
|