mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-04 08:06:26 +08:00
Revise fundamentals lessons and add frequency handoff
This commit is contained in:
@@ -12,90 +12,93 @@ function gradientArt(colors: string[]): string {
|
||||
const fundamentalsLessons = [
|
||||
{
|
||||
id: 'icao-alphabet',
|
||||
title: 'ICAO Alphabet & Numbers',
|
||||
desc: 'Spell letters and digits clearly',
|
||||
title: 'Decode ICAO Letters & Numbers',
|
||||
desc: 'Turn phonetic blocks into identifiers',
|
||||
keywords: ['Alphabet', 'Numbers', 'Basics'],
|
||||
hints: [
|
||||
'Spell each letter with its ICAO name (e.g. Delta, Lima, Hotel).',
|
||||
'Use ATC numbers: tree, fower, fife, niner.'
|
||||
'Convert the NATO letters and ATC numbers back into characters.',
|
||||
'Write the identifier exactly as you would enter it into the FMS.'
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
key: 'letters',
|
||||
label: 'Letters',
|
||||
expected: scenario => scenario.callsignNato,
|
||||
placeholder: 'Delta Lima Hotel',
|
||||
width: 'xl',
|
||||
threshold: 0.9
|
||||
},
|
||||
{
|
||||
key: 'digits',
|
||||
label: 'Numbers',
|
||||
expected: scenario => scenario.flightNumberWords,
|
||||
placeholder: 'one two three',
|
||||
width: 'lg',
|
||||
threshold: 0.88
|
||||
key: 'icao-code',
|
||||
label: 'Identifier',
|
||||
expected: scenario => scenario.phoneticCode,
|
||||
alternatives: scenario => {
|
||||
const spelled = scenario.phoneticCodeWords
|
||||
const upper = scenario.phoneticCode.toUpperCase()
|
||||
const lower = upper.toLowerCase()
|
||||
const spacedUpper = upper.split('').join(' ')
|
||||
const spacedLower = lower.split('').join(' ')
|
||||
return Array.from(
|
||||
new Set([
|
||||
upper,
|
||||
lower,
|
||||
spelled,
|
||||
spelled.toLowerCase(),
|
||||
spacedUpper,
|
||||
spacedLower
|
||||
])
|
||||
)
|
||||
},
|
||||
placeholder: 'SWR59',
|
||||
width: 'lg'
|
||||
}
|
||||
],
|
||||
readback: [
|
||||
{ type: 'text', text: 'Call sign: ' },
|
||||
{ type: 'field', key: 'letters', width: 'lg' },
|
||||
{ type: 'text', text: ' · ' },
|
||||
{ type: 'field', key: 'digits', width: 'md' }
|
||||
{ type: 'text', text: 'Identifier ' },
|
||||
{ type: 'field', key: 'icao-code', width: 'lg' }
|
||||
],
|
||||
defaultFrequency: 'DEL',
|
||||
phrase: scenario => `${scenario.callsignNato} ${scenario.flightNumberWords}`,
|
||||
phrase: scenario => scenario.phoneticCodeWords,
|
||||
info: scenario => [
|
||||
`Callsign: ${scenario.callsign}`,
|
||||
`Radio call: ${scenario.radioCall}`,
|
||||
`ICAO spelling: ${scenario.callsignNato}`,
|
||||
`Flight number spoken: ${scenario.flightNumberWords}`
|
||||
`Heard: ${scenario.phoneticCodeWords}`,
|
||||
`Identifier: ${scenario.phoneticCode}`
|
||||
],
|
||||
generate: createBaseScenario
|
||||
},
|
||||
{
|
||||
id: 'radio-call',
|
||||
title: 'Radio Call Sign',
|
||||
desc: 'Say the spoken and ICAO call sign',
|
||||
desc: 'Say the spoken or ICAO call sign confidently',
|
||||
keywords: ['Basics', 'Callsign'],
|
||||
hints: [
|
||||
'Use the airline telephony plus digits for the spoken version.',
|
||||
'ICAO format keeps the three-letter code with the numbers.'
|
||||
'Use the airline telephony plus digits when talking to ATC.',
|
||||
'Readbacks can use either the spoken or ICAO format.'
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
key: 'radio-call-spoken',
|
||||
label: 'Spoken Call Sign',
|
||||
key: 'radio-call',
|
||||
label: 'Call sign',
|
||||
expected: scenario => scenario.radioCall,
|
||||
alternatives: scenario => [
|
||||
scenario.radioCall,
|
||||
`${scenario.airlineCall} ${scenario.flightNumber}`,
|
||||
`${scenario.airlineCall} ${scenario.flightNumberWords}`
|
||||
],
|
||||
width: 'lg'
|
||||
},
|
||||
{
|
||||
key: 'radio-call-icao',
|
||||
label: 'ICAO Identifier',
|
||||
expected: scenario => scenario.callsign,
|
||||
alternatives: scenario => [
|
||||
scenario.callsign,
|
||||
`${scenario.airlineCode}${scenario.flightNumber}`
|
||||
],
|
||||
width: 'md'
|
||||
alternatives: scenario => {
|
||||
const variants = new Set<string>()
|
||||
const add = (value?: string) => {
|
||||
if (!value) return
|
||||
variants.add(value)
|
||||
variants.add(value.toLowerCase())
|
||||
}
|
||||
add(scenario.radioCall)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumber}`)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumberWords}`)
|
||||
add(scenario.callsign)
|
||||
add(`${scenario.airlineCode} ${scenario.flightNumber}`)
|
||||
add(`${scenario.callsignNato} ${scenario.flightNumberWords}`)
|
||||
return Array.from(variants)
|
||||
},
|
||||
width: 'xl'
|
||||
}
|
||||
],
|
||||
readback: [
|
||||
{ type: 'text', text: 'Call sign ' },
|
||||
{ type: 'field', key: 'radio-call-spoken', width: 'lg' },
|
||||
{ type: 'text', text: ' · ICAO ' },
|
||||
{ type: 'field', key: 'radio-call-icao', width: 'md' }
|
||||
{ type: 'field', key: 'radio-call', width: 'xl' }
|
||||
],
|
||||
defaultFrequency: 'DEL',
|
||||
phrase: scenario => `${scenario.radioCall}`,
|
||||
info: scenario => [
|
||||
`Spoken call sign: ${scenario.radioCall}`,
|
||||
`ICAO identifier: ${scenario.callsign}`
|
||||
`Spoken: ${scenario.radioCall}`,
|
||||
`ICAO: ${scenario.callsign}`,
|
||||
`Phonetic: ${scenario.callsignNato} ${scenario.flightNumberWords}`
|
||||
],
|
||||
generate: createBaseScenario
|
||||
},
|
||||
@@ -105,8 +108,8 @@ const fundamentalsLessons = [
|
||||
desc: 'Extract the identifier and key data from the ATIS',
|
||||
keywords: ['ATIS', 'Weather'],
|
||||
hints: [
|
||||
'Remember the ATIS identifier as a single letter.',
|
||||
'Order: runway – wind – visibility – temperature – dew point – QNH.'
|
||||
'Remember the ATIS identifier as its NATO word (e.g. Information Yankee).',
|
||||
'Order: runway – wind – visibility – temperature – dew point – QNH; copy the numbers as digits.'
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
@@ -116,7 +119,12 @@ const fundamentalsLessons = [
|
||||
alternatives: scenario => [
|
||||
scenario.atisCode,
|
||||
scenario.atisCode.toLowerCase(),
|
||||
`Information ${scenario.atisCode}`
|
||||
scenario.atisCodeWord,
|
||||
scenario.atisCodeWord.toLowerCase(),
|
||||
`Information ${scenario.atisCode}`,
|
||||
`information ${scenario.atisCode.toLowerCase()}`,
|
||||
`Information ${scenario.atisCodeWord}`,
|
||||
`information ${scenario.atisCodeWord.toLowerCase()}`
|
||||
],
|
||||
placeholder: 'Letter',
|
||||
width: 'xs',
|
||||
@@ -143,22 +151,93 @@ const fundamentalsLessons = [
|
||||
{
|
||||
key: 'atis-visibility',
|
||||
label: 'Visibility',
|
||||
expected: scenario => scenario.atisSummary.visibility,
|
||||
alternatives: scenario => [scenario.visibility, scenario.visibilityWords],
|
||||
expected: scenario => scenario.visibility,
|
||||
alternatives: scenario => {
|
||||
const values = new Set<string>()
|
||||
const add = (value?: string) => {
|
||||
if (!value) return
|
||||
values.add(value)
|
||||
values.add(value.toLowerCase())
|
||||
}
|
||||
add(scenario.visibility)
|
||||
add(scenario.atisSummary.visibility)
|
||||
add(scenario.visibilityWords)
|
||||
const numeric = Number(scenario.visibility)
|
||||
if (!Number.isNaN(numeric)) {
|
||||
if (numeric >= 1000) {
|
||||
const precise = (numeric / 1000).toFixed(1).replace(/\.0$/, '')
|
||||
add(precise)
|
||||
add(`${precise}km`)
|
||||
add(`${precise} km`)
|
||||
}
|
||||
if (numeric >= 1000) {
|
||||
const rounded = Math.round(numeric / 1000)
|
||||
add(rounded.toString())
|
||||
add(`${rounded}km`)
|
||||
add(`${rounded} km`)
|
||||
}
|
||||
}
|
||||
if (scenario.visibility === '9999') {
|
||||
add('10')
|
||||
add('10km')
|
||||
add('10 km')
|
||||
}
|
||||
return Array.from(values)
|
||||
},
|
||||
width: 'sm'
|
||||
},
|
||||
{
|
||||
key: 'atis-temp',
|
||||
label: 'Temperature',
|
||||
expected: scenario => scenario.atisSummary.temperature,
|
||||
alternatives: scenario => [scenario.temperatureWords],
|
||||
expected: scenario => scenario.temperature.toString(),
|
||||
alternatives: scenario => {
|
||||
const value = scenario.temperature
|
||||
const base = value.toString()
|
||||
const plus = value > 0 ? `+${base}` : base
|
||||
const c = `${base}°C`
|
||||
const cSpaced = `${base} °C`
|
||||
const shortC = value > 0 ? `${plus}C` : `${base}C`
|
||||
const options = new Set<string>([
|
||||
base,
|
||||
plus,
|
||||
c,
|
||||
cSpaced,
|
||||
shortC,
|
||||
scenario.temperatureWords,
|
||||
formatTemp(value)
|
||||
])
|
||||
options.add(`${plus}°C`)
|
||||
options.add(`${plus} °C`)
|
||||
options.add(scenario.temperatureWords.toLowerCase())
|
||||
return Array.from(options)
|
||||
},
|
||||
width: 'sm'
|
||||
},
|
||||
{
|
||||
key: 'atis-dew',
|
||||
label: 'Dew point',
|
||||
expected: scenario => scenario.atisSummary.dewpoint,
|
||||
alternatives: scenario => [scenario.dewpointWords],
|
||||
expected: scenario => scenario.dewpoint.toString(),
|
||||
alternatives: scenario => {
|
||||
const value = scenario.dewpoint
|
||||
const base = value.toString()
|
||||
const plus = value > 0 ? `+${base}` : base
|
||||
const c = `${base}°C`
|
||||
const cSpaced = `${base} °C`
|
||||
const shortC = value > 0 ? `${plus}C` : `${base}C`
|
||||
const options = new Set<string>([
|
||||
base,
|
||||
plus,
|
||||
c,
|
||||
cSpaced,
|
||||
shortC,
|
||||
scenario.dewpointWords,
|
||||
formatTemp(value)
|
||||
])
|
||||
options.add(`${plus}°C`)
|
||||
options.add(`${plus} °C`)
|
||||
options.add(scenario.dewpointWords.toLowerCase())
|
||||
return Array.from(options)
|
||||
},
|
||||
width: 'sm'
|
||||
},
|
||||
{
|
||||
@@ -188,8 +267,8 @@ const fundamentalsLessons = [
|
||||
defaultFrequency: 'ATIS',
|
||||
phrase: scenario => scenario.atisText,
|
||||
info: () => [
|
||||
'Note the identifier, runway, wind, visibility, temperature, dew point, and QNH.',
|
||||
'Visibility: four digits or 9999 for ≥10 km; QNH as a four-digit value.'
|
||||
'Note the identifier (NATO word), runway, wind, visibility, temperature, dew point, and QNH.',
|
||||
'Temperatures and dew point can be recorded as plain numbers; visibility may be metres or kilometres.'
|
||||
],
|
||||
generate: createBaseScenario
|
||||
},
|
||||
@@ -261,22 +340,32 @@ const fundamentalsLessons = [
|
||||
{
|
||||
id: 'radio-check',
|
||||
title: 'Radio Check',
|
||||
desc: 'Report readability',
|
||||
desc: 'Acknowledge a requested radio check',
|
||||
keywords: ['Ground', 'Comms'],
|
||||
hints: [
|
||||
'Reply with "Readability" followed by the number.',
|
||||
'Always finish the check with your call sign.'
|
||||
'Reply with "Readability" plus the number you hear.',
|
||||
'Finish with your call sign; no need to repeat the frequency.'
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
key: 'rc-callsign',
|
||||
label: 'Callsign',
|
||||
expected: scenario => scenario.radioCall,
|
||||
alternatives: scenario => [
|
||||
scenario.radioCall,
|
||||
`${scenario.airlineCall} ${scenario.flightNumber}`,
|
||||
scenario.callsign
|
||||
],
|
||||
alternatives: scenario => {
|
||||
const variants = new Set<string>()
|
||||
const add = (value?: string) => {
|
||||
if (!value) return
|
||||
variants.add(value)
|
||||
variants.add(value.toLowerCase())
|
||||
}
|
||||
add(scenario.radioCall)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumber}`)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumberWords}`)
|
||||
add(scenario.callsign)
|
||||
add(`${scenario.airlineCode} ${scenario.flightNumber}`)
|
||||
add(`${scenario.callsignNato} ${scenario.flightNumberWords}`)
|
||||
return Array.from(variants)
|
||||
},
|
||||
placeholder: 'Lufthansa one two three',
|
||||
width: 'lg'
|
||||
},
|
||||
@@ -284,22 +373,106 @@ const fundamentalsLessons = [
|
||||
key: 'rc-readability',
|
||||
label: 'Readability',
|
||||
expected: scenario => scenario.readabilityWord,
|
||||
alternatives: scenario => [scenario.readability.toString(), scenario.readabilityWord],
|
||||
alternatives: scenario => [
|
||||
scenario.readability.toString(),
|
||||
scenario.readabilityWord,
|
||||
scenario.readabilityWord.toLowerCase()
|
||||
],
|
||||
placeholder: 'five',
|
||||
width: 'sm'
|
||||
}
|
||||
],
|
||||
readback: [
|
||||
{ type: 'text', text: 'This is ' },
|
||||
{ type: 'field', key: 'rc-callsign', width: 'lg' },
|
||||
{ type: 'text', text: ', readability ' },
|
||||
{ type: 'field', key: 'rc-readability', width: 'sm' }
|
||||
{ type: 'text', text: 'Readability ' },
|
||||
{ type: 'field', key: 'rc-readability', width: 'sm' },
|
||||
{ type: 'text', text: ', ' },
|
||||
{ type: 'field', key: 'rc-callsign', width: 'lg' }
|
||||
],
|
||||
defaultFrequency: 'GND',
|
||||
phrase: scenario => `${scenario.airport.name} Ground, ${scenario.radioCall}, radio check on ${scenario.groundFreq}.`,
|
||||
phrase: scenario => `${scenario.radioCall}, ${scenario.airport.name} Ground, say radio check on ${scenario.groundFreq}.`,
|
||||
info: scenario => [
|
||||
`Frequency: ${scenario.groundFreq} (${scenario.frequencyWords.GND})`,
|
||||
`Expected response: Readability ${scenario.readability} (${scenario.readabilityWord})`
|
||||
`Request: ${scenario.airport.name} Ground on ${scenario.groundFreq} (${scenario.frequencyWords.GND})`,
|
||||
`Respond: Readability ${scenario.readability} (${scenario.readabilityWord}) with your call sign`
|
||||
],
|
||||
generate: createBaseScenario
|
||||
},
|
||||
{
|
||||
id: 'frequency-change',
|
||||
title: 'Frequency Change Readback',
|
||||
desc: 'Confirm a handoff instruction',
|
||||
keywords: ['Comms', 'Frequency'],
|
||||
hints: [
|
||||
'Repeat the station and frequency before your call sign.',
|
||||
'State the frequency as digits or with "decimal".'
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
key: 'freq-contact-frequency',
|
||||
label: 'Frequency',
|
||||
expected: scenario => scenario.handoff.frequency,
|
||||
alternatives: scenario => {
|
||||
const freq = scenario.handoff.frequency
|
||||
const trimmed = freq.replace(/\.?0+$/, '')
|
||||
const comma = freq.replace('.', ',')
|
||||
const trimmedComma = trimmed.replace('.', ',')
|
||||
const spaced = freq.replace('.', ' ')
|
||||
const trimmedSpaced = trimmed.replace('.', ' ')
|
||||
const words = scenario.handoff.frequencyWords
|
||||
const pointWords = words.replace('decimal', 'point')
|
||||
const compact = freq.replace('.', '')
|
||||
const trimmedCompact = trimmed.replace('.', '')
|
||||
const values = new Set<string>([
|
||||
freq,
|
||||
trimmed,
|
||||
comma,
|
||||
trimmedComma,
|
||||
spaced,
|
||||
trimmedSpaced,
|
||||
words,
|
||||
words.toLowerCase(),
|
||||
pointWords,
|
||||
pointWords.toLowerCase(),
|
||||
compact,
|
||||
trimmedCompact
|
||||
])
|
||||
return Array.from(values)
|
||||
},
|
||||
placeholder: '125.35',
|
||||
width: 'md'
|
||||
},
|
||||
{
|
||||
key: 'freq-contact-callsign',
|
||||
label: 'Callsign',
|
||||
expected: scenario => scenario.radioCall,
|
||||
alternatives: scenario => {
|
||||
const variants = new Set<string>()
|
||||
const add = (value?: string) => {
|
||||
if (!value) return
|
||||
variants.add(value)
|
||||
variants.add(value.toLowerCase())
|
||||
}
|
||||
add(scenario.radioCall)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumber}`)
|
||||
add(`${scenario.airlineCall} ${scenario.flightNumberWords}`)
|
||||
add(scenario.callsign)
|
||||
add(`${scenario.airlineCode} ${scenario.flightNumber}`)
|
||||
add(`${scenario.callsignNato} ${scenario.flightNumberWords}`)
|
||||
return Array.from(variants)
|
||||
},
|
||||
width: 'lg'
|
||||
}
|
||||
],
|
||||
readback: [
|
||||
{ type: 'text', text: scenario => `Contact ${scenario.handoff.facility} on ` },
|
||||
{ type: 'field', key: 'freq-contact-frequency', width: 'md' },
|
||||
{ type: 'text', text: ', ' },
|
||||
{ type: 'field', key: 'freq-contact-callsign', width: 'lg' }
|
||||
],
|
||||
defaultFrequency: 'TWR',
|
||||
phrase: scenario => `${scenario.radioCall}, contact ${scenario.handoff.facility} on ${scenario.handoff.frequencyWords}.`,
|
||||
info: scenario => [
|
||||
`Station: ${scenario.handoff.facility}`,
|
||||
`Frequency: ${scenario.handoff.frequency} (${scenario.handoff.frequencyWords})`
|
||||
],
|
||||
generate: createBaseScenario
|
||||
}
|
||||
|
||||
@@ -190,6 +190,30 @@ function randomFlightNumber(): string {
|
||||
return value
|
||||
}
|
||||
|
||||
const phoneticCodeCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.split('')
|
||||
|
||||
function randomPhoneticCode(length = 5): string {
|
||||
let value = ''
|
||||
for (let i = 0; i < length; i++) {
|
||||
value += choice(phoneticCodeCharacters)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
function codeToPhonetic(value: string): string {
|
||||
return value
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.map(char => {
|
||||
if (natoMap[char]) return natoMap[char]
|
||||
if (atcNumberWords[char]) return atcNumberWords[char]
|
||||
return char
|
||||
})
|
||||
.join(' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function generateSquawk(): string {
|
||||
let code = ''
|
||||
for (let i = 0; i < 4; i++) {
|
||||
@@ -301,6 +325,8 @@ export function createBaseScenario(): Scenario {
|
||||
const airline = choice(airlines)
|
||||
const flightNumber = randomFlightNumber()
|
||||
const callsign = `${airline.code}${flightNumber}`
|
||||
const phoneticCode = randomPhoneticCode()
|
||||
const phoneticCodeWords = codeToPhonetic(phoneticCode)
|
||||
const runway = choice(airport.runways)
|
||||
const stand = choice(airport.stands)
|
||||
const taxiRoute = choice(airport.taxi)
|
||||
@@ -325,6 +351,7 @@ export function createBaseScenario(): Scenario {
|
||||
const temperature = randInt(-3, 28)
|
||||
const dewpoint = Math.max(temperature - randInt(2, 6), -10)
|
||||
const atisCode = choice(atisLetters)
|
||||
const atisCodeWord = lettersToNato(atisCode)
|
||||
const remarks = choice(['NOSIG', 'BECMG 4000', 'TEMPO -SHRA'])
|
||||
const arrivalQnh = randInt(980, 1035)
|
||||
const arrivalWindDirection = randInt(0, 35) * 10
|
||||
@@ -384,9 +411,15 @@ export function createBaseScenario(): Scenario {
|
||||
return acc
|
||||
}, {} as Record<FrequencyType, string>)
|
||||
|
||||
const contactFrequencies = frequencies.filter(freq => freq.type !== 'ATIS')
|
||||
const handoffTarget = choice(contactFrequencies)
|
||||
const handoffCity = handoffTarget.type === 'CTR' ? destination.city : airport.city
|
||||
const handoffFacility = `${handoffCity} ${handoffTarget.label}`.trim()
|
||||
const handoffFrequencyWords = frequencyWords[handoffTarget.type]
|
||||
|
||||
const readability = choice(readabilityScale)
|
||||
|
||||
const atisText = `${airport.name} information ${atisCode}, time ${timestamp.slice(2, 4)}${timestamp.slice(4, 6)}, runway ${
|
||||
const atisText = `${airport.name} information ${atisCodeWord}, time ${timestamp.slice(2, 4)}${timestamp.slice(4, 6)}, runway ${
|
||||
runwayToWords(runway)
|
||||
} in use, wind ${windToWords(windDirection, windSpeed)}, visibility ${visibilityToWords(visibility)}, temperature ${
|
||||
temperatureToWords(temperature)
|
||||
@@ -397,6 +430,8 @@ export function createBaseScenario(): Scenario {
|
||||
airlineCode: airline.code,
|
||||
airlineCall: airline.call,
|
||||
radioCall: `${airline.call} ${digitsToWords(flightNumber)}`,
|
||||
phoneticCode,
|
||||
phoneticCodeWords,
|
||||
callsignNato: lettersToNato(airline.code),
|
||||
flightNumber,
|
||||
flightNumberWords: digitsToWords(flightNumber),
|
||||
@@ -430,6 +465,7 @@ export function createBaseScenario(): Scenario {
|
||||
qnh,
|
||||
qnhWords: qnhToWords(qnh),
|
||||
atisCode,
|
||||
atisCodeWord,
|
||||
atisText,
|
||||
atisSummary: {
|
||||
runway,
|
||||
@@ -470,6 +506,13 @@ export function createBaseScenario(): Scenario {
|
||||
readabilityPhrase: `Readability ${readability.word}`,
|
||||
frequencies,
|
||||
frequencyWords,
|
||||
handoff: {
|
||||
type: handoffTarget.type,
|
||||
facility: handoffFacility,
|
||||
short: handoffTarget.label,
|
||||
frequency: handoffTarget.value,
|
||||
frequencyWords: handoffFrequencyWords
|
||||
},
|
||||
atisFreq: airport.freqs.atis,
|
||||
deliveryFreq: airport.freqs.delivery,
|
||||
groundFreq: airport.freqs.ground,
|
||||
|
||||
@@ -46,6 +46,8 @@ export type Scenario = {
|
||||
airlineCode: string
|
||||
airlineCall: string
|
||||
radioCall: string
|
||||
phoneticCode: string
|
||||
phoneticCodeWords: string
|
||||
callsignNato: string
|
||||
flightNumber: string
|
||||
flightNumberWords: string
|
||||
@@ -79,6 +81,7 @@ export type Scenario = {
|
||||
qnh: number
|
||||
qnhWords: string
|
||||
atisCode: string
|
||||
atisCodeWord: string
|
||||
atisText: string
|
||||
atisSummary: {
|
||||
runway: string
|
||||
@@ -119,6 +122,13 @@ export type Scenario = {
|
||||
readabilityPhrase: string
|
||||
frequencies: Frequency[]
|
||||
frequencyWords: Record<FrequencyType, string>
|
||||
handoff: {
|
||||
type: FrequencyType
|
||||
facility: string
|
||||
short: string
|
||||
frequency: string
|
||||
frequencyWords: string
|
||||
}
|
||||
atisFreq: string
|
||||
deliveryFreq: string
|
||||
groundFreq: string
|
||||
|
||||
Reference in New Issue
Block a user