diff --git a/app/components/live-atc/cockpit/SettingsSheet.vue b/app/components/live-atc/cockpit/SettingsSheet.vue index d381e65..ed3c14e 100644 --- a/app/components/live-atc/cockpit/SettingsSheet.vue +++ b/app/components/live-atc/cockpit/SettingsSheet.vue @@ -21,6 +21,8 @@ const prerecEnabled = defineModel('prerecEnabled', { required: true }) const prerecSeconds = defineModel('prerecSeconds', { required: true }) const aiTrafficEnabled = defineModel('aiTrafficEnabled', { required: true }) const autoTuneEnabled = defineModel('autoTuneEnabled', { required: true }) +const forceRto = defineModel('forceRto', { required: true }) +const forceGoAround = defineModel('forceGoAround', { required: true }) /** * Shown while AI traffic is on. These are deliberate v1 boundaries from the @@ -170,6 +172,42 @@ const AI_TRAFFIC_LIMITS = [ + +
+
+

Special scenarios

+

+ Force a rare event on the next flight instead of waiting for it. Both + otherwise occur by chance, about once in five hundred flights. +

+
+ + + +

+ Applies when you start the next flight. A rejected take-off ends with + the aircraft stopped on the runway; a go-around sends you back to + Approach — neither continues to the stand. +

+
+
+

Voice input

diff --git a/app/composables/useLiveAtcSession.ts b/app/composables/useLiveAtcSession.ts index 0181a6c..dd44ff4 100644 --- a/app/composables/useLiveAtcSession.ts +++ b/app/composables/useLiveAtcSession.ts @@ -36,6 +36,13 @@ export interface LiveAtcSessionDeps { isRecording: Ref /** Settings toggle: dial in the new frequency automatically after a handoff. */ autoTuneEnabled: Ref + /** + * Special-scenario switches. Read once when the session is created, so + * toggling one mid-flight applies to the next flight — which is how an + * instructor sets one up without the pilot seeing it coming. + */ + forceRto: Ref + forceGoAround: Ref bridgeConnected: Ref bridgePosition: Ref<{ lat: number; lon: number } | null> /** ?token=… from the route — auths the frequency-sim-control channel (design §4). */ @@ -65,7 +72,8 @@ export function useLiveAtcSession( const { state, freq, speech, radioBackend, api, config, prefetchAtisAudio, - isRecording, autoTuneEnabled, bridgeConnected, bridgePosition, bridgeToken, + isRecording, autoTuneEnabled, forceRto, forceGoAround, + bridgeConnected, bridgePosition, bridgeToken, persistSelectedPlan, maybeShowFirstRunHelp, } = deps @@ -696,6 +704,12 @@ export function useLiveAtcSession( handoff_freq: v.handoff_freq || '131.150', } + // Special scenarios. Only sent when switched on: the backend treats the + // variable's absence as "leave it to chance", and sending false would pin + // the roll off rather than leaving it alone. + if (forceRto.value) backendVariables.force_rto = true + if (forceGoAround.value) backendVariables.force_go_around = true + // 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 diff --git a/app/pages/live-atc.vue b/app/pages/live-atc.vue index 734c08c..3752535 100644 --- a/app/pages/live-atc.vue +++ b/app/pages/live-atc.vue @@ -142,6 +142,8 @@ v-model:prerec-seconds="prerecSeconds" v-model:ai-traffic-enabled="aiTrafficEnabled" v-model:auto-tune-enabled="autoTuneEnabled" + v-model:force-rto="forceRto" + v-model:force-go-around="forceGoAround" @set-theme="setPmTheme" /> @@ -321,6 +323,11 @@ const aiTrafficEnabled = ref(false) // working the radio is part of what is being practised, so turning it over to // the aircraft has to be a deliberate choice. const autoTuneEnabled = ref(false) +// Special scenarios: force a rare intervention on the next flight rather than +// waiting for its ~0.2% chance. Read when the session is created, so toggling +// mid-flight affects the next one — which is also how you teach them. +const forceRto = ref(false) +const forceGoAround = ref(false) // ── Bug Report ─────────────────────────────────────────────────────────────── // Owned here rather than by the dialog: the HUD button starts the screenshot @@ -599,6 +606,8 @@ const session = useLiveAtcSession(engine, { prefetchAtisAudio, isRecording, autoTuneEnabled, + forceRto, + forceGoAround, bridgeConnected, bridgePosition, bridgeToken,