feat(pm): VFR registration callsigns and pronunciation (#28)

- VFR scenarios get a German D-registration (e.g. D-EKLM) and its
  abbreviated form (callsign_short, D-EKLM -> D-LM) instead of the airline
  callsign; the pilot's first call uses the full registration, ATC uses the
  short form thereafter.
- radioSpeech: spell aircraft registrations phonetically for TTS
  ("D-EKLM" -> "Delta Echo Kilo Lima Mike", "D-LM" -> "Delta Lima Mike").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
leubeem
2026-06-29 10:17:52 +02:00
parent 8aeab4716a
commit 863d74e3aa
2 changed files with 22 additions and 0 deletions

View File

@@ -3538,6 +3538,21 @@ const startMonitoring = async (flightPlan: any, scenario: Scenario) => {
approach_freq: v.approach_freq || '119.000',
handoff_freq: v.handoff_freq || '131.150',
}
// VFR flights identify by aircraft registration, not an airline callsign.
// Assign a German D-registration and its abbreviated form (D-EMIL -> D-IL,
// first letter + last two), which ATC uses after the first call. Mirror it
// into the local engine vars and HUD so the display matches the radio.
if (scenario.startFlow.startsWith('vfr')) {
const pool = ['D-EMIL', 'D-EKLM', 'D-ENNY', 'D-ELLA', 'D-EOMT', 'D-ELPC', 'D-EMTO', 'D-EBRA']
const reg = pool[Math.floor(Math.random() * pool.length)]
const short = `D-${reg.replace(/^D-/, '').slice(-2)}`
backendVariables.callsign = reg
backendVariables.callsign_short = short
patchVariables({ callsign: reg, callsign_short: short })
} else {
backendVariables.callsign_short = backendVariables.callsign
}
pmLog.info('backend variables payload:', backendVariables)
// 4. Create a backend session with the flight-plan-derived variables

View File

@@ -741,6 +741,13 @@ export function normalizeRadioPhrase(text: string, options: NormalizeRadioOption
out = out.replace(/\b(wind\s+)(\d{3})\/(\d{2,3})(?:KT)?\b/gi, (_m, prefix: string, dir: string, spd: string) =>
`${prefix}${spellIcaoDigits(dir)} degrees, ${spellIcaoDigits(spd)} knots`);
// Aircraft registration callsign: "D-EMIL" → "Delta Echo Mike India Lima",
// abbreviated "D-IL" → "Delta India Lima". Single prefix letter, hyphen, then
// 15 registration letters, each spelled phonetically. Runs before airport/
// callsign expansion so the registration body isn't read as an ICAO code.
out = out.replace(/\b([A-Z])-([A-Z]{1,5})\b/g, (_m, prefix: string, body: string) =>
spellIcaoLetters(prefix + body));
if (opts.sidSuffixIcao) {
out = out.replace(/\b([A-Z]{4,6})\s*(\d)\s*([A-Z])\b/g, (_match, prefix: string, digit: string, letter: string) => {
return sidSuffixSpeak(prefix, digit, letter);