@fboes/aerofly-custom-missions
Version:
Builder for Aerofly FS4 Custom Missions Files
136 lines (121 loc) • 4.36 kB
text/typescript
import { AeroflyConfigurationNode, AeroflyConfigurationNodeComment } from "../node/AeroflyConfigurationNode.js";
import { feetPerMeter } from "./AeroflyMission.js";
/**
* Cloud coverage codes
*/
export type AeroflyMissionConditionsCloudCoverCode = "CLR" | "FEW" | "SCT" | "BKN" | "OVC";
/**
* @class
* A cloud layer for the current flight plan's weather data
*
* The purpose of this class is to collect data needed for Aerofly FS4's
* `custom_missions_user.tmc` flight plan file format, and export the structure
* for this file via the `toString()` method.
*/
export class AeroflyMissionConditionsCloud {
/**
* @property {number} cover normalized value [0,1]
*/
cover: number;
/**
* @property {number} base altitude in meters AGL
*/
base: number;
/**
* @param {number} cover normalized value [0,1]
* @param {number} base altitude in meters AGL
*/
constructor(cover: number, base: number) {
this.cover = cover;
this.base = base;
}
/**
* @param {number} cover normalized value [0,1]
* @param {number} base_feet altitude, but in feet AGL instead of meters AGL
* @returns {AeroflyMissionConditionsCloud} self
*/
static createInFeet(cover: number, base_feet: number): AeroflyMissionConditionsCloud {
return new AeroflyMissionConditionsCloud(cover, base_feet / feetPerMeter);
}
/**
* @param {number} base_feet `this.base` in feet instead of meters
*/
set base_feet(base_feet: number) {
this.base = base_feet / feetPerMeter;
}
/**
* @returns {number} `this.base` in feet instead of meters
*/
get base_feet(): number {
return this.base * feetPerMeter;
}
/**
* @returns {string} Cloud coverage as text representation like "OVC" for `this.cover`
*/
get cover_code(): AeroflyMissionConditionsCloudCoverCode {
if (this.cover < 1 / 8) {
return "CLR";
} else if (this.cover <= 2 / 8) {
return "FEW";
} else if (this.cover <= 4 / 8) {
return "SCT";
} else if (this.cover <= 7 / 8) {
return "BKN";
}
return "OVC";
}
/**
* @param {number} index if used in an array will set the array index
* @returns {AeroflyConfigurationNode[]} to use in Aerofly FS4's `custom_missions_user.tmc`
*/
getElements(index: number = 0): AeroflyConfigurationNode[] {
const getIndexString = (index: number) => {
switch (index) {
case 0:
return "cloud";
case 1:
return "cirrus";
case 2:
return "cumulus_mediocris";
default:
return "more_clouds";
}
};
const indexString = getIndexString(index);
return index <= 1
? [
new AeroflyConfigurationNode("float64", `${indexString}_cover`, this.cover ?? 0, this.cover_code),
new AeroflyConfigurationNode("float64", `${indexString}_base`, this.base, `${this.base_feet} ft AGL`),
]
: [
new AeroflyConfigurationNodeComment(
"float64",
`${indexString}_cover`,
this.cover ?? 0,
this.cover_code,
),
new AeroflyConfigurationNodeComment(
"float64",
`${indexString}_base`,
this.base,
`${this.base_feet} ft AGL`,
),
];
}
/**
* @param {number} index if used in an array will set the array index
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
*/
toString(index: number = 0): string {
return this.getElements()
.map((element) => element.toString(index))
.join("\n");
}
static fromJSON(json: unknown): AeroflyMissionConditionsCloud {
if (typeof json !== "object" || json === null) {
throw new Error("Invalid mission condition cloud data");
}
const data = json as Record<string, unknown>;
return new this(Number(data.cover ?? 0), Number(data.base ?? 0));
}
}