7159 lines
207 KiB
Plaintext
7159 lines
207 KiB
Plaintext
#
|
|
# Red Griffin ATC - Speaking Air Traffic Controller for FlightGear
|
|
#
|
|
# Written and developer by Antonello Biancalana (Red Griffin, IK0TOJ)
|
|
#
|
|
# Copyright (C) 2019-2021 Antonello Biancalana
|
|
#
|
|
# rgatc.nas
|
|
#
|
|
# Main program
|
|
#
|
|
# Version 2.3.0 - 7 May 2021
|
|
#
|
|
# Red Griffin ATC is an Open Source project and it is licensed
|
|
# under the Gnu Public License v3 (GPLv3)
|
|
#
|
|
|
|
var rgatcKeyboardListener = setlistener("/devices/status/keyboard/event", func(event)
|
|
{
|
|
if(!event.getNode("pressed").getValue())
|
|
return;
|
|
|
|
var key = event.getNode("key").getValue();
|
|
var shift = event.getNode("modifier/shift").getValue();
|
|
var ctrl = event.getNode("modifier/ctrl").getValue();
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
if(key == last_key)
|
|
return;
|
|
|
|
if(isAtcEnabled() == 0)
|
|
{
|
|
#showPopup(RGAtcName ~ " is not enabled.\nTurn it on from the menu");
|
|
showPopup(RGAtcName ~ " 未启用.\nTurn it on from the menu");
|
|
|
|
return;
|
|
}
|
|
|
|
last_key = key;
|
|
|
|
if(key == binding_key_dialog)
|
|
{
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
if(!rgatcTimer.isRunning)
|
|
rgatcTimer.start();
|
|
|
|
if(ctrl == 0)
|
|
{
|
|
last_key = 0;
|
|
|
|
if(dialogOpened == 0)
|
|
openATCDialog();
|
|
else
|
|
closeATCDialog();
|
|
}
|
|
else
|
|
updateATC(update_popup);
|
|
|
|
return;
|
|
}
|
|
else if(ctrl == 1 and shift == 0)
|
|
{
|
|
if(key == binding_key_msg1)
|
|
pilotRequest(atcMessageType[0]);
|
|
else if(key == binding_key_msg2)
|
|
pilotRequest(atcMessageType[1]);
|
|
else if(key == binding_key_msg3)
|
|
pilotRequest(atcMessageType[2]);
|
|
else if(key == binding_key_msg4)
|
|
pilotRequest(atcMessageType[3]);
|
|
else if(key == binding_key_request_ctr)
|
|
pilotRequest(message_request_ctr);
|
|
else if(key == binding_key_repeat_last_atc_message)
|
|
pilotRequest(message_say_again);
|
|
}
|
|
else if(ctrl == 1 and shift == 1)
|
|
{
|
|
if(key == binding_key_flight_level_1 and aircraft_status == status_flying and flightLevel1 >= minCruiseAltidude)
|
|
{
|
|
requestedAltitude = flightLevel1;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
else if(key == binding_key_flight_level_2 and aircraft_status == status_flying and flightLevel2 >= minCruiseAltidude)
|
|
{
|
|
requestedAltitude = flightLevel2;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
else if(key == binding_key_flight_level_3 and aircraft_status == status_flying and flightLevel3 >= minCruiseAltidude and property_Aircraft_AltitudeFeet.getValue() > flightLevel3)
|
|
{
|
|
requestedAltitude = flightLevel3;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
else if(key == binding_key_abort_approach)
|
|
pilotRequest(message_abort_approach);
|
|
}
|
|
}, 1);
|
|
|
|
var rgatcTimer = maketimer(timer_interval, func()
|
|
{
|
|
var isTerrainSafe = 1;
|
|
var radioIsTunedToApprovedCtrRadio = 0;
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
if(isSimulationPaused() == 1 or isAtcEnabled() == 0)
|
|
return;
|
|
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
updateATC((dialogOpened == 1) ? update_dialog : update_data_only);
|
|
|
|
if(atc_callback_wait_seconds != auto_reply_off)
|
|
{
|
|
atc_callback_seconds_counter += timer_interval;
|
|
|
|
if(atc_callback_seconds_counter >= atc_callback_wait_seconds)
|
|
{
|
|
atc_callback_seconds_counter = 0;
|
|
|
|
atc_callback_wait_seconds = auto_reply_off;
|
|
|
|
atcAutoMessage();
|
|
}
|
|
}
|
|
|
|
if(pilot_message_wait_seconds > 0)
|
|
{
|
|
pilot_message_counter += timer_interval;
|
|
|
|
if(pilot_message_counter >= pilot_message_wait_seconds)
|
|
{
|
|
pilot_message_wait_seconds = -1;
|
|
|
|
atcReplyToRequest(pilotMessageType);
|
|
|
|
pilotMessageType = message_none;
|
|
}
|
|
}
|
|
|
|
if(pilot_response_wait_seconds > 0)
|
|
{
|
|
pilot_response_counter += timer_interval;
|
|
|
|
if(pilot_response_counter >= pilot_response_wait_seconds)
|
|
{
|
|
pilot_response_wait_seconds = -1;
|
|
|
|
pilotResponse(pilotResponseType);
|
|
|
|
pilotResponseType = message_none;
|
|
}
|
|
}
|
|
|
|
key_press_counter += timer_interval;
|
|
ctr_update_counter += timer_interval;
|
|
ctr_check_counter += timer_interval;
|
|
|
|
if(aircraft_status == status_flying or aircraft_status == status_took_off)
|
|
flight_time_seconds += timer_interval;
|
|
|
|
if(key_press_counter > reset_key_interval)
|
|
{
|
|
key_press_counter = 0;
|
|
|
|
last_key = 0;
|
|
}
|
|
|
|
radioIsTunedToApprovedCtrRadio = isRadioTunedToApprovedCtrRadio();
|
|
|
|
if(ctr_check_counter > ctr_check_interval)
|
|
{
|
|
if(currentCtr != nil and approvedCtr == nil and aircraft_status == status_flying and radioIsTunedToApprovedCtrRadio == 1)
|
|
{
|
|
atcReplyToRequest(message_not_in_this_ctr);
|
|
}
|
|
|
|
ctr_check_counter = 0;
|
|
}
|
|
|
|
if(ctr_update_counter > ctr_update_interval)
|
|
{
|
|
if(approvedCtr != nil)
|
|
{
|
|
currentCtr = getCtrData(airportinfo(approvedCtr.ident));
|
|
|
|
if(currentCtr.distance > (currentCtr.range - ctr_leaving_range))
|
|
{
|
|
if(radioIsTunedToApprovedCtrRadio == 1)
|
|
atcReplyToRequest(message_leaving_ctr);
|
|
|
|
ctr_leaving_warning = 1;
|
|
|
|
approvedCtr = nil;
|
|
|
|
altitude_check_counter = 0;
|
|
|
|
resetAircraftStatus();
|
|
|
|
setCtrButtons();
|
|
}
|
|
}
|
|
else
|
|
currentCtr = getNearbyCtr(ctr_search_range);
|
|
|
|
ctr_update_counter = 0;
|
|
|
|
var aircraftPosition = geo.aircraft_position();
|
|
var terrainInfo = geodinfo(aircraftPosition.lat(), aircraftPosition.lon());
|
|
isTerrainSafe = isTerrainSafeAhead();
|
|
|
|
if(terrainInfo != nil)
|
|
altitudeFromTerrain = property_Aircraft_AltitudeFeet.getValue() - (terrainInfo[0] * M2FT);
|
|
else
|
|
altitudeFromTerrain = -1;
|
|
|
|
if((altitudeFromTerrain < min_altitude_from_terrain or isTerrainSafe == 0) and terrainWarning == 0 and (aircraft_status == status_flying or aircraft_status == status_requested_approach or aircraft_status == status_requested_ils) and flight_time_seconds > take_off_max_seconds)
|
|
{
|
|
if(approvedCtr.ident == currentCtr.ident and radioIsTunedToApprovedCtrRadio == 1)
|
|
{
|
|
if(altitudeFromTerrain > min_altitude_too_low_warning)
|
|
{
|
|
if(altitudeFromTerrain < min_altitude_from_terrain and tooLowWarningMode == "On")
|
|
atcReplyToRequest(message_flying_too_low);
|
|
else if(isTerrainSafe == 0 and terrainWarningMode == "On")
|
|
atcReplyToRequest(message_terrain_ahead);
|
|
}
|
|
|
|
terrainWarning = 1;
|
|
terrain_warning_counter = 0;
|
|
}
|
|
}
|
|
|
|
if(aircraft_status == status_flying)
|
|
{
|
|
var heading = property_Aircraft_HeadingDeg.getValue();
|
|
|
|
flightLevel2 = normalizeAltitudeHeading(property_Aircraft_AltitudeFeet.getValue(), heading, minCruiseAltidude);
|
|
|
|
flightLevel1 = flightLevel2 + flight_level_step;
|
|
|
|
flightLevel3 = flightLevel2 - flight_level_step;
|
|
|
|
if(flightLevel2 < minCruiseAltidude)
|
|
flightLevel2 = normalizeAltitudeHeading(minCruiseAltidude, heading, minCruiseAltidude);
|
|
|
|
if(flightLevel3 < minCruiseAltidude)
|
|
flightLevel3 = normalizeAltitudeHeading(minCruiseAltidude, heading, minCruiseAltidude);
|
|
}
|
|
}
|
|
|
|
if(terrainWarning == 1)
|
|
{
|
|
terrain_warning_counter += timer_interval;
|
|
|
|
if(terrain_warning_counter >= terrain_warning_interval)
|
|
{
|
|
if(pilot_message_wait_seconds > 0)
|
|
pilot_message_wait_seconds += 10;
|
|
|
|
if(altitude_change_wait_seconds > 0)
|
|
altitude_change_wait_seconds += 15;
|
|
|
|
altitude_check_counter = 0;
|
|
|
|
if(altitudeFromTerrain > min_altitude_too_low_warning)
|
|
{
|
|
if(altitudeFromTerrain < min_altitude_from_terrain)
|
|
atcReplyToRequest(message_flying_too_low);
|
|
else if(isTerrainSafe == 0)
|
|
atcReplyToRequest(message_terrain_ahead);
|
|
else
|
|
terrainWarning = 0;
|
|
}
|
|
else
|
|
terrainWarning = 0;
|
|
|
|
terrain_warning_counter = 0;
|
|
}
|
|
}
|
|
|
|
if(assignedAltitude != -1 and aircraft_status == status_flying)
|
|
{
|
|
altitude_check_counter += timer_interval;
|
|
|
|
if(approvedCtr != nil)
|
|
{
|
|
if(altitude_check_counter >= altitude_check_interval and radioIsTunedToApprovedCtrRadio == 1)
|
|
{
|
|
var fpalt = getFlightPlanAltitude();
|
|
|
|
if(fpalt != -1 and assignedAltitude != fpalt)
|
|
{
|
|
atcReplyToRequest(message_change_altitude);
|
|
}
|
|
else
|
|
{
|
|
if(property_Aircraft_HeadingDeg.getValue() > 180)
|
|
altitudeZone = altitude_zone_even;
|
|
else
|
|
altitudeZone = altitude_zone_odd;
|
|
|
|
if(currentAltitudeZone != altitudeZone)
|
|
{
|
|
currentAltitudeZone = altitudeZone;
|
|
|
|
atcReplyToRequest(message_change_altitude);
|
|
}
|
|
else if(abs(property_Aircraft_AltitudeFeet.getValue() - assignedAltitude) > assigned_altitude_delta)
|
|
atcReplyToRequest(message_check_altitude);
|
|
}
|
|
|
|
altitude_check_counter = 0;
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(altitude_change_wait_seconds > 0)
|
|
{
|
|
altitude_change_counter += timer_interval;
|
|
|
|
if(approvedCtr != nil)
|
|
{
|
|
if(altitude_change_counter >= altitude_change_wait_seconds and aircraft_status == status_flying and radioIsTunedToApprovedCtrRadio == 1)
|
|
{
|
|
altitude_change_wait_seconds = -1;
|
|
|
|
atcReplyToRequest(message_change_altitude);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(aircraft_status == status_requested_approach or aircraft_status == status_requested_ils)
|
|
{
|
|
approach_check_counter += timer_interval;
|
|
|
|
if(approach_check_counter > approach_check_interval and radioIsTunedToApprovedCtrRadio == 1)
|
|
{
|
|
assistedAtcApproach();
|
|
|
|
approach_check_counter = 0;
|
|
}
|
|
}
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
if(aircraft_status == status_flying or aircraft_status == status_requested_approach or aircraft_status == status_requested_ils)
|
|
{
|
|
squawk_check_counter += timer_interval;
|
|
|
|
if(checkTransponderIdent(selectedTransponder) == 1)
|
|
squawkIdentButtonPushed = 1;
|
|
|
|
if(squawk_check_counter > squawk_check_interval)
|
|
{
|
|
if(squawkIdent != squawk_ident_off)
|
|
{
|
|
if(checkTransponder(selectedTransponder) == 1 and squawkIdentButtonPushed == 1)
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
else
|
|
atcReplyToRequest(message_check_transponder);
|
|
}
|
|
else if(checkTransponder(selectedTransponder) == 0)
|
|
atcReplyToRequest(message_check_transponder);
|
|
|
|
squawk_check_counter = 0;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var initRgATC = func()
|
|
{
|
|
initSettings();
|
|
|
|
var aircraftDescription = split(" ", getprop("/sim/description"));
|
|
|
|
RGAtcName = getprop(RGAtcAddonProp ~ "name");
|
|
RGAtcVersion = getprop(RGAtcAddonProp ~ "version");
|
|
|
|
setRGTitle();
|
|
|
|
if(size(aircraftDescription) > 0)
|
|
aircraftManufacturer = aircraftDescription[0];
|
|
else
|
|
aircraftManufacturer = "";
|
|
|
|
rgatcTimer.start();
|
|
|
|
initialized = 1;
|
|
|
|
setsize(radioButton, max_radios);
|
|
setsize(radioButtonFrequency, max_radios);
|
|
|
|
for(var i = 0; i < max_radios; i += 1)
|
|
{
|
|
radioButton[i] = nil;
|
|
radioButtonFrequency[i] = 0;
|
|
}
|
|
|
|
var pos = geo.aircraft_position();
|
|
|
|
var range = min_airport_range;
|
|
|
|
if(currentCtr != nil)
|
|
range += int((currentCtr.range / 1.5) / 10);
|
|
|
|
var airport = findAirportsWithinRange(pos, range);
|
|
|
|
if(size(airport) > 0)
|
|
{
|
|
currentAirport = airport[0];
|
|
|
|
getAvailableRadios();
|
|
|
|
currentRadioStationId = currentAirport.id;
|
|
}
|
|
|
|
aircraftIsDeparting = 1;
|
|
approachStatus = approach_status_none;
|
|
approach_check_interval = approach_check_interval_initial;
|
|
|
|
currentCtr = getNearbyCtr(ctr_search_range);
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(1);
|
|
|
|
pilotVoice = getPilotVoice();
|
|
|
|
initAtcVoice();
|
|
|
|
print(RGAtcName ~ " successfully initialized and ready");
|
|
|
|
RGAtcEnabled = 1;
|
|
|
|
clearAtcLog();
|
|
}
|
|
|
|
var enableAtc = func()
|
|
{
|
|
if(!rgatcTimer.isRunning)
|
|
rgatcTimer.start();
|
|
|
|
RGAtcEnabled = 1;
|
|
|
|
openATCDialog();
|
|
|
|
showPopup(RGAtcName ~ " is on");
|
|
}
|
|
|
|
var disableAtc = func()
|
|
{
|
|
if(rgatcTimer.isRunning)
|
|
rgatcTimer.stop();
|
|
|
|
RGAtcEnabled = 0;
|
|
|
|
closeATCDialog();
|
|
|
|
showPopup(RGAtcName ~ " is off");
|
|
}
|
|
|
|
var isAtcEnabled = func()
|
|
{
|
|
return RGAtcEnabled;
|
|
}
|
|
|
|
var toggleAtc = func()
|
|
{
|
|
if(isAtcEnabled() == 1)
|
|
disableAtc();
|
|
else
|
|
enableAtc();
|
|
}
|
|
|
|
var setRGTitle = func()
|
|
{
|
|
RGAtcTitle = "Red Griffin ATC";
|
|
|
|
if(RGAtcName != nil and RGAtcName != "")
|
|
{
|
|
RGAtcTitle = RGAtcName;
|
|
|
|
if(RGAtcVersion != nil and RGAtcVersion != "")
|
|
RGAtcTitle ~= " " ~ RGAtcVersion;
|
|
}
|
|
else
|
|
RGAtcName = RGAtcTitle;
|
|
|
|
RGAtcTitle ~= " - Aircraft: " ~ aircraftType;
|
|
|
|
if(dlgWindow != nil)
|
|
dlgWindow.setTitle(RGAtcTitle);
|
|
}
|
|
|
|
var initRgATCDialog = func()
|
|
{
|
|
dlgWindow = canvas.Window.new([dialogWidth, dialogHeight], "dialog")
|
|
.setTitle(RGAtcTitle);
|
|
|
|
dlgWindow.del = func()
|
|
{
|
|
dialogInitialized = 0;
|
|
dialogOpened = 0;
|
|
|
|
call(canvas.Window.del, [], me);
|
|
};
|
|
|
|
dlgCanvas = dlgWindow.createCanvas().set("background", canvas.style.getColor("bg_color"));
|
|
dlgCanvas.setColorBackground(0.5, 0.5, 0.5, 0.9);
|
|
|
|
dlgRoot = dlgCanvas.createGroup();
|
|
|
|
dlgLayout = canvas.VBoxLayout.new();
|
|
|
|
dlgCanvas.setLayout(dlgLayout);
|
|
|
|
txtAirport = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1,1,1,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 20);
|
|
|
|
txtAircraftPosition = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1,1,1,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 36);
|
|
|
|
txtCurrentCtr = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(0.6,1,1,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 60);
|
|
|
|
txtCurrentCtrSpecs = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(0.6,1,1,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 76);
|
|
|
|
txtCurrentRadio = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1,1,0,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 100);
|
|
|
|
txtCurrentRadioSpecs = dlgRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1,1,0,1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 116);
|
|
|
|
var buttonBox = canvas.HBoxLayout.new();
|
|
|
|
var middleBox = canvas.HBoxLayout.new();
|
|
|
|
var messageBox = canvas.VBoxLayout.new();
|
|
|
|
var topButtonBox = canvas.HBoxLayout.new();
|
|
|
|
btnRepeatATCMessage = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("R")
|
|
.setFixedSize(repeatBtnWidth, 26);
|
|
|
|
btnRepeatATCMessage.hide();
|
|
|
|
btnRepeatATCMessage.listen("clicked", func
|
|
{
|
|
pilotRequest(message_say_again);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnRepeatATCMessage.hide();
|
|
|
|
btnMessage[0] = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("")
|
|
.setFixedSize((dialogWidth / 2) - 20, 26);
|
|
|
|
btnMessage[0].listen("clicked", func
|
|
{
|
|
pilotRequest(atcMessageType[0]);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnMessage[1] = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("")
|
|
.setFixedSize((dialogWidth / 2) - 20, 26);
|
|
|
|
btnMessage[1].listen("clicked", func
|
|
{
|
|
pilotRequest(atcMessageType[1]);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnMessage[2] = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("")
|
|
.setFixedSize((dialogWidth / 2) - 20, 26);
|
|
|
|
btnMessage[2].listen("clicked", func
|
|
{
|
|
pilotRequest(atcMessageType[2]);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnMessage[3] = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("")
|
|
.setFixedSize((dialogWidth / 2) - 20, 26);
|
|
|
|
btnMessage[3].listen("clicked", func
|
|
{
|
|
pilotRequest(atcMessageType[3]);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
for(var i = 0; i < 4; i += 1)
|
|
btnMessage[i].hide();
|
|
|
|
topButtonBox.addItem(btnRepeatATCMessage);
|
|
topButtonBox.addItem(btnMessage[0]);
|
|
|
|
messageBox.addItem(topButtonBox);
|
|
messageBox.addItem(btnMessage[1]);
|
|
messageBox.addItem(btnMessage[2]);
|
|
messageBox.addItem(btnMessage[3]);
|
|
|
|
radioBox = canvas.VBoxLayout.new();
|
|
|
|
radioBox.hide();
|
|
|
|
radioScroll = canvas.gui.widgets.ScrollArea.new(dlgRoot, canvas.style, {size: [(dialogWidth / 2) - 20, 80]});
|
|
radioScroll.setColorBackground(1.0, 1.0, 0.9, 0.9);
|
|
|
|
radioBox.addItem(radioScroll, 1);
|
|
|
|
radioScrollContent = radioScroll.getContent()
|
|
.set("font", "LiberationFonts/LiberationSans-Bold.ttf")
|
|
.set("character-size", 16)
|
|
.set("alignment", "left-center");
|
|
|
|
middleBox.addItem(messageBox);
|
|
middleBox.addItem(radioBox);
|
|
|
|
btnRequestCtr = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("Request CTR")
|
|
.setFixedSize(114, 26);
|
|
|
|
btnRequestCtr.setEnabled(0);
|
|
|
|
btnRequestCtr.listen("clicked", func
|
|
{
|
|
pilotRequest(message_request_ctr);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
btnRequestFlightLevel1 = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("--")
|
|
.setFixedSize(58, 26);
|
|
|
|
btnRequestFlightLevel1.setEnabled(0);
|
|
|
|
btnRequestFlightLevel1.listen("clicked", func
|
|
{
|
|
if(flightLevel1 >= minCruiseAltidude)
|
|
{
|
|
requestedAltitude = flightLevel1;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnRequestFlightLevel2 = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("--")
|
|
.setFixedSize(58, 26);
|
|
|
|
btnRequestFlightLevel2.setEnabled(0);
|
|
|
|
btnRequestFlightLevel2.listen("clicked", func
|
|
{
|
|
if(flightLevel2 >= minCruiseAltidude)
|
|
{
|
|
requestedAltitude = flightLevel2;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnRequestFlightLevel3 = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("--")
|
|
.setFixedSize(58, 26);
|
|
|
|
btnRequestFlightLevel3.setEnabled(0);
|
|
|
|
btnRequestFlightLevel3.listen("clicked", func
|
|
{
|
|
if(flightLevel3 >= minCruiseAltidude)
|
|
{
|
|
requestedAltitude = flightLevel3;
|
|
|
|
pilotRequest(message_request_fl);
|
|
}
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnAbortApproach = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("--")
|
|
.setFixedSize(140, 26);
|
|
|
|
btnAbortApproach.setEnabled(0);
|
|
|
|
btnAbortApproach.listen("clicked", func
|
|
{
|
|
pilotRequest(message_abort_approach);
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
btnAvailableRadio = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("Radios")
|
|
.setFixedSize(74, 26);
|
|
|
|
btnAvailableRadio.setEnabled(0);
|
|
|
|
btnAvailableRadio.listen("clicked", func
|
|
{
|
|
availableRadioDialog();
|
|
|
|
dlgWindow.clearFocus();
|
|
});
|
|
|
|
var btnClose = canvas.gui.widgets.Button.new(dlgRoot, canvas.style, {})
|
|
.setText("Close")
|
|
.setFixedSize(70, 26);
|
|
|
|
btnClose.listen("clicked", func
|
|
{
|
|
closeATCDialog();
|
|
});
|
|
|
|
setApproachButtons();
|
|
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnRequestCtr);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnAbortApproach);
|
|
buttonBox.addItem(btnRequestFlightLevel1);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnRequestFlightLevel2);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnRequestFlightLevel3);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnAvailableRadio);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnClose);
|
|
buttonBox.addStretch(1);
|
|
|
|
dlgLayout.addStretch(1);
|
|
dlgLayout.addItem(middleBox);
|
|
dlgLayout.addItem(buttonBox);
|
|
|
|
dialogInitialized = 1;
|
|
|
|
setDialogPosition();
|
|
|
|
showRepeatATCMessageButton(0);
|
|
|
|
updateATC(update_dialog);
|
|
}
|
|
|
|
var setAtcTextPosition = func()
|
|
{
|
|
if(atcTextPosition == "Top Left")
|
|
{
|
|
atc_popup_x_position = 20;
|
|
atc_popup_y_position = -(10 + menu_bar_height);
|
|
atc_popup_align = "left";
|
|
}
|
|
else if(atcTextPosition == "Top Center")
|
|
{
|
|
atc_popup_x_position = nil;
|
|
atc_popup_y_position = -(10 + menu_bar_height);
|
|
atc_popup_align = "center";
|
|
}
|
|
else if(atcTextPosition == "Top Right")
|
|
{
|
|
atc_popup_x_position = -20;
|
|
atc_popup_y_position = -(10 + menu_bar_height);
|
|
atc_popup_align = "left";
|
|
}
|
|
else if(atcTextPosition == "Middle Left")
|
|
{
|
|
atc_popup_x_position = 20;
|
|
atc_popup_y_position = nil;
|
|
atc_popup_align = "left";
|
|
}
|
|
else if(atcTextPosition == "Middle Center")
|
|
{
|
|
atc_popup_x_position = nil;
|
|
atc_popup_y_position = nil;
|
|
atc_popup_align = "center";
|
|
}
|
|
else if(atcTextPosition == "Middle Right")
|
|
{
|
|
atc_popup_x_position = -20;
|
|
atc_popup_y_position = nil;
|
|
atc_popup_align = "left";
|
|
}
|
|
else if(atcTextPosition == "Bottom Left")
|
|
{
|
|
atc_popup_x_position = 20;
|
|
atc_popup_y_position = 10 + menu_bar_height;
|
|
atc_popup_align = "left";
|
|
}
|
|
else if(atcTextPosition == "Bottom Center")
|
|
{
|
|
atc_popup_x_position = nil;
|
|
atc_popup_y_position = 10 + menu_bar_height;
|
|
atc_popup_align = "center";
|
|
}
|
|
else if(atcTextPosition == "Bottom Right")
|
|
{
|
|
atc_popup_x_position = -20;
|
|
atc_popup_y_position = 10 + menu_bar_height;
|
|
atc_popup_align = "left";
|
|
}
|
|
else
|
|
{
|
|
atc_popup_x_position = nil;
|
|
atc_popup_y_position = -(10 + menu_bar_height);
|
|
atc_popup_align = "center";
|
|
}
|
|
|
|
if(atcTextTransparency == "Off")
|
|
popup_window_bg_color[3] = 1;
|
|
else if(atcTextTransparency == "Very low")
|
|
popup_window_bg_color[3] = 0.8;
|
|
else if(atcTextTransparency == "Low")
|
|
popup_window_bg_color[3] = 0.6;
|
|
else if(atcTextTransparency == "Medium")
|
|
popup_window_bg_color[3] = 0.4;
|
|
else if(atcTextTransparency == "High")
|
|
popup_window_bg_color[3] = 0.2;
|
|
else if(atcTextTransparency == "Very high")
|
|
popup_window_bg_color[3] = 0;
|
|
else
|
|
popup_window_bg_color[3] = 0.4;
|
|
}
|
|
|
|
var setDialogPosition = func()
|
|
{
|
|
var canvasWidth = property_Canvas_Width.getValue();
|
|
var canvasHeight = property_Canvas_Height.getValue();
|
|
|
|
if(canvasWidth != nil and canvasHeight != nil)
|
|
{
|
|
if(dialogPosition == "Top Left")
|
|
{
|
|
dialogPosX = 0;
|
|
dialogPosY = menu_bar_height;
|
|
}
|
|
else if(dialogPosition == "Top Right")
|
|
{
|
|
dialogPosX = canvasWidth - maxDialogWidth;
|
|
dialogPosY = menu_bar_height;
|
|
}
|
|
else if(dialogPosition == "Bottom Left")
|
|
{
|
|
dialogPosX = 0;
|
|
dialogPosY = canvasHeight - maxDialogHeight;
|
|
}
|
|
else if(dialogPosition == "Bottom Right")
|
|
{
|
|
dialogPosX = canvasWidth - maxDialogWidth;
|
|
dialogPosY = canvasHeight - maxDialogHeight;
|
|
}
|
|
else
|
|
{
|
|
dialogPosX = 0;
|
|
dialogPosY = menu_bar_height;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dialogPosX = 0;
|
|
dialogPosY = menu_bar_height;
|
|
}
|
|
|
|
if(dlgWindow != nil and dialogInitialized == 1)
|
|
dlgWindow.setPosition(dialogPosX, dialogPosY);
|
|
}
|
|
|
|
var setApproachButtons = func()
|
|
{
|
|
if(dialogOpened == 0)
|
|
return;
|
|
|
|
if(aircraft_status == status_requested_approach or aircraft_status == status_requested_ils or aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
btnRequestFlightLevel1.setEnabled(0);
|
|
btnRequestFlightLevel2.setEnabled(0);
|
|
btnRequestFlightLevel3.setEnabled(0);
|
|
|
|
btnRequestFlightLevel1.hide();
|
|
btnRequestFlightLevel2.hide();
|
|
btnRequestFlightLevel3.hide();
|
|
|
|
btnAbortApproach.setEnabled(1);
|
|
|
|
btnAbortApproach.show();
|
|
|
|
if(aircraft_status == status_requested_approach)
|
|
btnAbortApproach.setText("Abort Approach");
|
|
else if(aircraft_status == status_requested_ils)
|
|
btnAbortApproach.setText("Abort ILS");
|
|
else if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
btnAbortApproach.setText("Abort Landing");
|
|
else
|
|
{
|
|
btnAbortApproach.setEnabled(0);
|
|
btnAbortApproach.hide();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
btnAbortApproach.setEnabled(0);
|
|
|
|
btnAbortApproach.hide();
|
|
|
|
btnRequestFlightLevel1.setEnabled(1);
|
|
btnRequestFlightLevel2.setEnabled(1);
|
|
btnRequestFlightLevel3.setEnabled(1);
|
|
|
|
btnRequestFlightLevel1.show();
|
|
btnRequestFlightLevel2.show();
|
|
btnRequestFlightLevel3.show();
|
|
}
|
|
}
|
|
|
|
var setCtrButtons = func()
|
|
{
|
|
if(dialogOpened == 0)
|
|
return;
|
|
|
|
if(selectedComFrequency > 0)
|
|
btnRequestCtr.setEnabled(1);
|
|
else
|
|
btnRequestCtr.setEnabled(0);
|
|
|
|
if(aircraft_status == status_flying)
|
|
{
|
|
if(approvedCtr != nil)
|
|
{
|
|
btnRequestFlightLevel1.show();
|
|
btnRequestFlightLevel2.show();
|
|
btnRequestFlightLevel3.show();
|
|
}
|
|
else
|
|
{
|
|
btnRequestFlightLevel1.hide();
|
|
btnRequestFlightLevel2.hide();
|
|
btnRequestFlightLevel3.hide();
|
|
}
|
|
}
|
|
}
|
|
|
|
var openATCDialog = func()
|
|
{
|
|
if(isAtcEnabled() == 0)
|
|
{
|
|
showPopup(RGAtcName ~ " is not enabled.\nTurn it on from the menu");
|
|
|
|
return;
|
|
}
|
|
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
if(dlgWindow == nil or dialogInitialized == 0)
|
|
initRgATCDialog();
|
|
|
|
if(dlgWindow != nil and dialogInitialized == 1)
|
|
{
|
|
if(dialogOpened == 0)
|
|
{
|
|
dlgWindow.show();
|
|
|
|
dlgWindow.clearFocus();
|
|
|
|
setRGTitle();
|
|
|
|
dialogOpened = 1;
|
|
|
|
updateATC(update_dialog);
|
|
|
|
updateRadioList();
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
}
|
|
else
|
|
closeATCDialog();
|
|
}
|
|
}
|
|
|
|
var closeATCDialog = func()
|
|
{
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
if(dlgWindow == nil or dialogInitialized == 0)
|
|
initRgATCDialog();
|
|
|
|
if(dialogInitialized == 1 and dialogOpened == 1 and dlgWindow != nil)
|
|
{
|
|
dlgWindow.hide();
|
|
|
|
dialogOpened = 0;
|
|
|
|
dlgWindow.clearFocus();
|
|
}
|
|
}
|
|
|
|
var openAtcLogDialog = func()
|
|
{
|
|
if(atcLogWindow == nil)
|
|
{
|
|
atcLogWindow = canvas.Window.new([320, 180], "dialog")
|
|
.setTitle(RGAtcName ~ ": Log");
|
|
|
|
var atcLogCanvas = atcLogWindow.createCanvas().set("background", canvas.style.getColor("bg_color"));
|
|
atcLogCanvas.setColorBackground(0.4, 0.4, 0.4, 0.9);
|
|
|
|
var atcLogRoot = atcLogCanvas.createGroup();
|
|
|
|
var atcLogLayout = canvas.VBoxLayout.new();
|
|
|
|
atcLogCanvas.setLayout(atcLogLayout);
|
|
|
|
atcLogScroll = canvas.gui.widgets.ScrollArea.new(atcLogRoot, canvas.style, {});
|
|
atcLogScroll.setColorBackground(1.0, 1.0, 0.9, 0.9);
|
|
atcLogScroll.setFixedSize(320, 148);
|
|
|
|
atcLogLayout.addItem(atcLogScroll, 1);
|
|
|
|
atcLogScrollContent = atcLogScroll.getContent()
|
|
.set("font", "LiberationFonts/LiberationSans-Bold.ttf")
|
|
.set("character-size", 16)
|
|
.set("alignment", "left-center");
|
|
|
|
txtAtcLog = canvas.gui.widgets.Label.new(atcLogScrollContent, canvas.style, {});
|
|
|
|
var btnClear = canvas.gui.widgets.Button.new(atcLogRoot, canvas.style, {})
|
|
.setText("Clear")
|
|
.setFixedSize(75, 26);
|
|
|
|
btnClear.listen("clicked", func
|
|
{
|
|
clearAtcLog();
|
|
});
|
|
|
|
var btnClose = canvas.gui.widgets.Button.new(atcLogRoot, canvas.style, {})
|
|
.setText("Close")
|
|
.setFixedSize(75, 26);
|
|
|
|
btnClose.listen("clicked", func
|
|
{
|
|
atcLogWindow.hide();
|
|
|
|
atcLogOpened = 0;
|
|
});
|
|
|
|
var buttonBox = canvas.HBoxLayout.new();
|
|
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnClear);
|
|
buttonBox.addStretch(1);
|
|
buttonBox.addItem(btnClose);
|
|
buttonBox.addStretch(1);
|
|
|
|
atcLogLayout.addStretch(1);
|
|
atcLogLayout.addItem(buttonBox);
|
|
}
|
|
else
|
|
atcLogWindow.show();
|
|
|
|
atcLogOpened = 1;
|
|
|
|
txtAtcLog.setText(atcLogText);
|
|
|
|
atcLogWindow.raise(1);
|
|
|
|
atcLogScroll.scrollTo(0, 32768);
|
|
|
|
atcLogWindow.clearFocus();
|
|
}
|
|
|
|
var addAtcLog = func(text)
|
|
{
|
|
rowlen = 45;
|
|
|
|
text = string.replace(text, "\n", " ");
|
|
var word = split(" ", text);
|
|
var wlen = size(word);
|
|
var row = property_TimeGmtString.getValue() ~ "Z: ";
|
|
|
|
for(var i = 0; i < wlen; i += 1)
|
|
{
|
|
if(size(row) + size(word[i]) <= rowlen)
|
|
row ~= word[i] ~ " ";
|
|
else
|
|
{
|
|
atcLogText ~= row ~ "\n";
|
|
|
|
row = word[i] ~ " ";
|
|
}
|
|
}
|
|
|
|
atcLogText ~= row ~ "\n\n";
|
|
|
|
if(txtAtcLog != nil)
|
|
txtAtcLog.setText(atcLogText);
|
|
|
|
if(atcLogOpened == 1 and atcLogWindow != nil and atcLogScroll != nil)
|
|
atcLogScroll.scrollTo(0, 32768);
|
|
}
|
|
|
|
var clearAtcLog = func()
|
|
{
|
|
atcLogText = "\n";
|
|
|
|
if(txtAtcLog != nil)
|
|
txtAtcLog.setText(atcLogText);
|
|
|
|
if(atcLogOpened == 1 and atcLogWindow != nil and atcLogScroll != nil)
|
|
atcLogScroll.scrollTo(0, 32768);
|
|
}
|
|
|
|
var updateATC = func(update_mode)
|
|
{
|
|
var type = nil;
|
|
var aircraftPosition = "";
|
|
var txt = "";
|
|
var degTag = "°";
|
|
var popupText = RGAtcTitle ~ "\n\n";
|
|
|
|
if(update_mode == update_dialog)
|
|
degTag = "°";
|
|
else
|
|
degTag = "°";
|
|
|
|
if(property_COM1_Serviceable != nil)
|
|
{
|
|
if(property_COM1_Quality != nil)
|
|
com1quality = property_COM1_Quality.getValue();
|
|
else
|
|
com1quality = 5;
|
|
|
|
com1volume = getRadioVolume(property_COM1_Volume, property_COM1_VolumeSelected);
|
|
|
|
com1serviceable = property_COM1_Serviceable.getValue();
|
|
|
|
if(property_COM1_PowerButton != nil)
|
|
com1PowerStatus = property_COM1_PowerButton.getValue();
|
|
else
|
|
com1PowerStatus = 1;
|
|
|
|
if(property_COM1_Operable != nil)
|
|
com1Operable = property_COM1_Operable.getValue();
|
|
else
|
|
com1Operable = 1;
|
|
}
|
|
else
|
|
{
|
|
com1quality = 0;
|
|
com1volume = 0;
|
|
com1serviceable = 0;
|
|
com1PowerStatus = 0;
|
|
com1Operable = 0;
|
|
}
|
|
|
|
if(property_COM2_Serviceable != nil)
|
|
{
|
|
if(property_COM2_Quality != nil)
|
|
com2quality = property_COM2_Quality.getValue();
|
|
else
|
|
com2quality = 5;
|
|
|
|
com2volume = getRadioVolume(property_COM2_Volume, property_COM2_VolumeSelected);
|
|
|
|
com2serviceable = property_COM1_Serviceable.getValue();
|
|
|
|
if(property_COM2_PowerButton != nil)
|
|
com2PowerStatus = property_COM2_PowerButton.getValue();
|
|
else
|
|
com2PowerStatus = 1;
|
|
|
|
if(property_COM2_Operable != nil)
|
|
com2Operable = property_COM2_Operable.getValue();
|
|
else
|
|
com2Operable = 1;
|
|
}
|
|
else
|
|
{
|
|
com2quality = 0;
|
|
com2volume = 0;
|
|
com2serviceable = 0;
|
|
com2PowerStatus = 0;
|
|
com2Operable = 0;
|
|
}
|
|
|
|
if(property_COM3_Serviceable != nil)
|
|
{
|
|
if(property_COM3_Quality != nil)
|
|
com3quality = property_COM3_Quality.getValue();
|
|
else
|
|
com3quality = 5;
|
|
|
|
com3volume = getRadioVolume(property_COM3_Volume, property_COM3_VolumeSelected);
|
|
|
|
com3serviceable = property_COM3_Serviceable.getValue();
|
|
|
|
if(property_COM3_PowerButton != nil)
|
|
com3PowerStatus = property_COM3_PowerButton.getValue();
|
|
else
|
|
com3PowerStatus = 1;
|
|
|
|
if(property_COM3_Operable != nil)
|
|
com3Operable = property_COM3_Operable.getValue();
|
|
else
|
|
com3Operable = 1;
|
|
}
|
|
else
|
|
{
|
|
com3quality = 0;
|
|
com3volume = 0;
|
|
com3serviceable = 0;
|
|
com3PowerStatus = 0;
|
|
com3Operable = 0;
|
|
}
|
|
|
|
if(com1serviceable == 1 and com1PowerStatus == 1 and com1Operable == 1 and (atcRadioMode == "Auto" or atcRadioMode == "COM1"))
|
|
{
|
|
if(property_COM1_StationName != nil)
|
|
selectedComStationType = getRadioType(property_COM1_StationName.getValue());
|
|
else
|
|
{
|
|
selectedComStationType = radio_station_type_unknown;
|
|
com1serviceable = 0;
|
|
}
|
|
|
|
if(property_COM1_AirportID != nil)
|
|
selectedComAirportId = property_COM1_AirportID.getValue();
|
|
else
|
|
{
|
|
selectedComAirportId = "";
|
|
com1serviceable = 0;
|
|
}
|
|
|
|
if(property_COM1_StationName != nil)
|
|
{
|
|
if(selectedComAirportId != "")
|
|
selectedComStationName = getRadioFullName(selectedComAirportId, property_COM1_StationName.getValue());
|
|
else
|
|
selectedComStationName = property_COM1_StationName.getValue();
|
|
}
|
|
else
|
|
{
|
|
selectedComStationName = "";
|
|
com1serviceable = 0;
|
|
}
|
|
|
|
selectedComFrequency = getRadioFrequency(property_COM1_Frequency, property_COM1_RealFrequency);
|
|
|
|
if(selectedComFrequency <= 0)
|
|
com1serviceable = 0;
|
|
|
|
if(property_COM1_Distance != nil)
|
|
selectedComStationDistance = property_COM1_Distance.getValue();
|
|
else
|
|
{
|
|
selectedComStationDistance = "";
|
|
com1serviceable = 0;
|
|
}
|
|
|
|
if(property_COM1_Bearing != nil)
|
|
selectedComStationBearing = property_COM1_Bearing.getValue();
|
|
else
|
|
{
|
|
selectedComStationBearing = "";
|
|
com1serviceable = 0;
|
|
}
|
|
|
|
if(com1serviceable == 1)
|
|
{
|
|
selectedComRadio = "COM1";
|
|
|
|
selectedComSignalQuality = com1quality;
|
|
selectedComVolume = com1volume;
|
|
selectedComServiceable = com1serviceable;
|
|
selectedComServiceableProperty = property_COM1_Serviceable;
|
|
selectedComPowerStatus = com1PowerStatus;
|
|
selectedComOperable = com1Operable;
|
|
}
|
|
else
|
|
{
|
|
selectedComRadio = "";
|
|
|
|
selectedComServiceableProperty = nil;
|
|
|
|
selectedComSignalQuality = 0;
|
|
}
|
|
}
|
|
else if(com2serviceable == 1 and com2PowerStatus == 1 and com2Operable == 1 and (atcRadioMode == "Auto" or atcRadioMode == "COM2"))
|
|
{
|
|
if(property_COM2_StationName != nil)
|
|
selectedComStationType = getRadioType(property_COM2_StationName.getValue());
|
|
else
|
|
{
|
|
selectedComStationType = radio_station_type_unknown;
|
|
com2serviceable = 0;
|
|
}
|
|
|
|
if(property_COM2_AirportID != nil)
|
|
selectedComAirportId = property_COM2_AirportID.getValue();
|
|
else
|
|
{
|
|
selectedComAirportId = "";
|
|
com2serviceable = 0;
|
|
}
|
|
|
|
if(property_COM2_StationName != nil)
|
|
{
|
|
if(selectedComAirportId != "")
|
|
selectedComStationName = getRadioFullName(selectedComAirportId, property_COM2_StationName.getValue());
|
|
else
|
|
selectedComStationName = property_COM2_StationName.getValue();
|
|
}
|
|
else
|
|
{
|
|
selectedComStationName = "";
|
|
com2serviceable = 0;
|
|
}
|
|
|
|
selectedComFrequency = getRadioFrequency(property_COM2_Frequency, property_COM2_RealFrequency);
|
|
|
|
if(selectedComFrequency <= 0)
|
|
com2serviceable = 0;
|
|
|
|
if(property_COM2_Distance != nil)
|
|
selectedComStationDistance = property_COM2_Distance.getValue();
|
|
else
|
|
{
|
|
selectedComStationDistance = "";
|
|
com2serviceable = 0;
|
|
}
|
|
|
|
if(property_COM2_Bearing != nil)
|
|
selectedComStationBearing = property_COM2_Bearing.getValue();
|
|
else
|
|
{
|
|
selectedComStationBearing = "";
|
|
com2serviceable = 0;
|
|
}
|
|
|
|
if(com2serviceable == 1)
|
|
{
|
|
selectedComRadio = "COM2";
|
|
|
|
selectedComSignalQuality = com2quality;
|
|
selectedComVolume = com2volume;
|
|
selectedComServiceable = com2serviceable;
|
|
selectedComServiceableProperty = property_COM2_Serviceable;
|
|
selectedComPowerStatus = com2PowerStatus;
|
|
selectedComOperable = com2Operable;
|
|
}
|
|
else
|
|
{
|
|
selectedComRadio = "";
|
|
|
|
selectedComServiceableProperty = nil;
|
|
|
|
selectedComSignalQuality = 0;
|
|
}
|
|
}
|
|
else if(com3serviceable == 1 and com3PowerStatus == 1 and com3Operable == 1 and (atcRadioMode == "Auto" or atcRadioMode == "COM3"))
|
|
{
|
|
if(property_COM3_StationName != nil)
|
|
selectedComStationType = getRadioType(property_COM3_StationName.getValue());
|
|
else
|
|
{
|
|
selectedComStationType = radio_station_type_unknown;
|
|
com3serviceable = 0;
|
|
}
|
|
|
|
if(property_COM3_AirportID != nil)
|
|
selectedComAirportId = property_COM3_AirportID.getValue();
|
|
else
|
|
{
|
|
selectedComAirportId = "";
|
|
com3serviceable = 0;
|
|
}
|
|
|
|
if(property_COM3_StationName != nil)
|
|
{
|
|
if(selectedComAirportId != "")
|
|
selectedComStationName = getRadioFullName(selectedComAirportId, property_COM3_StationName.getValue());
|
|
else
|
|
selectedComStationName = property_COM3_StationName.getValue();
|
|
}
|
|
else
|
|
{
|
|
selectedComStationName = "";
|
|
com3serviceable = 0;
|
|
}
|
|
|
|
selectedComFrequency = getRadioFrequency(property_COM3_Frequency, property_COM3_RealFrequency);
|
|
|
|
if(selectedComFrequency <= 0)
|
|
com3serviceable = 0;
|
|
|
|
if(property_COM3_Distance != nil)
|
|
selectedComStationDistance = property_COM3_Distance.getValue();
|
|
else
|
|
{
|
|
selectedComStationDistance = "";
|
|
com3serviceable = 0;
|
|
}
|
|
|
|
if(property_COM3_Bearing != nil)
|
|
selectedComStationBearing = property_COM3_Bearing.getValue();
|
|
else
|
|
{
|
|
selectedComStationBearing = "";
|
|
com3serviceable = 0;
|
|
}
|
|
|
|
if(com3serviceable == 1)
|
|
{
|
|
selectedComRadio = "COM3";
|
|
|
|
selectedComSignalQuality = com3quality;
|
|
selectedComVolume = com3volume;
|
|
selectedComServiceable = com3serviceable;
|
|
selectedComServiceableProperty = property_COM3_Serviceable;
|
|
selectedComPowerStatus = com3PowerStatus;
|
|
selectedComOperable = com3Operable;
|
|
}
|
|
else
|
|
{
|
|
selectedComRadio = "";
|
|
|
|
selectedComServiceableProperty = nil;
|
|
|
|
selectedComSignalQuality = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
selectedComSignalQuality = 0;
|
|
selectedComAirportId = "";
|
|
selectedComStationName = "";
|
|
selectedComFrequency = 0;
|
|
selectedComStationDistance = "";
|
|
selectedComStationBearing = "";
|
|
|
|
if(property_COM1_Serviceable != nil)
|
|
{
|
|
selectedComRadio = "COM1";
|
|
selectedComVolume = com1volume;
|
|
selectedComServiceable = com1serviceable;
|
|
selectedComServiceableProperty = property_COM1_Serviceable;
|
|
selectedComPowerStatus = com1PowerStatus;
|
|
selectedComOperable = com1Operable;
|
|
}
|
|
else
|
|
{
|
|
selectedComRadio = "";
|
|
selectedComVolume = "";
|
|
selectedComServiceable = 0;
|
|
selectedComServiceableProperty = nil;
|
|
selectedComPowerStatus = 0;
|
|
selectedComOperable = 0;
|
|
}
|
|
}
|
|
|
|
if(selectedComStationType != radio_station_type_unknown)
|
|
selectedComStationName = normalizeRadioStationName(selectedComStationName);
|
|
else
|
|
selectedComStationName = atcMessageAction.unknown_radio_type;
|
|
|
|
if(selectedComAirportId == "")
|
|
selectedComAirportId = atcMessageAction.bad_airport_radio;
|
|
|
|
if(selectedComFrequency <= 0)
|
|
selectedComFrequency = 999.99;
|
|
|
|
if(selectedComStationDistance == "")
|
|
selectedComStationDistance = 9999;
|
|
|
|
if(selectedComStationBearing == "")
|
|
selectedComStationBearing = 999;
|
|
|
|
selectedTransponder = getOperatingTransponder();
|
|
|
|
var pos = geo.aircraft_position();
|
|
|
|
var range = min_airport_range;
|
|
|
|
if(currentCtr != nil)
|
|
range += int((currentCtr.range / 1.5) / 10);
|
|
|
|
if(update_mode == update_dialog)
|
|
setCtrButtons();
|
|
|
|
var airport = findAirportsWithinRange(pos, range);
|
|
var altitude = property_Aircraft_AltitudeAglFeet.getValue();
|
|
|
|
if(size(airport) > 0 and aircraft_status != status_requested_approach and aircraft_status != status_requested_ils)
|
|
{
|
|
if(update_mode == update_dialog)
|
|
txtAirport.setText(airport[0].id ~ " " ~ airport[0].name);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= airport[0].id ~ " " ~ airport[0].name ~ "\n";
|
|
|
|
var aPos = getPositionInAirport(airport[0], pos);
|
|
|
|
if(aPos == position_ground)
|
|
{
|
|
aircraftPosition = "Ground";
|
|
|
|
if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
aircraft_status = status_landed;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(welcome_airport_secs);
|
|
}
|
|
else if(aircraft_status != status_landed and aircraft_status != status_cleared_for_takeoff)
|
|
aircraft_status = status_going_around;
|
|
|
|
assignedAltitude = -1;
|
|
}
|
|
else if(aPos == position_flying)
|
|
{
|
|
aircraftPosition = "Flying over";
|
|
airportRunwayInUse = "";
|
|
airportRunwayInUseILS = "";
|
|
|
|
if(aircraft_status == status_cleared_for_takeoff)
|
|
{
|
|
aircraft_status = status_took_off;
|
|
flight_time_seconds = 0;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(wait_after_take_off);
|
|
}
|
|
else if(aircraft_status == status_going_around)
|
|
aircraft_status = status_flying;
|
|
}
|
|
else if(aPos == position_runway)
|
|
aircraftPosition = "Runway " ~ currentRunway;
|
|
else
|
|
aircraftPosition = "???";
|
|
|
|
if(aPos == position_runway)
|
|
{
|
|
atcMessageType[0] = message_none;
|
|
atcMessageType[1] = message_none;
|
|
atcMessageType[2] = message_none;
|
|
atcMessageType[3] = message_none;
|
|
|
|
if(nearRunway == 1)
|
|
{
|
|
aircraftPosition = "Near " ~ aircraftPosition;
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_departure_information;
|
|
|
|
if(aircraft_status == status_cleared_for_takeoff)
|
|
atcMessageType[2] = message_abort_departure;
|
|
else
|
|
atcMessageType[2] = message_ready_for_departure;
|
|
|
|
atcMessageType[3] = message_none;
|
|
}
|
|
else if(alignedOnRunway == 1)
|
|
{
|
|
aircraftPosition ~= " - Aligned";
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_departure_information;
|
|
|
|
if(aircraft_status == status_cleared_for_takeoff)
|
|
atcMessageType[2] = message_abort_departure;
|
|
else
|
|
atcMessageType[2] = message_ready_for_departure;
|
|
|
|
atcMessageType[3] = message_none;
|
|
}
|
|
else
|
|
{
|
|
aircraftPosition = aircraftPosition;
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_departure_information;
|
|
atcMessageType[2] = message_request_taxi;
|
|
|
|
if(aircraft_status == status_cleared_for_takeoff)
|
|
atcMessageType[3] = message_abort_departure;
|
|
else
|
|
atcMessageType[3] = message_ready_for_departure;
|
|
}
|
|
|
|
if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
aircraft_status = status_landed;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(welcome_airport_secs);
|
|
}
|
|
|
|
assignedAltitude = -1;
|
|
}
|
|
else if(aPos == position_flying)
|
|
{
|
|
var approachingRunway = "";
|
|
var distance = -1;
|
|
var degreeDiff = 0;
|
|
var turnToDiff = "";
|
|
var posTag = "";
|
|
var slopeCourseMarker = "";
|
|
|
|
(approachingRunway, distance) = getApproachingRunway(currentAirport);
|
|
|
|
if(approachingRunway != "")
|
|
{
|
|
var course = 0;
|
|
var dist = 0;
|
|
|
|
var alignPoint = geo.Coord.new().set_latlon(currentAirport.runways[approachingRunway].lat, currentAirport.runways[approachingRunway].lon);
|
|
|
|
(course, dist) = courseAndDistance(alignPoint);
|
|
|
|
alignPoint.apply_course_distance(currentAirport.runways[approachingRunway].heading, -(dist * NM2M));
|
|
|
|
(course, dist) = courseAndDistance(alignPoint);
|
|
|
|
(degreeDiff, turnToDiff) = degreesDifference(currentAirport.runways[approachingRunway].heading, course);
|
|
|
|
dist = int(dist * NM2M);
|
|
|
|
slopeCourseMarker = " [";
|
|
altMarker = "";
|
|
|
|
altSlope = altitudeApproachSlope(currentAirport.elevation, distance);
|
|
altitudeFt = property_Aircraft_AltitudeFeet.getValue();
|
|
|
|
altOk = 0;
|
|
crsOk = 0;
|
|
|
|
if(altitudeFt > altSlope)
|
|
{
|
|
altMarker = "v";
|
|
altOk = 0;
|
|
}
|
|
else if(altitudeFt < altSlope)
|
|
{
|
|
altMarker = "^";
|
|
altOk = 0;
|
|
}
|
|
else
|
|
{
|
|
altMarker = "o";
|
|
altOk = 1;
|
|
}
|
|
|
|
if(dist > 3)
|
|
{
|
|
if(dist > 60)
|
|
dist = 60;
|
|
|
|
if(turnToDiff == "left")
|
|
slopeCourseMarker ~= "<";
|
|
else
|
|
slopeCourseMarker ~= altMarker;
|
|
|
|
if(dist > 10)
|
|
{
|
|
for(var n = 0; n < dist; n += 30)
|
|
slopeCourseMarker ~= "=";
|
|
}
|
|
|
|
if(turnToDiff == "right")
|
|
slopeCourseMarker ~= ">";
|
|
else
|
|
slopeCourseMarker ~= altMarker;
|
|
|
|
crsOk = 0;
|
|
}
|
|
else
|
|
{
|
|
slopeCourseMarker ~= altMarker;
|
|
crsOk = 1;
|
|
}
|
|
|
|
if(altOk == 1 and crsOk == 1)
|
|
slopeCourseMarker ~= "ok";
|
|
|
|
slopeCourseMarker ~= "]";
|
|
|
|
aircraftPosition = sprintf("APPR Runway %s%s DST %.1f nm AGL %.1f ft (%.1f m)", approachingRunway, slopeCourseMarker, distance, altitude, altitude * FT2M);
|
|
}
|
|
else
|
|
aircraftPosition = sprintf("Flying over @ AGL %.1f ft (%.1f m)", altitude, altitude * FT2M);
|
|
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airportinfo(selectedComAirportId), runway_landing);
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_request_approach;
|
|
|
|
if(airportRunwayInUseILS != "")
|
|
{
|
|
atcMessageType[2] = message_request_ils;
|
|
atcMessageType[3] = message_airfield_in_sight;
|
|
}
|
|
else
|
|
{
|
|
atcMessageType[2] = message_airfield_in_sight;
|
|
atcMessageType[3] = message_none;
|
|
}
|
|
|
|
if(aircraft_status == status_cleared_for_takeoff)
|
|
{
|
|
aircraft_status = status_took_off;
|
|
flight_time_seconds = 0;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(wait_after_take_off);
|
|
}
|
|
}
|
|
else if(aPos == position_ground)
|
|
{
|
|
var speed = property_Aircraft_GroundSpeedKnots.getValue();
|
|
|
|
aircraftPosition ~= sprintf(" @ %.1f kt (%.1f km/h)", speed, speed * KT2KMH);
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_departure_information;
|
|
atcMessageType[2] = message_engine_start;
|
|
atcMessageType[3] = message_request_taxi;
|
|
}
|
|
|
|
if(airportRunwayInUse != "" and aPos != position_flying)
|
|
aircraftPosition ~= " - Departure runway " ~ airportRunwayInUse;
|
|
|
|
if(update_mode == update_dialog)
|
|
txtAircraftPosition.setText(aircraftPosition);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= aircraftPosition ~ "\n\n";
|
|
|
|
currentAirport = airport[0];
|
|
|
|
if(update_mode == update_dialog)
|
|
{
|
|
btnAvailableRadio.setEnabled(1);
|
|
|
|
if(selectedComAirportId != "" or currentCtr != nil)
|
|
btnRequestCtr.setEnabled(1);
|
|
else
|
|
btnRequestCtr.setEnabled(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var upperText = "";
|
|
var bottomText = "";
|
|
var altitude = property_Aircraft_AltitudeFeet.getValue();
|
|
var airSpeed = property_Aircraft_AirSpeedKnots.getValue();
|
|
|
|
if(patternPoint != nil and approachPoint != nil and (aircraft_status == status_requested_approach or aircraft_status == status_requested_ils))
|
|
{
|
|
var courseToPoint = nil;
|
|
var distanceToPoint = 0;
|
|
|
|
(courseToPoint, distanceToPoint) = courseAndDistance(patternPoint);
|
|
|
|
upperText = sprintf("PTTN: HDG %d%s - DST %.2f nm - ALT %d ft", courseToPoint, degTag, distanceToPoint, altitude);
|
|
|
|
(courseToPoint, distanceToPoint) = courseAndDistance(approachPoint);
|
|
|
|
bottomText = sprintf("APPR: HDG %d%s - DST %.2f nm - IAS %d kt - Runway %s", courseToPoint, degTag, distanceToPoint, airSpeed, airportLandingRunway);
|
|
}
|
|
else
|
|
{
|
|
var agl = property_Aircraft_AltitudeAglFeet.getValue();
|
|
var heading = property_Aircraft_HeadingDeg.getValue();
|
|
var groundSpeed = property_Aircraft_GroundSpeedKnots.getValue();
|
|
var mach = property_Aircraft_MachSpeed.getValue();
|
|
|
|
upperText = sprintf("ALT %d ft (%d m) - AGL %d ft (%d m) - HDG %d%s", altitude, altitude * FT2M, agl, agl * FT2M, heading, degTag);
|
|
bottomText = sprintf("IAS %d kt (%d km/h) - SPD %d kt (%d km/h) - Mach %.2f", airSpeed, airSpeed * KT2KMH, groundSpeed, groundSpeed * 1.852, mach);
|
|
}
|
|
|
|
if(update_mode == update_dialog)
|
|
{
|
|
if(txtAirport != nil)
|
|
txtAirport.setText(upperText);
|
|
|
|
if(txtAircraftPosition != nil)
|
|
txtAircraftPosition.setText(bottomText);
|
|
}
|
|
else if(update_mode == update_popup)
|
|
popupText ~= upperText ~ "\n" ~ bottomText ~ "\n\n";
|
|
|
|
currentAirport = nil;
|
|
}
|
|
|
|
if(currentCtr != nil)
|
|
{
|
|
if(currentCtr.status != ctr_status_outside)
|
|
{
|
|
var frequency = 0;
|
|
var ctrDistance = 0;
|
|
var ctrStatus = "";
|
|
|
|
txt = sprintf("CTR: %s %s", currentCtr.ident, currentCtr.airport);
|
|
|
|
if(update_mode == update_dialog)
|
|
txtCurrentCtr.setText(txt);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= txt ~ "\n";
|
|
|
|
var radio = getCtrRadio(currentCtr);
|
|
|
|
if(radio != nil)
|
|
frequency = radio.frequency;
|
|
else
|
|
frequency = 0;
|
|
|
|
if(currentCtr.status == ctr_status_inside)
|
|
{
|
|
ctrDistance = currentCtr.distance;
|
|
|
|
if(approvedCtr != nil and approvedCtr.ident == currentCtr.ident)
|
|
ctrStatus = "Approved";
|
|
else
|
|
ctrStatus = "Inside";
|
|
}
|
|
else if(currentCtr.status == ctr_status_in_range)
|
|
{
|
|
ctrDistance = currentCtr.distance_from_range;
|
|
ctrStatus = "Flying to";
|
|
}
|
|
|
|
txt = sprintf("RNG %d nm DST %.2f nm CRS %d%s - %.3f MHz - %s", currentCtr.range, ctrDistance, currentCtr.course, degTag, frequency, ctrStatus);
|
|
|
|
if(update_mode == update_dialog)
|
|
txtCurrentCtrSpecs.setText(txt);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= txt ~ "\n\n";
|
|
}
|
|
else
|
|
{
|
|
if(update_mode == update_dialog)
|
|
{
|
|
txtCurrentCtr.setText("CTR: --");
|
|
txtCurrentCtrSpecs.setText("--");
|
|
}
|
|
else if(update_mode == update_popup)
|
|
popupText ~= "\nCTR: --\n\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(update_mode == update_dialog)
|
|
{
|
|
txtCurrentCtr.setText("CTR: --");
|
|
txtCurrentCtrSpecs.setText("--");
|
|
}
|
|
else if(update_mode == update_popup)
|
|
popupText ~= "\nCTR: --\n\n";
|
|
}
|
|
|
|
var aircraftPosition = "";
|
|
|
|
if(radioSignalQuality() > 0 and selectedComVolume >= 0.1)
|
|
{
|
|
if(btnAvailableRadio != nil)
|
|
btnAvailableRadio.setEnabled(1);
|
|
|
|
if(selectedComAirportId != currentRadioStationId)
|
|
{
|
|
getAvailableRadios();
|
|
|
|
radioListHasChanged = 1;
|
|
|
|
currentRadioStationId = selectedComAirportId;
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(1);
|
|
|
|
showRepeatATCMessageButton(0);
|
|
}
|
|
|
|
if(altitude > min_ground_altitude)
|
|
{
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airportinfo(selectedComAirportId), runway_landing);
|
|
|
|
atcMessageType[0] = message_radio_check;
|
|
atcMessageType[1] = message_request_approach;
|
|
|
|
if(aircraft_status == status_requested_ils or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
atcMessageType[2] = message_request_ils;
|
|
atcMessageType[3] = message_ils_established;
|
|
}
|
|
else
|
|
{
|
|
if(airportRunwayInUseILS != "")
|
|
{
|
|
atcMessageType[2] = message_request_ils;
|
|
atcMessageType[3] = message_airfield_in_sight;
|
|
}
|
|
else
|
|
{
|
|
atcMessageType[2] = message_airfield_in_sight;
|
|
atcMessageType[3] = message_none;
|
|
}
|
|
}
|
|
}
|
|
|
|
txt = sprintf("%s: %s %s", selectedComRadio, selectedComAirportId, selectedComStationName);
|
|
|
|
if(update_mode == update_dialog)
|
|
txtCurrentRadio.setText(txt);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= txt ~ "\n";
|
|
|
|
txt = sprintf("%.3f MHz - Distance: %.2f nm @ %d%s - Quality: %d", selectedComFrequency, selectedComStationDistance * M2NM , int(selectedComStationBearing), degTag, radioSignalQuality());
|
|
|
|
if(update_mode == update_dialog)
|
|
txtCurrentRadioSpecs.setText(txt);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= txt ~ "\n";
|
|
|
|
if(update_mode == update_dialog)
|
|
{
|
|
var wh = dialogHeight;
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
for(var i = 0; i < size(atcMessageType); i += 1)
|
|
{
|
|
if(atcMessageType[i] != message_none)
|
|
{
|
|
wh += 32;
|
|
|
|
var btnTag = getMessageText(atcMessageType[i]);
|
|
|
|
if(btnTag != "")
|
|
{
|
|
btnMessage[i].setText(btnTag);
|
|
|
|
btnMessage[i].show();
|
|
}
|
|
}
|
|
else
|
|
btnMessage[i].hide();
|
|
}
|
|
|
|
if(radioListHasChanged == 1)
|
|
{
|
|
radioBox.show();
|
|
|
|
updateRadioList();
|
|
|
|
radioListHasChanged = 0;
|
|
|
|
showRepeatATCMessageButton(0);
|
|
}
|
|
|
|
radioBox.show();
|
|
|
|
if(aircraft_status == status_flying)
|
|
{
|
|
if(flightLevel1 >= minCruiseAltidude)
|
|
{
|
|
btnRequestFlightLevel1.setText("FL" ~ getFlightLevelCode(flightLevel1));
|
|
btnRequestFlightLevel1.setEnabled(1);
|
|
}
|
|
else
|
|
{
|
|
btnRequestFlightLevel1.setText("--");
|
|
btnRequestFlightLevel1.setEnabled(0);
|
|
}
|
|
|
|
if(flightLevel2 >= minCruiseAltidude)
|
|
{
|
|
btnRequestFlightLevel2.setText("FL" ~ getFlightLevelCode(flightLevel2));
|
|
btnRequestFlightLevel2.setEnabled(1);
|
|
}
|
|
else
|
|
{
|
|
btnRequestFlightLevel2.setText("--");
|
|
btnRequestFlightLevel2.setEnabled(0);
|
|
}
|
|
|
|
if(flightLevel3 >= minCruiseAltidude and flightLevel3 != flightLevel2)
|
|
{
|
|
btnRequestFlightLevel3.setText("FL" ~ getFlightLevelCode(flightLevel3));
|
|
btnRequestFlightLevel3.setEnabled(1);
|
|
}
|
|
else
|
|
{
|
|
btnRequestFlightLevel3.setText("--");
|
|
btnRequestFlightLevel3.setEnabled(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
btnRequestFlightLevel1.setText("--");
|
|
btnRequestFlightLevel1.setEnabled(0);
|
|
|
|
btnRequestFlightLevel2.setText("--");
|
|
btnRequestFlightLevel2.setEnabled(0);
|
|
|
|
btnRequestFlightLevel3.setText("--");
|
|
btnRequestFlightLevel3.setEnabled(0);
|
|
}
|
|
|
|
if(dialogInitialized == 1 and dialogOpened == 1 and dlgWindow != nil)
|
|
dlgWindow.setSize(dialogWidth, wh);
|
|
}
|
|
else if(update_mode == update_popup)
|
|
{
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
for(var i = 0; i < size(atcMessageType); i += 1)
|
|
{
|
|
if(atcMessageType[i] != message_none)
|
|
popupText ~= sprintf("\n<ctrl+%d> %s", i+4, getMessageText(atcMessageType[i]));
|
|
}
|
|
|
|
if(lastAtcText != "" or lastAtcVoice != "")
|
|
popupText ~= "\n<ctrl+9> Repeat last ATC message";
|
|
|
|
popupText ~= "\n<ctrl+0> Request CTR";
|
|
|
|
if(aircraft_status == status_flying)
|
|
{
|
|
popupText ~= "\n";
|
|
|
|
if(flightLevel1 >= minCruiseAltidude)
|
|
popupText ~= "<ctrl+shift+4> Request FL" ~ getFlightLevelCode(flightLevel1) ~ "\n";
|
|
|
|
if(flightLevel2 >= minCruiseAltidude)
|
|
popupText ~= "<ctrl+shift+5> Request FL" ~ getFlightLevelCode(flightLevel2) ~ "\n";
|
|
|
|
if(flightLevel3 >= minCruiseAltidude and flightLevel3 != flightLevel2)
|
|
popupText ~= "<ctrl+shift+6> Request FL" ~ getFlightLevelCode(flightLevel3) ~ "\n";
|
|
}
|
|
else if(aircraft_status == status_requested_approach)
|
|
popupText ~= "\n<ctrl+shift+0> Abort Approach";
|
|
else if(aircraft_status == status_requested_ils)
|
|
popupText ~= "\n<ctrl+shift+0> Abort ILS";
|
|
else if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
popupText ~= "\n<ctrl+shift+0> Abort Landing";
|
|
|
|
showPopup(popupText);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(selectedComServiceableProperty == nil)
|
|
txt = atcMessageAction.bad_radio_data;
|
|
else if(selectedComServiceable == 0 or selectedComPowerStatus == 0 or selectedComOperable == 0)
|
|
txt = atcMessageAction.turn_radio_on;
|
|
else if(selectedComVolume < 0.1)
|
|
{
|
|
if(selectedComRadio != "")
|
|
txt = selectedComRadio ~ ": ";
|
|
else
|
|
txt = "";
|
|
|
|
txt ~= atcMessageAction.radio_volume_up;
|
|
}
|
|
else if(radioSignalQuality() == 0)
|
|
{
|
|
if(selectedComRadio != "")
|
|
txt = selectedComRadio ~ ": ";
|
|
else
|
|
txt = "";
|
|
|
|
txt ~= atcMessageAction.no_radio_tuned;
|
|
}
|
|
else
|
|
txt = atcMessageAction.bad_radio_data;
|
|
|
|
if(update_mode == update_dialog)
|
|
txtCurrentRadio.setText(txt);
|
|
else if(update_mode == update_popup)
|
|
popupText ~= txt ~ "\n";
|
|
|
|
if(update_mode == update_dialog)
|
|
{
|
|
txtCurrentRadioSpecs.setText("--");
|
|
|
|
btnRequestFlightLevel1.setText("--");
|
|
btnRequestFlightLevel1.setEnabled(0);
|
|
|
|
btnRequestFlightLevel2.setText("--");
|
|
btnRequestFlightLevel2.setEnabled(0);
|
|
|
|
btnRequestFlightLevel3.setText("--");
|
|
btnRequestFlightLevel3.setEnabled(0);
|
|
}
|
|
|
|
selectedComStationType = radio_station_type_unknown;
|
|
|
|
if(update_mode == update_dialog)
|
|
clearATCButtons();
|
|
else if(update_mode == update_popup)
|
|
showPopup(popupText);
|
|
|
|
if(radioBox != nil)
|
|
radioBox.hide();
|
|
|
|
getAvailableRadios();
|
|
|
|
radioListHasChanged = 1;
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(1);
|
|
|
|
showRepeatATCMessageButton(0);
|
|
}
|
|
|
|
if(dialogInitialized == 1 and dialogOpened == 1 and dlgWindow != nil)
|
|
dlgWindow.clearFocus();
|
|
|
|
if(atcLogOpened == 1 and atcLogWindow != nil)
|
|
atcLogWindow.clearFocus();
|
|
}
|
|
|
|
var getPositionInAirport = func(airport, pos)
|
|
{
|
|
var distance = 9999;
|
|
var course = 0;
|
|
var dist = 0;
|
|
var runwayPos = 0;
|
|
var position = position_ground;
|
|
var degreeDiff = 360;
|
|
var turnToDiff = "";
|
|
|
|
currentRunway = "";
|
|
alignedOnRunway = 0;
|
|
nearRunway = 0;
|
|
|
|
if(airport == nil)
|
|
return position_unknown;
|
|
|
|
if(property_Aircraft_AltitudeAglFeet.getValue() > min_ground_altitude)
|
|
return position_flying;
|
|
|
|
if(size(airport.runways) > 0)
|
|
{
|
|
var aircraftHeading = property_Aircraft_HeadingDeg.getValue();
|
|
|
|
foreach(var runway; keys(airport.runways))
|
|
{
|
|
min_distance = airport.runways[runway].width * 1.5;
|
|
min_near_distance = min_distance + airport.runways[runway].width * 2;
|
|
var angleDeviation = abs(airport.runways[runway].heading - aircraftHeading);
|
|
|
|
runwayPos = geo.Coord.new().set_latlon(airport.runways[runway].lat, airport.runways[runway].lon);
|
|
runwayLength = airport.runways[runway].length;
|
|
|
|
if(airport.runways[runway].stopway > 0)
|
|
{
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].stopway);
|
|
runwayLength += airport.runways[runway].stopway;
|
|
}
|
|
|
|
if(airport.runways[runway].threshold > 0)
|
|
{
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].threshold);
|
|
runwayLength += airport.runways[runway].threshold;
|
|
}
|
|
|
|
if(airport.runways[runway].reciprocal.stopway > 0)
|
|
{
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].reciprocal.stopway);
|
|
runwayLength += airport.runways[runway].reciprocal.stopway;
|
|
}
|
|
|
|
if(airport.runways[runway].reciprocal.threshold > 0)
|
|
{
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].reciprocal.threshold);
|
|
runwayLength += airport.runways[runway].reciprocal.threshold;
|
|
}
|
|
|
|
dist = minPathDistance(pos, runwayPos, airport.runways[runway].heading, runwayLength / 2, min_distance);
|
|
|
|
if(dist < min_near_distance)
|
|
{
|
|
position = position_runway;
|
|
currentRunway = runway;
|
|
nearRunway = 1;
|
|
}
|
|
|
|
if(dist < min_distance and dist < distance)
|
|
{
|
|
distance = dist;
|
|
position = position_runway;
|
|
currentRunway = runway;
|
|
nearRunway = 0;
|
|
}
|
|
}
|
|
|
|
if(position == position_runway)
|
|
{
|
|
(degreeDiff, turnToDiff) = degreesDifference(aircraftHeading, airport.runways[currentRunway].heading);
|
|
|
|
if(degreeDiff < max_runway_alignment_degrees)
|
|
alignedOnRunway = 1;
|
|
else
|
|
alignedOnRunway = 0;
|
|
}
|
|
}
|
|
|
|
return position;
|
|
}
|
|
|
|
var runwayInUse = func(airport, runway_type)
|
|
{
|
|
var degreesBest = 360;
|
|
var lengthBest = 0;
|
|
var degreeDiff = 360;
|
|
var turnToDiff = "";
|
|
|
|
var windDirection = 0;
|
|
|
|
if(isRealMeteoEnabled() == 1)
|
|
{
|
|
if(property_Weather_Metar_WindDirectionDeg != nil)
|
|
windDirection = property_Weather_Metar_WindDirectionDeg.getValue();
|
|
else
|
|
windDirection = 0;
|
|
}
|
|
else
|
|
{
|
|
if(property_Weather_WindDirectionDeg != nil)
|
|
windDirection = property_Weather_WindDirectionDeg.getValue();
|
|
else
|
|
windDirection = 0;
|
|
}
|
|
|
|
var atcRunway = property_AtcRunway.getValue();
|
|
|
|
if(airport == nil)
|
|
return ["", nil];
|
|
|
|
airportRunway = "";
|
|
airportRunwayILS = "";
|
|
|
|
if(property_Autopilot_RouteManagerActive.getValue() and property_Autopilot_RouteManagerDepartureRunway.getValue() != "" and runway_type == runway_take_off)
|
|
{
|
|
airportRunway = property_Autopilot_RouteManagerDepartureRunway.getValue();
|
|
}
|
|
else if(atcRunway != "" and airport.runways[atcRunway] != nil)
|
|
{
|
|
airportRunway = atcRunway;
|
|
|
|
if(airport.runways[airportRunway].ils_frequency_mhz != nil)
|
|
airportRunwayILS = airport.runways[airportRunway].id;
|
|
}
|
|
else
|
|
{
|
|
foreach(var runway; keys(airport.runways))
|
|
{
|
|
var runwayDeg = airport.runways[runway].heading;
|
|
(degreeDiff, turnToDiff) = degreesDifference(runwayDeg, windDirection);
|
|
|
|
if(degreeDiff < degreesBest or (degreeDiff == degreesBest and airport.runways[runway].length > lengthBest))
|
|
{
|
|
airportRunway = airport.runways[runway].id;
|
|
|
|
degreesBest = degreeDiff;
|
|
|
|
lengthBest = airport.runways[runway].length;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(airportRunwayILS == "")
|
|
{
|
|
degreesBest = 360;
|
|
lengthBest = 0;
|
|
degreeDiff = 360;
|
|
|
|
foreach(var runway; keys(airport.runways))
|
|
{
|
|
var runwayDeg = airport.runways[runway].heading;
|
|
(degreeDiff, turnToDiff) = degreesDifference(runwayDeg, windDirection);
|
|
|
|
if(airport.runways[runway].ils_frequency_mhz != nil and (degreeDiff < degreesBest or (degreeDiff == degreesBest and airport.runways[runway].length > lengthBest)))
|
|
{
|
|
airportRunwayILS = airport.runways[runway].id;
|
|
|
|
degreesBest = degreeDiff;
|
|
|
|
lengthBest = airport.runways[runway].length;
|
|
}
|
|
}
|
|
}
|
|
|
|
return [airportRunway, airportRunwayILS];
|
|
}
|
|
|
|
var getApproachingRunway = func(airport)
|
|
{
|
|
var degreesBest = 360;
|
|
var lengthBest = 0;
|
|
var heading = property_Aircraft_HeadingDeg.getValue();
|
|
var approachingRunway = "";
|
|
var distance = 9999;
|
|
var degreeDiff = 0;
|
|
var turnToDiff = "";
|
|
var runwayPos = nil;
|
|
var runwayVector = nil;
|
|
|
|
if(airport == nil)
|
|
return ["", 0];
|
|
|
|
foreach(var runway; keys(airport.runways))
|
|
{
|
|
if(courseWithinDegrees(heading, airport.runways[runway].heading, max_runway_align_angle) == 1)
|
|
{
|
|
runwayPos = geo.Coord.new().set_latlon(airport.runways[runway].lat, airport.runways[runway].lon);
|
|
|
|
if(airport.runways[runway].stopway > 0)
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].stopway);
|
|
|
|
if(airport.runways[runway].threshold > 0)
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].threshold);
|
|
|
|
if(airport.runways[runway].reciprocal.stopway > 0)
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].reciprocal.stopway);
|
|
|
|
if(airport.runways[runway].reciprocal.threshold > 0)
|
|
runwayPos.apply_course_distance(airport.runways[runway].heading, -airport.runways[runway].reciprocal.threshold);
|
|
|
|
(course, dist) = courseAndDistance(runwayPos);
|
|
|
|
if(courseWithinDegrees(heading, course, max_runway_align_angle) == 1)
|
|
{
|
|
runwayVector = runwayPos;
|
|
|
|
runwayVector.apply_course_distance(airport.runways[runway].heading, -(dist * NM2M));
|
|
|
|
(courseVector, distVector) = courseAndDistance(runwayVector);
|
|
|
|
if(distVector < distance)
|
|
{
|
|
distance = distVector;
|
|
|
|
approachingRunway = runway;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return [approachingRunway, distance];
|
|
}
|
|
|
|
var clearATCButtons = func()
|
|
{
|
|
if(btnMessage[0] == nil)
|
|
return;
|
|
|
|
btnMessage[0].hide();
|
|
btnMessage[1].hide();
|
|
btnMessage[2].hide();
|
|
btnMessage[3].hide();
|
|
|
|
if(dialogInitialized == 1 and dialogOpened == 1 and dlgWindow != nil)
|
|
dlgWindow.setSize(dialogWidth, dialogHeight);
|
|
}
|
|
|
|
var showRepeatATCMessageButton = func(enable)
|
|
{
|
|
var w = (dialogWidth / 2) - 20;
|
|
|
|
if(btnRepeatATCMessage != nil)
|
|
{
|
|
if(enable == 1)
|
|
{
|
|
btnRepeatATCMessage.show();
|
|
|
|
w = (dialogWidth / 2) - 28 - repeatBtnWidth;
|
|
}
|
|
else
|
|
{
|
|
lastAtcText = "";
|
|
lastAtcVoice = "";
|
|
|
|
btnRepeatATCMessage.hide();
|
|
}
|
|
}
|
|
|
|
if(btnMessage[0] != nil)
|
|
btnMessage[0].setFixedSize(w, 26);
|
|
}
|
|
|
|
var availableRadioDialog = func()
|
|
{
|
|
if(size(availableRadio) == 0)
|
|
{
|
|
showPopup(RGAtcName ~ ": " ~ atcMessageAction.no_radio_available ~ ".");
|
|
|
|
return;
|
|
}
|
|
|
|
if(selectedComStationType != radio_station_type_unknown and selectedComAirportId != "")
|
|
airport = airportinfo(selectedComAirportId);
|
|
else if(currentAirport != nil)
|
|
airport = currentAirport;
|
|
else
|
|
{
|
|
showPopup(RGAtcName ~ ": " ~ atcMessageAction.no_radio_available ~ ".");
|
|
|
|
return;
|
|
}
|
|
|
|
var h = (size(availableRadio) * 14) + 120;
|
|
|
|
var (width, height) = (320, h);
|
|
|
|
var radioWindow = canvas.Window.new([width,height], "dialog")
|
|
.setTitle(RGAtcName ~ ": Available Radios");
|
|
|
|
var radioCanvas = radioWindow.createCanvas().set("background", canvas.style.getColor("bg_color"));
|
|
radioCanvas.setColorBackground(0.4, 0.4, 0.4, 0.9);
|
|
|
|
var radioRoot = radioCanvas.createGroup();
|
|
|
|
var radioLayout = canvas.VBoxLayout.new();
|
|
|
|
radioCanvas.setLayout(radioLayout);
|
|
|
|
var btnRadioClose = canvas.gui.widgets.Button.new(radioRoot, canvas.style, {})
|
|
.setText("Close")
|
|
.setFixedSize(75, 26);
|
|
|
|
btnRadioClose.listen("clicked", func
|
|
{
|
|
radioWindow.hide();
|
|
});
|
|
|
|
radioLayout.addStretch(1);
|
|
radioLayout.addItem(btnRadioClose);
|
|
|
|
var txtAirport = radioRoot.createChild("text")
|
|
.setText(airport.name)
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1, 1, 1, 1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 20);
|
|
|
|
var txtComTitle = radioRoot.createChild("text")
|
|
.setText("Communication Radios")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1, 1, 0, 1)
|
|
.setAlignment("left-center")
|
|
.setTranslation(10, 48);
|
|
|
|
var txtRadios = radioRoot.createChild("text")
|
|
.setText("")
|
|
.setFont("LiberationFonts/LiberationSans-Bold.ttf")
|
|
.setFontSize(14, 0.9)
|
|
.setColor(1, 1, 1, 1)
|
|
.setAlignment("left")
|
|
.setTranslation(10, 88);
|
|
|
|
var radioDesc = "";
|
|
var i = 0;
|
|
|
|
for(i = 0; i < size(availableRadio); i += 1)
|
|
{
|
|
var radio = availableRadio[i];
|
|
|
|
radioDesc ~= sprintf("%s: %.3f MHz\n", radio.ident, radio.frequency);
|
|
}
|
|
|
|
txtRadios.setText(radioDesc);
|
|
|
|
radioWindow.raise(1);
|
|
|
|
radioWindow.clearFocus();
|
|
}
|
|
|
|
var updateRadioList = func()
|
|
{
|
|
var vndx = 0;
|
|
var voiceIsValid = 0;
|
|
|
|
getAvailableRadios();
|
|
|
|
numRadios = size(availableRadio);
|
|
|
|
if(numRadios == 0)
|
|
return;
|
|
|
|
stationVoice = {};
|
|
|
|
radioList = canvas.VBoxLayout.new();
|
|
|
|
for(var i = 0; i < numRadios; i += 1)
|
|
{
|
|
var radio = availableRadio[i];
|
|
|
|
radioButton[i] = canvas.gui.widgets.Button.new(radioScrollContent, canvas.style, {})
|
|
.setText(sprintf("%s: %.3f MHz", radio.ident, radio.frequency))
|
|
.setFixedSize((dialogWidth / 2) - 4, 24);
|
|
|
|
radioButton[i].show();
|
|
|
|
radioButtonFrequency[i] = radio.frequency;
|
|
|
|
radioList.addItem(radioButton[i]);
|
|
|
|
stationVoice[radio.frequency] = getSynthVoice(radio.frequency);
|
|
}
|
|
|
|
radioList.addStretch(1);
|
|
|
|
radioScroll.setLayout(radioList);
|
|
|
|
for(; i < max_radios; i += 1)
|
|
{
|
|
if(radioButton[i] != nil)
|
|
{
|
|
radioButton[i].hide();
|
|
radioButton[i] = nil;
|
|
}
|
|
}
|
|
|
|
if(numRadios > 0)
|
|
{
|
|
radioButton[0].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[0]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 1)
|
|
{
|
|
radioButton[1].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[1]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 2)
|
|
{
|
|
radioButton[2].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[2]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 3)
|
|
{
|
|
radioButton[3].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[3]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 4)
|
|
{
|
|
radioButton[4].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[4]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 5)
|
|
{
|
|
radioButton[5].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[5]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 6)
|
|
{
|
|
radioButton[6].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[6]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 7)
|
|
{
|
|
radioButton[7].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[7]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 8)
|
|
{
|
|
radioButton[8].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[8]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 9)
|
|
{
|
|
radioButton[9].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[9]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 10)
|
|
{
|
|
radioButton[10].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[10]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 11)
|
|
{
|
|
radioButton[11].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[11]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 12)
|
|
{
|
|
radioButton[12].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[12]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 13)
|
|
{
|
|
radioButton[13].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[13]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 14)
|
|
{
|
|
radioButton[14].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[14]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 15)
|
|
{
|
|
radioButton[15].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[15]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 16)
|
|
{
|
|
radioButton[16].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[16]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 17)
|
|
{
|
|
radioButton[17].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[17]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 18)
|
|
{
|
|
radioButton[18].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[18]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 19)
|
|
{
|
|
radioButton[19].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[19]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 20)
|
|
{
|
|
radioButton[20].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[20]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 21)
|
|
{
|
|
radioButton[21].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[21]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 22)
|
|
{
|
|
radioButton[22].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[22]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 23)
|
|
{
|
|
radioButton[23].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[23]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 24)
|
|
{
|
|
radioButton[24].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[24]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 25)
|
|
{
|
|
radioButton[25].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[25]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 26)
|
|
{
|
|
radioButton[26].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[26]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 27)
|
|
{
|
|
radioButton[27].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[27]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 28)
|
|
{
|
|
radioButton[28].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[28]);
|
|
});
|
|
}
|
|
|
|
if(numRadios > 29)
|
|
{
|
|
radioButton[29].listen("clicked", func()
|
|
{
|
|
setCurrentComRadioFrequency(radioButtonFrequency[29]);
|
|
});
|
|
}
|
|
}
|
|
|
|
var setCurrentComRadioFrequency = func(frequency)
|
|
{
|
|
if(selectedComRadio == "COM1")
|
|
{
|
|
if(property_COM1_RealFrequency != nil)
|
|
property_COM1_RealFrequency.setValue(frequency);
|
|
|
|
if(property_COM1_Frequency != nil)
|
|
property_COM1_Frequency.setValue(frequency);
|
|
}
|
|
else if(selectedComRadio == "COM2")
|
|
{
|
|
if(property_COM2_RealFrequency != nil)
|
|
property_COM2_RealFrequency.setValue(frequency);
|
|
|
|
if(property_COM2_Frequency != nil)
|
|
property_COM2_Frequency.setValue(frequency);
|
|
}
|
|
else if(selectedComRadio == "COM3")
|
|
{
|
|
if(property_COM3_RealFrequency != nil)
|
|
property_COM3_RealFrequency.setValue(frequency);
|
|
|
|
if(property_COM3_Frequency != nil)
|
|
property_COM3_Frequency.setValue(frequency);
|
|
}
|
|
|
|
if(dialogInitialized == 1 and dialogOpened == 1 and dlgWindow != nil)
|
|
{
|
|
dlgWindow.clearFocus();
|
|
|
|
showRepeatATCMessageButton(0);
|
|
}
|
|
}
|
|
|
|
var showPopup = func(text)
|
|
{
|
|
var window = screen.window.new(atc_popup_x_position, atc_popup_y_position, 20, 8);
|
|
|
|
window.bg = popup_window_bg_color;
|
|
window.fg = popup_window_fg_atc_color;
|
|
window.align = atc_popup_align;
|
|
|
|
window.write(text);
|
|
}
|
|
|
|
var atcReplyToRequest = func(messageType)
|
|
{
|
|
var text = "";
|
|
var voice = "";
|
|
var signal = -1;
|
|
var extraText = "";
|
|
var extraVoice = "";
|
|
var towerContactText = "";
|
|
var towerContactVoice = "";
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
if(isRadioServiceable() == 0)
|
|
return;
|
|
|
|
if(messageType == message_none or selectedComAirportId == "")
|
|
return;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(0);
|
|
|
|
if(messageType == message_say_again)
|
|
{
|
|
if(lastAtcText == "" and lastAtcVoice == "")
|
|
return;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = lastAtcText;
|
|
|
|
voice = lastAtcVoice;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
else if(messageType == message_radio_check)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
signal = radioSignalQuality();
|
|
|
|
var atisRadio = getRadio(radio_station_type_atis, radio_type_exact_match);
|
|
|
|
if(atisRadio != nil)
|
|
{
|
|
extraText = sprintf(atcMessageReply.radio_available_at,
|
|
"\nATIS",
|
|
sprintf("%.3f", atisRadio.frequency)
|
|
);
|
|
|
|
extraVoice = sprintf(atcMessageReply.radio_available_at,
|
|
"\nA T I S",
|
|
spellToPhonetic(sprintf("%.3f", atisRadio.frequency), spell_number)
|
|
);
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.radio_check,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
sprintf("%d", signal),
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.radio_check,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(sprintf("%d", signal), spell_number),
|
|
extraVoice
|
|
);
|
|
|
|
pilotResponseType = message_none;
|
|
}
|
|
else if(messageType == message_request_ctr)
|
|
{
|
|
var ctrData = getCtrData(airportinfo(selectedComAirportId));
|
|
var radio = nil;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(getCtrData != nil)
|
|
{
|
|
radio = getCtrRadio(ctrData);
|
|
|
|
if(radio != nil)
|
|
{
|
|
if(approvedCtr != nil and approvedCtr.ident == ctrData.ident)
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_already_approved);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
else if(ctrData.status == ctr_status_in_range or ctrData.status == ctr_status_inside)
|
|
{
|
|
if(selectedComAirportId == ctrData.ident and selectedComFrequency == radio.frequency)
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_approved);
|
|
|
|
currentCtr = ctrData;
|
|
approvedCtr = ctrData;
|
|
ctr_leaving_warning = 0;
|
|
altitude_check_counter = 0;
|
|
|
|
altitude_change_wait_seconds = int(rand() * max_altitude_change_secs) + min_altitude_change_secs;
|
|
assignedAltitude = -1;
|
|
aircraftIsDeparting = 0;
|
|
|
|
resetAircraftStatus();
|
|
|
|
pilotResponseType = message_ctr_approved;
|
|
}
|
|
else
|
|
{
|
|
text = sprintf("%s, %s, ",
|
|
atcCallsignText,
|
|
selectedComStationName
|
|
);
|
|
|
|
voice = sprintf("%s, %s, ",
|
|
atcCallsignVoice,
|
|
selectedComStationName
|
|
);
|
|
|
|
text ~= sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
sprintf("%.3f", radio.frequency)
|
|
);
|
|
|
|
voice ~= sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
spellToPhonetic(sprintf("%.3f", radio.frequency), spell_number)
|
|
);
|
|
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
}
|
|
else if(messageType == message_engine_start)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_ground) == 0)
|
|
return;
|
|
|
|
var airport = "";
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(selectedComAirportId == property_ClosestAirportId.getValue())
|
|
{
|
|
airport = airportinfo(selectedComAirportId);
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airport, runway_take_off);
|
|
|
|
(qnhValue, qnhLiteralValue) = getQNH();
|
|
|
|
text = sprintf(atcMessageReply.engine_start,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse,
|
|
"QNH",
|
|
qnhValue
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.engine_start,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway),
|
|
"Q N H",
|
|
qnhLiteralValue
|
|
);
|
|
|
|
aircraftIsDeparting = 1;
|
|
|
|
pilotResponseType = message_engine_start;
|
|
}
|
|
else
|
|
{
|
|
reason = " ";
|
|
|
|
if(rand() < 0.5)
|
|
reason ~= atcMessageAction.unable_approve;
|
|
else
|
|
reason ~= atcMessageAction.negative;
|
|
|
|
reason ~= " " ~ atcMessageAction.startup ~ ".";
|
|
|
|
text = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_departure_information)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_ground) == 0)
|
|
return;
|
|
|
|
var airport = "";
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(selectedComAirportId == property_ClosestAirportId.getValue())
|
|
{
|
|
airport = airportinfo(selectedComAirportId);
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airport, runway_take_off);
|
|
var currentTime = substr(property_TimeGmtString.getValue(), 0, 5) ~ "Z";
|
|
|
|
if(selectedComAirportId != departureInformationAirport)
|
|
{
|
|
departureInformationAirport = selectedComAirportId;
|
|
|
|
letter = chr(int(rand() * (size(phoneticLetter) - 1)) + 65);
|
|
|
|
departureInformation = phoneticLetter[letter];
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.departure_information,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse,
|
|
getMeteoText(meteo_type_full, 0),
|
|
currentTime,
|
|
departureInformation
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.departure_information,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway),
|
|
getMeteoText(meteo_type_full, 1),
|
|
spellToPhonetic(currentTime, spell_number),
|
|
departureInformation
|
|
);
|
|
|
|
pilotResponseType = message_departure_information;
|
|
|
|
aircraftIsDeparting = 1;
|
|
}
|
|
else
|
|
{
|
|
text = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
""
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
""
|
|
);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_request_taxi)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_ground) == 0)
|
|
return;
|
|
|
|
var airport = "";
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(selectedComAirportId == property_ClosestAirportId.getValue())
|
|
{
|
|
var towerRadio = getRadio(radio_station_type_tower, radio_type_any);
|
|
var reportTag = "";
|
|
var reportVoice = "";
|
|
|
|
if(towerRadio == nil)
|
|
{
|
|
showPopup(RGAtcName ~ ": " ~ atcMessageAction.tower_not_reachable ~ ".");
|
|
|
|
return;
|
|
}
|
|
|
|
if(selectedComFrequency == towerRadio.frequency)
|
|
{
|
|
reportTag = atcMessageReply.report_ready_departure;
|
|
|
|
reportVoice = reportTag;
|
|
}
|
|
else
|
|
{
|
|
reportTag = sprintf(atcMessageAction.contact_when_ready,
|
|
normalizeRadioStationName(towerRadio.name),
|
|
sprintf("%.3f", towerRadio.frequency)
|
|
);
|
|
|
|
reportVoice = sprintf(atcMessageAction.contact_when_ready,
|
|
normalizeRadioStationName(towerRadio.name),
|
|
spellToPhonetic(sprintf("%.3f", towerRadio.frequency), spell_number)
|
|
);
|
|
}
|
|
|
|
airport = airportinfo(selectedComAirportId);
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airport, runway_take_off);
|
|
|
|
extraText = "";
|
|
extraVoice = "";
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
squawkCode = getSquawkCode();
|
|
squawkChange = 1;
|
|
|
|
extraText ~= sprintf(" Squawk %s.", squawkCode);
|
|
extraVoice ~= sprintf(" Squawk %s.", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
}
|
|
else
|
|
{
|
|
extraText = ".";
|
|
extraVoice = ".";
|
|
}
|
|
|
|
if(departureInformation != "")
|
|
{
|
|
if(squawkingMode == "Off")
|
|
{
|
|
extraText ~= ".";
|
|
extraVoice ~= ".";
|
|
}
|
|
|
|
extraText ~= sprintf("\nYou have information %s.",
|
|
departureInformation
|
|
);
|
|
|
|
extraVoice ~= sprintf("\nYou have information %s.",
|
|
departureInformation
|
|
);
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.request_taxi,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse,
|
|
reportTag,
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.request_taxi,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway),
|
|
reportVoice,
|
|
extraVoice
|
|
);
|
|
|
|
aircraftIsDeparting = 1;
|
|
|
|
pilotResponseType = message_request_taxi;
|
|
}
|
|
else
|
|
{
|
|
reason = " ";
|
|
|
|
if(rand() < 0.5)
|
|
reason ~= atcMessageAction.unable_approve;
|
|
else
|
|
reason ~= atcMessageAction.negative;
|
|
|
|
reason ~= " " ~ atcMessageAction.taxi_request ~ ".";
|
|
|
|
text = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_ready_for_departure)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_tower) == 0)
|
|
return;
|
|
|
|
var airport = nil;
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(selectedComAirportId == airportinfo().id)
|
|
{
|
|
airport = airportinfo(selectedComAirportId);
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airport, runway_take_off);
|
|
|
|
if(nearRunway == 1)
|
|
{
|
|
extraText = atcMessageAction.lineup_and_wait;
|
|
extraVoice = atcMessageAction.lineup_and_wait;
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
if(currentRunway == airportRunwayInUse)
|
|
{
|
|
text = sprintf(atcMessageReply.ready_departure,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
extraText,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.ready_departure,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
extraVoice,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
|
|
if(squawkingMode == "On" and squawkChange == 1)
|
|
{
|
|
squawkCode = getSquawkCode();
|
|
|
|
text ~= sprintf(" Squawk %s.", squawkCode);
|
|
|
|
voice ~= sprintf(" Squawk %s.", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
}
|
|
|
|
aircraft_status = status_ready_for_departure;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(int(rand() * max_cleared_takeoff_secs) + min_cleared_takeoff_secs);
|
|
|
|
pilotResponseType = message_wait_for_departure;
|
|
}
|
|
else
|
|
{
|
|
text = sprintf(atcMessageReply.wrong_runway,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.wrong_runway,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
aircraftIsDeparting = 1;
|
|
}
|
|
else
|
|
{
|
|
reason = " ";
|
|
|
|
if(rand() < 0.5)
|
|
reason ~= atcMessageAction.unable_approve;
|
|
else
|
|
reason ~= atcMessageAction.negative;
|
|
|
|
reason ~= " " ~ atcMessageAction.departure_request ~ ".";
|
|
|
|
text = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_in_this_airfield,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
reason
|
|
);
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_abort_departure)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_tower) == 0)
|
|
return;
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
airport = airportinfo(selectedComAirportId);
|
|
(airportRunwayInUse, airportRunwayInUseILS) = runwayInUse(airport, runway_take_off);
|
|
|
|
text = sprintf(atcMessageReply.abort_departure,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.abort_departure,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
|
|
aircraft_status = status_going_around;
|
|
|
|
aircraftIsDeparting = 0;
|
|
|
|
pilotResponseType = message_going_around;
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_request_approach or messageType == message_request_ils)
|
|
{
|
|
var towerRadio = nil;
|
|
var initialReportLetter = "R";
|
|
var finalTurn = "";
|
|
var ilsText = "";
|
|
var ilsVoice = "";
|
|
|
|
if(isRadioTunedToApprovedCtrRadio() == 0)
|
|
{
|
|
atcReplyToRequest(message_not_in_this_ctr);
|
|
|
|
return;
|
|
}
|
|
|
|
if(checkRadioIsType(radio_station_type_approach) == 0)
|
|
return;
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(approvedCtr != nil)
|
|
airport = airportinfo(approvedCtr.ident);
|
|
else
|
|
airport = airportinfo(selectedComAirportId);
|
|
|
|
(airportLandingRunway, airportRunwayInUseILS) = runwayInUse(airport, runway_landing);
|
|
|
|
if(messageType == message_request_ils)
|
|
{
|
|
patternFormat = atcMessageReply.request_pattern_ils;
|
|
approachFormat = atcMessageReply.request_ils;
|
|
|
|
ilsText = "ILS";
|
|
ilsVoice = "I L S";
|
|
|
|
airportLandingRunway = airportRunwayInUseILS;
|
|
}
|
|
else
|
|
{
|
|
patternFormat = atcMessageReply.request_pattern_approach;
|
|
approachFormat = atcMessageReply.request_approach;
|
|
|
|
ilsText = "";
|
|
ilsVoice = "";
|
|
}
|
|
|
|
var (courseToRunway, distanceToRunway) = courseAndDistance(airport.runways[airportLandingRunway]);
|
|
|
|
approachPoint = geo.Coord.new().set_latlon(airport.runways[airportLandingRunway].lat,
|
|
airport.runways[airportLandingRunway].lon);
|
|
|
|
approachPoint.apply_course_distance(airport.runways[airportLandingRunway].heading, approach_point_distance * NM2M);
|
|
|
|
var heading = property_Aircraft_HeadingMagneticDeg.getValue();
|
|
|
|
patternPoint = geo.Coord.new().set_latlon(approachPoint.lat(),
|
|
approachPoint.lon());
|
|
|
|
if(geo.normdeg(courseToRunway - heading) < 180)
|
|
{
|
|
patternCircuit = atcMessageAction.right_tag;
|
|
|
|
courseToApproachPoint = geo.normdeg(airport.runways[airportLandingRunway].heading - 90);
|
|
}
|
|
else
|
|
{
|
|
patternCircuit = atcMessageAction.left_tag;
|
|
|
|
courseToApproachPoint = geo.normdeg(airport.runways[airportLandingRunway].heading + 90);
|
|
}
|
|
|
|
if(messageType == message_request_approach)
|
|
finalTurn = patternCircuit;
|
|
else
|
|
finalTurn = "";
|
|
|
|
patternPoint.apply_course_distance(courseToApproachPoint, pattern_point_distance * NM2M);
|
|
|
|
var (courseToPattern, distanceToPattern) = courseAndDistance(patternPoint);
|
|
var (courseToApproach, distanceToApproach) = courseAndDistance(approachPoint);
|
|
|
|
airportElevation = airport.elevation * M2FT;
|
|
|
|
approachAltitude = altitudeApproachSlope(airport.elevation, abs(approach_point_distance), 1);
|
|
|
|
var cruiseAltitude = approachAltitude;
|
|
|
|
var altitudeInstructionText = "";
|
|
var altitudeInstructionVoice = "";
|
|
|
|
if(distanceToPattern > min_distance_for_altitude_change)
|
|
{
|
|
var altSteps = int(distanceToPattern / miles_altitude_step);
|
|
|
|
cruiseAltitude += (feet_altitude_step * altSteps);
|
|
|
|
cruiseAltitude = normalizeAltitudeHeading(cruiseAltitude, courseToPattern, approachAltitude);
|
|
|
|
if(property_Aircraft_AltitudeFeet.getValue() > cruiseAltitude)
|
|
actionTag = atcMessageAction.descend;
|
|
else
|
|
actionTag = atcMessageAction.climb;
|
|
|
|
altitudeInstructionText = sprintf(atcMessageAction.altitude_change,
|
|
actionTag,
|
|
sprintf("%d", cruiseAltitude)
|
|
);
|
|
|
|
altitudeInstructionVoice = sprintf(atcMessageAction.altitude_change,
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", cruiseAltitude), spell_number_to_literal)
|
|
);
|
|
|
|
assignedAltitude = cruiseAltitude;
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
}
|
|
|
|
if(distanceToPattern < distanceToRunway or distanceToApproach < distanceToRunway)
|
|
{
|
|
# Route plane to runway approach point
|
|
|
|
(courseToApproach, distanceToApproach) = courseAndDistance(approachPoint);
|
|
|
|
text = sprintf(approachFormat,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
altitudeInstructionText,
|
|
sprintf("%d", courseToApproach),
|
|
sprintf("%d", distanceToApproach),
|
|
finalTurn,
|
|
ilsText,
|
|
airportLandingRunway,
|
|
sprintf("%d", approachAltitude),
|
|
getMeteoText(meteo_type_qnh, 0)
|
|
);
|
|
|
|
voice = sprintf(approachFormat,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
altitudeInstructionVoice,
|
|
spellToPhonetic(sprintf("%d", courseToApproach), spell_number),
|
|
spellToPhonetic(sprintf("%d", distanceToApproach), spell_number_to_literal),
|
|
finalTurn,
|
|
ilsVoice,
|
|
spellToPhonetic(airportLandingRunway, spell_runway),
|
|
spellToPhonetic(sprintf("%d", approachAltitude), spell_number_to_literal),
|
|
getMeteoText(meteo_type_qnh, 1)
|
|
);
|
|
|
|
assignedAltitude = approachAltitude;
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
|
|
approachStatus = approach_status_to_approach;
|
|
approach_check_counter = 0;
|
|
}
|
|
else if(distanceToApproach > 3)
|
|
{
|
|
# Route plane to pattern point
|
|
|
|
text = sprintf(patternFormat,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
altitudeInstructionText,
|
|
sprintf("%d", courseToPattern),
|
|
sprintf("%d", distanceToPattern),
|
|
patternCircuit,
|
|
sprintf("%d", courseToApproachPoint),
|
|
finalTurn,
|
|
ilsText,
|
|
airportLandingRunway,
|
|
sprintf("%d", approachAltitude),
|
|
getMeteoText(meteo_type_qnh, 0)
|
|
);
|
|
|
|
voice = sprintf(patternFormat,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
altitudeInstructionVoice,
|
|
spellToPhonetic(sprintf("%d", courseToPattern), spell_number),
|
|
spellToPhonetic(sprintf("%d", distanceToPattern), spell_number_to_literal),
|
|
patternCircuit,
|
|
spellToPhonetic(sprintf("%d", courseToApproachPoint), spell_number),
|
|
finalTurn,
|
|
ilsVoice,
|
|
spellToPhonetic(airportLandingRunway, spell_runway),
|
|
spellToPhonetic(sprintf("%d", approachAltitude), spell_number_to_literal),
|
|
getMeteoText(meteo_type_qnh, 1)
|
|
);
|
|
|
|
approachStatus = approach_status_to_pattern;
|
|
approach_check_counter = 0;
|
|
}
|
|
else
|
|
{
|
|
# Route plane to approach point
|
|
|
|
text = sprintf(approachFormat,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
altitudeInstructionText,
|
|
sprintf("%d", courseToApproachPoint),
|
|
sprintf("%d", distanceToApproach),
|
|
finalTurn,
|
|
ilsText,
|
|
airportLandingRunway,
|
|
sprintf("%d", approachAltitude),
|
|
getMeteoText(meteo_type_qnh, 0)
|
|
);
|
|
|
|
voice = sprintf(approachFormat,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
altitudeInstructionVoice,
|
|
spellToPhonetic(sprintf("%d", courseToApproachPoint), spell_number),
|
|
spellToPhonetic(sprintf("%d", distanceToApproach), spell_number_to_literal),
|
|
finalTurn,
|
|
ilsVoice,
|
|
spellToPhonetic(airportLandingRunway, spell_runway),
|
|
spellToPhonetic(sprintf("%d", approachAltitude), spell_number_to_literal),
|
|
getMeteoText(meteo_type_qnh, 1)
|
|
);
|
|
|
|
approachStatus = approach_status_to_approach;
|
|
approach_check_counter = 0;
|
|
}
|
|
|
|
if(messageType == message_request_approach)
|
|
pilotResponseType = message_approved_approach;
|
|
else
|
|
pilotResponseType = message_approved_ils;
|
|
|
|
if(approvedCtr == nil or approvedCtr.ident != currentCtr.ident)
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
else
|
|
{
|
|
if(messageType == message_request_approach)
|
|
aircraft_status = status_requested_approach;
|
|
else
|
|
aircraft_status = status_requested_ils;
|
|
|
|
aircraftIsDeparting = 0;
|
|
}
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
approach_check_interval = approach_check_interval_initial;
|
|
}
|
|
else if(messageType == message_approach_route_instructions)
|
|
{
|
|
text = sprintf(atcMessageReply.approach_route_instructions,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
approachRouteTextInstructions
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.approach_route_instructions,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
approachRouteVoiceInstructions
|
|
);
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
pilotResponseType = message_approach_route_instructions;
|
|
}
|
|
else if(messageType == message_airfield_in_sight or messageType == message_ils_established)
|
|
{
|
|
if(checkRadioIsType(radio_station_type_tower) == 0)
|
|
return;
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(aircraft_status == status_requested_approach or aircraft_status == status_requested_ils or aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
airport = airportinfo(selectedComAirportId);
|
|
|
|
(airportLandingRunway, airportRunwayInUseILS) = runwayInUse(airport, runway_landing);
|
|
|
|
if(aircraft_status == status_requested_ils or aircraft_status == status_cleared_for_land_ils)
|
|
landingRunway = airportRunwayInUseILS;
|
|
else
|
|
landingRunway = airportLandingRunway;
|
|
|
|
text = sprintf(atcMessageReply.airfield_in_sight,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
getMeteoText(meteo_type_wind, 0),
|
|
landingRunway
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.airfield_in_sight,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
getMeteoText(meteo_type_wind, 1),
|
|
spellToPhonetic(landingRunway, spell_runway)
|
|
);
|
|
|
|
if(aircraft_status == status_requested_ils)
|
|
aircraft_status = status_cleared_for_land_ils;
|
|
else
|
|
aircraft_status = status_cleared_for_land_approach;
|
|
|
|
setApproachButtons();
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(land_check_secs);
|
|
|
|
aircraftIsDeparting = 0;
|
|
|
|
pilotResponseType = message_cleared_landing;
|
|
}
|
|
else
|
|
{
|
|
text = sprintf(atcMessageReply.not_allowed_to_land,
|
|
atcCallsignText,
|
|
selectedComStationName
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_allowed_to_land,
|
|
atcCallsignVoice,
|
|
selectedComStationName
|
|
);
|
|
|
|
setApproachButtons();
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
if(approvedCtr == nil or approvedCtr.ident != currentCtr.ident)
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
}
|
|
}
|
|
else if(messageType == message_flying_too_low)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(atcMessageReply.flying_too_low,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.flying_too_low,
|
|
atcCallsignVoice
|
|
);
|
|
|
|
pilotResponseType = message_none;
|
|
}
|
|
else if(messageType == message_terrain_ahead)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(atcMessageReply.terrain_ahead,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.terrain_ahead,
|
|
atcCallsignVoice
|
|
);
|
|
|
|
pilotResponseType = message_none;
|
|
}
|
|
else if(messageType == message_leaving_ctr)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
var nearestCtr = getNearbyCtr(ctr_search_range);
|
|
|
|
if(nearestCtr != nil)
|
|
{
|
|
var radio = getCtrRadio(nearestCtr);
|
|
|
|
extraText = sprintf(atcMessageAction.contact_ctr,
|
|
nearestCtr.airport,
|
|
"CTR",
|
|
sprintf("%.3f", radio.frequency)
|
|
);
|
|
|
|
extraVoice = sprintf(atcMessageAction.contact_ctr,
|
|
nearestCtr.airport,
|
|
"C T R",
|
|
spellToPhonetic(sprintf("%.3f", radio.frequency), spell_number)
|
|
);
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.leaving_ctr,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"CTR",
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.leaving_ctr,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"C T R",
|
|
extraVoice
|
|
);
|
|
|
|
aircraftIsDeparting = 0;
|
|
|
|
pilotResponseType = message_roger;
|
|
|
|
resetAircraftStatus();
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(messageType == message_not_in_this_ctr)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(atcMessageReply.not_in_this_ctr,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"CTR",
|
|
"CTR"
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.not_in_this_ctr,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"C T R",
|
|
"C T R"
|
|
);
|
|
|
|
aircraftIsDeparting = 0;
|
|
|
|
pilotResponseType = message_roger;
|
|
|
|
resetAircraftStatus();
|
|
|
|
setApproachButtons();
|
|
}
|
|
if(messageType == message_request_fl)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(atcMessageReply.fl_approved,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"FL",
|
|
getFlightLevelCode(requestedAltitude)
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.fl_approved,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"Flight Level",
|
|
spellToPhonetic(getFlightLevelCode(requestedAltitude), spell_number)
|
|
);
|
|
|
|
resetAircraftStatus();
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
|
|
assignedAltitude = requestedAltitude;
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
|
|
pilotResponseType = message_fl_approved;
|
|
|
|
if(approvedCtr == nil or approvedCtr.ident != currentCtr.ident)
|
|
{
|
|
(text, voice) = getCtrAtcMessage(ctr_request_denied);
|
|
|
|
assignedAltitude = -1;
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
}
|
|
else if(messageType == message_change_altitude)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
assignedAltitude = getFlightPlanAltitude();
|
|
|
|
if(assignedAltitude == -1)
|
|
{
|
|
assignedAltitude = normalizeAltitudeHeading(property_Aircraft_AltitudeFeet.getValue(), property_Aircraft_HeadingDeg.getValue(), minCruiseAltidude);
|
|
|
|
if(rand() < 0.5 and (assignedAltitude - flight_level_step) >= minCruiseAltidude)
|
|
assignedAltitude -= flight_level_step;
|
|
}
|
|
|
|
if(property_Aircraft_AltitudeFeet.getValue() > assignedAltitude)
|
|
actionTag = atcMessageAction.descend;
|
|
else
|
|
actionTag = atcMessageAction.climb;
|
|
|
|
text = sprintf(atcMessageReply.change_altitude,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
actionTag,
|
|
sprintf("%d", assignedAltitude)
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.change_altitude,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", assignedAltitude), spell_number_to_literal)
|
|
);
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
|
|
pilotResponseType = message_change_altitude;
|
|
}
|
|
else if(messageType == message_check_altitude)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(property_Aircraft_AltitudeFeet.getValue() > assignedAltitude)
|
|
actionTag = atcMessageAction.descend;
|
|
else
|
|
actionTag = atcMessageAction.climb;
|
|
|
|
text = sprintf(atcMessageReply.check_altitude,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
actionTag,
|
|
sprintf("%d", assignedAltitude)
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.check_altitude,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", assignedAltitude), spell_number_to_literal)
|
|
);
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
|
|
pilotResponseType = message_change_altitude;
|
|
}
|
|
else if(messageType == message_check_transponder)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(squawkIdent != squawk_ident_code)
|
|
{
|
|
if(squawkCode == "")
|
|
squawkCode = getSquawkCode();
|
|
|
|
extraText = sprintf("%s and ", squawkCode);
|
|
|
|
extraVoice = sprintf("%s and ", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
|
|
setSquawkIdentMode(squawk_ident_only);
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.check_transponder,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.check_transponder,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
extraVoice
|
|
);
|
|
|
|
pilotResponseType = message_check_transponder;
|
|
}
|
|
else if(messageType == message_abort_approach)
|
|
{
|
|
var msg = "";
|
|
var rwy = "";
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(aircraft_status == status_requested_approach or aircraft_status == status_requested_ils)
|
|
{
|
|
msg = atcMessageReply.abort_approach;
|
|
rwy = airportLandingRunway;
|
|
}
|
|
else if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
msg = atcMessageReply.abort_landing;
|
|
rwy = landingRunway;
|
|
}
|
|
else
|
|
return;
|
|
|
|
text = sprintf(msg,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
rwy
|
|
);
|
|
|
|
voice = sprintf(msg,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(rwy, spell_runway)
|
|
);
|
|
|
|
aircraftIsDeparting = 0;
|
|
approachStatus = approach_status_none;
|
|
approach_check_interval = approach_check_interval_initial;
|
|
|
|
resetAircraftStatus();
|
|
|
|
setApproachButtons();
|
|
|
|
pilotResponseType = message_going_around;
|
|
}
|
|
|
|
if(text != "" or voice != "")
|
|
atcMessage(text, voice);
|
|
}
|
|
|
|
var atcAutoMessage = func()
|
|
{
|
|
var text = "";
|
|
var voice = "";
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
if(isRadioServiceable() == 0)
|
|
return;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(0);
|
|
|
|
if(aircraft_status == status_ready_for_departure)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(atcMessageReply.cleared_for_takeoff,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airportRunwayInUse,
|
|
getMeteoText(meteo_type_qnh, 0)
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.cleared_for_takeoff,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway),
|
|
getMeteoText(meteo_type_qnh, 1)
|
|
);
|
|
|
|
aircraft_status = status_cleared_for_takeoff;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(max_departure_secs);
|
|
|
|
departure_extra_time = 0;
|
|
|
|
approvedCtr = currentCtr;
|
|
altitude_check_counter = 0;
|
|
|
|
aircraftIsDeparting = 1;
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
|
|
pilotResponseType = message_cleared_take_off;
|
|
}
|
|
else if(aircraft_status == status_cleared_for_takeoff)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(departure_extra_time == 0 and alignedOnRunway == 1)
|
|
{
|
|
addSecondsToAtcAutoCallback(extra_departure_secs);
|
|
|
|
departure_extra_time = 1;
|
|
}
|
|
else
|
|
{
|
|
text = sprintf(atcMessageReply.vacate_runway,
|
|
atcCallsignText,
|
|
selectedComStationName
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.vacate_runway,
|
|
atcCallsignVoice,
|
|
selectedComStationName
|
|
);
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(max_take_off_secs);
|
|
}
|
|
|
|
approvedCtr = currentCtr;
|
|
altitude_check_counter = 0;
|
|
aircraftIsDeparting = 1;
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
else if(aircraft_status == status_took_off)
|
|
{
|
|
var airport = airportinfo();
|
|
var extraText = "";
|
|
var extraVoice = "";
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
aircraftIsDeparting = 1;
|
|
|
|
var cruiseAltitude = getFlightPlanAltitude();
|
|
|
|
if(cruiseAltitude == -1)
|
|
cruiseAltitude = normalizeAltitudeHeading(airport.elevation * M2FT, airport.runways[airportRunwayInUse].heading, minCruiseAltidude);
|
|
|
|
var radio = getCtrRadio(currentCtr);
|
|
|
|
if(radio.frequency != selectedComFrequency)
|
|
{
|
|
extraText = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
sprintf("%.3f", radio.frequency)
|
|
);
|
|
|
|
extraVoice = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
spellToPhonetic(sprintf("%.3f", radio.frequency), spell_number)
|
|
);
|
|
}
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
if(checkTransponder(selectedTransponder) == 0)
|
|
{
|
|
if(squawkCode == "")
|
|
squawkCode = getSquawkCode();
|
|
|
|
if(extraText != "")
|
|
{
|
|
extraText ~= ".";
|
|
extraVoice ~= ".";
|
|
}
|
|
|
|
extraText ~= " " ~ sprintf(atcMessageAction.check_transponder, squawkCode);
|
|
|
|
extraVoice ~= " " ~ sprintf(atcMessageAction.check_transponder, spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.leaving_airport,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
getMeteoText(meteo_type_wind, 0),
|
|
sprintf("%d", cruiseAltitude),
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.leaving_airport,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
getMeteoText(meteo_type_wind, 1),
|
|
spellToPhonetic(sprintf("%d", cruiseAltitude), spell_number_to_literal),
|
|
extraVoice
|
|
);
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
aircraft_status = status_flying;
|
|
approachStatus = approach_status_none;
|
|
approach_check_interval = approach_check_interval_initial;
|
|
|
|
approvedCtr = currentCtr;
|
|
assignedAltitude = cruiseAltitude;
|
|
altitude_check_counter = 0;
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
|
|
setApproachButtons();
|
|
|
|
setCtrButtons();
|
|
|
|
pilotResponseType = message_leaving_airport;
|
|
}
|
|
else if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
var approachingRunway = "";
|
|
var distance = 9999;
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
(approachingRunway, distance) = getApproachingRunway(currentAirport);
|
|
|
|
airport = airportinfo(selectedComAirportId);
|
|
|
|
(airportLandingRunway, airportRunwayInUseILS) = runwayInUse(airport, runway_landing);
|
|
|
|
if(aircraft_status == status_cleared_for_land_ils)
|
|
landingRunway = airportRunwayInUseILS;
|
|
else
|
|
landingRunway = airportLandingRunway;
|
|
|
|
if(approachingRunway != "" and approachingRunway != landingRunway)
|
|
{
|
|
text = sprintf(atcMessageReply.wrong_approach_runway,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
landingRunway
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.wrong_approach_runway,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
spellToPhonetic(landingRunway, spell_runway)
|
|
);
|
|
|
|
pilotResponseType = message_wilco;
|
|
}
|
|
else
|
|
pilotResponseType = message_none;
|
|
|
|
aircraftIsDeparting = 0;
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
setAtcAutoCallbackAfterSeconds(land_check_secs);
|
|
|
|
setApproachButtons();
|
|
}
|
|
else if(aircraft_status == status_landed)
|
|
{
|
|
airport = airportinfo();
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(atcMessageReply.welcome_to_airport,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
airport.name
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.welcome_to_airport,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
airport.name
|
|
);
|
|
|
|
cancelAtcPendingMessage();
|
|
|
|
aircraft_status = status_going_around;
|
|
|
|
assignedAltitude = -1;
|
|
aircraftIsDeparting = 0;
|
|
approachStatus = approach_status_none;
|
|
approach_check_interval = approach_check_interval_initial;
|
|
squawkCode = "";
|
|
squawkChange = 0;
|
|
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
|
|
setApproachButtons();
|
|
|
|
pilotResponseType = message_roger;
|
|
}
|
|
|
|
if(text != "" or voice != "")
|
|
atcMessage(text, voice);
|
|
}
|
|
|
|
var pilotRequest = func(messageType)
|
|
{
|
|
if(isRadioServiceable() == 0)
|
|
return;
|
|
|
|
if(isSimulationPaused() == 1)
|
|
return;
|
|
|
|
var text = "";
|
|
var voice = "";
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(messageType == message_say_again)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageRequest.say_again,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.say_again,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_radio_check)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageRequest.radio_check,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
sprintf("%.3f", selectedComFrequency)
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.radio_check,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(sprintf("%.3f", selectedComFrequency), spell_number)
|
|
);
|
|
}
|
|
else if(messageType == message_engine_start)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageRequest.engine_start,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.engine_start,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_departure_information)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageRequest.departure_information,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.departure_information,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_request_taxi)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(departureInformation != "")
|
|
{
|
|
extraText = sprintf(" with information %s",
|
|
departureInformation
|
|
);
|
|
|
|
extraVoice = extraText;
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(pilotMessageRequest.request_taxi,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.request_taxi,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
extraVoice
|
|
);
|
|
}
|
|
else if(messageType == message_ready_for_departure)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.ready_departure,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
currentRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.ready_departure,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(currentRunway, spell_runway)
|
|
);
|
|
|
|
if(squawkingMode == "On" and squawkCode == "")
|
|
squawkChange = 1;
|
|
}
|
|
else if(messageType == message_abort_departure)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.abort_departure,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
currentRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.abort_departure,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(currentRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_request_approach)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.request_approach,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.request_approach,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_request_ils)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.request_ils,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"ILS"
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.request_ils,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"I L S"
|
|
);
|
|
}
|
|
else if(messageType == message_airfield_in_sight)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.airfield_in_sight,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.airfield_in_sight,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_ils_established)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.ils_established,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"ILS",
|
|
airportRunwayInUseILS
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.ils_established,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"I L S",
|
|
spellToPhonetic(airportRunwayInUseILS, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_request_ctr)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageRequest.request_ctr,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"CTR"
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.request_ctr,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"C T R"
|
|
);
|
|
}
|
|
else if(messageType == message_request_fl)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageRequest.request_fl,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"FL",
|
|
getFlightLevelCode(requestedAltitude)
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.request_fl,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"Flight Level",
|
|
spellToPhonetic(getFlightLevelCode(requestedAltitude), spell_number)
|
|
);
|
|
}
|
|
else if(messageType == message_abort_approach)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(aircraft_status == status_requested_approach)
|
|
{
|
|
text = sprintf(pilotMessageRequest.abort_approach,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
airportLandingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.abort_approach,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(aircraft_status == status_requested_ils)
|
|
{
|
|
text = sprintf(pilotMessageRequest.abort_ils,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"ILS",
|
|
airportLandingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.abort_ils,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"I L S",
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(aircraft_status == status_cleared_for_land_approach or aircraft_status == status_cleared_for_land_ils)
|
|
{
|
|
text = sprintf(pilotMessageRequest.abort_landing,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
landingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageRequest.abort_landing,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(landingRunway, spell_runway)
|
|
);
|
|
}
|
|
}
|
|
else
|
|
return;
|
|
|
|
if(text != "" or voice != "")
|
|
{
|
|
cancelAtcPendingMessage();
|
|
|
|
var secs = 0;
|
|
|
|
pilotMessageType = messageType;
|
|
|
|
if(pilotRequestMode != "Disabled")
|
|
secs = int(size(text) / 12) + 1;
|
|
|
|
if((pilotRequestMode == "Voice only" or pilotRequestMode == "Voice and text") and voice != "")
|
|
{
|
|
speak(voice, pilotVoice['text'], pilotVoice['type']);
|
|
|
|
secs += 2;
|
|
}
|
|
|
|
echoMultiplayerChat(text, multiplayMessageType);
|
|
|
|
if((pilotRequestMode == "Text only" or pilotRequestMode == "Voice and text") and text != "")
|
|
{
|
|
var window = screen.window.new(atc_popup_x_position, atc_popup_y_position, 10, secs);
|
|
|
|
window.bg = popup_window_bg_color;
|
|
window.fg = popup_window_fg_pilot_color;
|
|
window.align = atc_popup_align;
|
|
|
|
window.write(text);
|
|
|
|
addAtcLog(text);
|
|
}
|
|
|
|
setPilotMessageSeconds(secs + pilot_message_pause_atc_seconds);
|
|
|
|
autoATCMessageDelay(secs + pilot_message_pause_atc_seconds);
|
|
}
|
|
}
|
|
|
|
var pilotResponse = func(messageType)
|
|
{
|
|
var text = "";
|
|
var voice = "";
|
|
var extraText = "";
|
|
var extraVoice = "";
|
|
var initialReportLetter = "R";
|
|
var radio = nil;
|
|
|
|
if(initialized == 0)
|
|
initRgATC();
|
|
|
|
if(isRadioServiceable() == 0)
|
|
return;
|
|
|
|
if(messageType == message_none or selectedComAirportId == "")
|
|
return;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(0);
|
|
|
|
if(messageType == message_roger)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageResponse.roger,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.roger,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_wilco)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageResponse.wilco,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.wilco,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_departure_information)
|
|
{
|
|
if(departureInformation == "")
|
|
return;
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageResponse.departure_information,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
departureInformation
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.departure_information,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
departureInformation
|
|
);
|
|
}
|
|
else if(messageType == message_engine_start)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageResponse.engine_start,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.engine_start,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_ctr_approved)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
if(squawkChange == 1)
|
|
{
|
|
extraText = sprintf(", Squawk %s and IDENT", squawkCode);
|
|
extraVoice = sprintf(", Squawk %s and ident", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
else
|
|
{
|
|
extraText = ", Squawk IDENT";
|
|
extraVoice = ", Squawk ident";
|
|
|
|
setSquawkIdentMode(squawk_ident_only);
|
|
}
|
|
|
|
squawkChange = 0;
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(pilotMessageResponse.approved_ctr,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"CTR",
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.approved_ctr,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"C T R",
|
|
extraVoice
|
|
);
|
|
}
|
|
else if(messageType == message_request_taxi)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
extraText = sprintf(", Squawk %s", squawkCode);
|
|
extraVoice = sprintf(", Squawk %s", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
squawkChange = 0;
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(pilotMessageResponse.taxi,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
airportRunwayInUse,
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.taxi,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway),
|
|
extraVoice
|
|
);
|
|
}
|
|
else if(messageType == message_wait_for_departure)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(nearRunway == 1)
|
|
{
|
|
extraText = atcMessageAction.lineup_and_wait;
|
|
extraVoice = atcMessageAction.lineup_and_wait;
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(pilotMessageResponse.wait_departure,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
extraText,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.wait_departure,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
extraVoice,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
|
|
if(squawkingMode == "On" and squawkChange == 1)
|
|
{
|
|
text ~= sprintf(". Squawk %s.", squawkCode);
|
|
|
|
voice ~= sprintf(". Squawk %s.", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
squawkChange = 0;
|
|
}
|
|
}
|
|
else if(messageType == message_cleared_take_off)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.cleared_take_off,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
airportRunwayInUse
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.cleared_take_off,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(airportRunwayInUse, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_leaving_airport)
|
|
{
|
|
radio = getCtrRadio(currentCtr);
|
|
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(radio != nil and radio.frequency != selectedComFrequency)
|
|
{
|
|
extraText = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
sprintf("%.3f", radio.frequency)
|
|
);
|
|
|
|
extraVoice = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(radio.name),
|
|
spellToPhonetic(sprintf("%.3f", radio.frequency), spell_number)
|
|
);
|
|
}
|
|
|
|
if(squawkingMode == "On")
|
|
{
|
|
if(checkTransponder(selectedTransponder) == 0)
|
|
{
|
|
if(squawkCode == "")
|
|
squawkCode = getSquawkCode();
|
|
|
|
if(extraText != "")
|
|
{
|
|
extraText ~= ".";
|
|
extraVoice ~= ".";
|
|
}
|
|
|
|
extraText ~= " " ~ sprintf(atcMessageAction.check_transponder, squawkCode);
|
|
|
|
extraVoice ~= " " ~ sprintf(atcMessageAction.check_transponder, spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
else
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
}
|
|
|
|
text = sprintf(pilotMessageResponse.leaving_airport,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
sprintf("%d", assignedAltitude),
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.leaving_airport,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(sprintf("%d", assignedAltitude), spell_number_to_literal),
|
|
extraVoice
|
|
);
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
}
|
|
else if(messageType == message_approved_approach)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.approved_approach,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
airportLandingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.approved_approach,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_approved_ils)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.approved_ils,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"ILS",
|
|
airportLandingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.approved_ils,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"I L S",
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_approach_route_instructions)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
text = sprintf(pilotMessageResponse.approach_route_instructions,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
approachRouteTextInstructions
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.approach_route_instructions,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
approachRouteVoiceInstructions
|
|
);
|
|
}
|
|
else if(messageType == message_cleared_landing)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.cleared_landing,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
landingRunway
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.cleared_landing,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
spellToPhonetic(landingRunway, spell_runway)
|
|
);
|
|
}
|
|
else if(messageType == message_fl_approved)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.approved_fl,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
"FL",
|
|
getFlightLevelCode(requestedAltitude)
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.approved_fl,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
"Flight Level",
|
|
spellToPhonetic(getFlightLevelCode(requestedAltitude), spell_number)
|
|
);
|
|
}
|
|
else if(messageType == message_change_altitude)
|
|
{
|
|
var actionTag = "";
|
|
|
|
multiplayMessageType = message_type_important;
|
|
|
|
if(property_Aircraft_AltitudeFeet.getValue() > assignedAltitude)
|
|
actionTag = atcMessageAction.descend;
|
|
else
|
|
actionTag = atcMessageAction.climb;
|
|
|
|
text = sprintf(pilotMessageResponse.change_altitude,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
actionTag,
|
|
sprintf("%d", assignedAltitude)
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.change_altitude,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", assignedAltitude), spell_number_to_literal)
|
|
);
|
|
|
|
altitude_check_interval = flightLevelChangeSeconds(assignedAltitude);
|
|
}
|
|
else if(messageType == message_check_transponder)
|
|
{
|
|
if(squawkIdent == squawk_ident_code)
|
|
{
|
|
extraText = sprintf("%s and ", squawkCode);
|
|
|
|
extraVoice = sprintf("%s and ", spellToPhonetic(squawkCode, spell_number));
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(pilotMessageResponse.check_transponder,
|
|
selectedComStationName,
|
|
atcCallsignText,
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.check_transponder,
|
|
selectedComStationName,
|
|
atcCallsignVoice,
|
|
extraVoice
|
|
);
|
|
}
|
|
else if(messageType == message_going_around)
|
|
{
|
|
multiplayMessageType = message_type_important;
|
|
|
|
text = sprintf(pilotMessageResponse.going_around,
|
|
selectedComStationName,
|
|
atcCallsignText
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.going_around,
|
|
selectedComStationName,
|
|
atcCallsignVoice
|
|
);
|
|
}
|
|
else if(messageType == message_contact_radio)
|
|
{
|
|
multiplayMessageType = message_type_local;
|
|
|
|
if(contactRadio != nil)
|
|
{
|
|
text = sprintf(pilotMessageResponse.contact_radio,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
normalizeRadioStationName(contactRadio.name),
|
|
sprintf("%.3f", contactRadio.frequency)
|
|
);
|
|
|
|
voice = sprintf(pilotMessageResponse.contact_radio,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
normalizeRadioStationName(contactRadio.name),
|
|
spellToPhonetic(sprintf("%.3f", contactRadio.frequency), spell_number)
|
|
);
|
|
}
|
|
}
|
|
|
|
pilotResponseType = message_none;
|
|
|
|
pilot_response_wait_seconds = -1;
|
|
|
|
if(text != "" or voice != "")
|
|
{
|
|
var secs = 0;
|
|
|
|
if(pilotResponseMode != "Disabled")
|
|
secs = int(size(text) / 12) + 1;
|
|
|
|
if((pilotResponseMode == "Voice only" or pilotResponseMode == "Voice and text") and voice != "")
|
|
{
|
|
speak(voice, pilotVoice['text'], pilotVoice['type']);
|
|
|
|
secs += 2;
|
|
}
|
|
|
|
if((pilotResponseMode == "Text only" or pilotResponseMode == "Voice and text") and text != "")
|
|
{
|
|
var window = screen.window.new(atc_popup_x_position, atc_popup_y_position, 10, secs);
|
|
|
|
window.bg = popup_window_bg_color;
|
|
window.fg = popup_window_fg_pilot_color;
|
|
window.align = atc_popup_align;
|
|
|
|
window.write(text);
|
|
|
|
addAtcLog(text);
|
|
}
|
|
|
|
autoATCMessageDelay(secs);
|
|
|
|
echoMultiplayerChat(text, multiplayMessageType);
|
|
}
|
|
}
|
|
|
|
var atcMessage = func(text, voice)
|
|
{
|
|
var secs = int(size(voice) / 12) + 1;
|
|
|
|
if((atcMessageMode == "Voice only" or atcMessageMode == "Voice and text") and voice != "")
|
|
{
|
|
if(stationVoice[selectedComFrequency] != nil)
|
|
speak(voice, stationVoice[selectedComFrequency]['text'], stationVoice[selectedComFrequency]['type']);
|
|
else
|
|
showPopup(atcMessageAction.inconsistent_radio_data);
|
|
}
|
|
|
|
if((atcMessageMode == "Text only" or atcMessageMode == "Voice and text") and text != "")
|
|
{
|
|
var window = screen.window.new(atc_popup_x_position, atc_popup_y_position, 10, secs);
|
|
|
|
window.bg = popup_window_bg_color;
|
|
window.fg = popup_window_fg_atc_color;
|
|
window.align = atc_popup_align;
|
|
|
|
window.write(text);
|
|
|
|
addAtcLog(text);
|
|
}
|
|
|
|
autoATCMessageDelay(secs);
|
|
|
|
echoMultiplayerChat(text, multiplayMessageType);
|
|
|
|
lastAtcText = text;
|
|
lastAtcVoice = voice;
|
|
|
|
showRepeatATCMessageButton(1);
|
|
|
|
pilot_response_counter = 0;
|
|
|
|
if(pilotResponseType != message_none)
|
|
pilot_response_wait_seconds = secs + pilot_response_pause_atc_seconds;
|
|
else
|
|
pilot_response_wait_seconds = -1;
|
|
}
|
|
|
|
var echoMultiplayerChat = func(text, type)
|
|
{
|
|
if(multiplayerChatEcho == "Off")
|
|
return;
|
|
|
|
var airport = airportinfo(selectedComAirportId);
|
|
|
|
var message = "[" ~ RGAtcName;
|
|
|
|
if(airport != nil)
|
|
message ~= "@" ~ airport.id;
|
|
|
|
message ~= "] ";
|
|
|
|
message ~= text;
|
|
|
|
if((multiplayerChatEcho == "Important messages only" and type == message_type_important) or (multiplayerChatEcho == "All messages"))
|
|
property_Multiplay_Chat.setValue(message);
|
|
}
|
|
|
|
var assistedAtcApproach = func()
|
|
{
|
|
var courseToPoint = nil;
|
|
var distanceToPoint = nil;
|
|
var degreeDiff = 0;
|
|
var turnToDiff = "";
|
|
var requiredSpeed = 0;
|
|
var actionTag = "";
|
|
var aircraftHeading = property_Aircraft_HeadingDeg.getValue();
|
|
var point = nil;
|
|
|
|
if(approachStatus == approach_status_none or approachStatus == approach_status_landing)
|
|
return;
|
|
|
|
if(approachStatus == approach_status_to_pattern)
|
|
{
|
|
(courseToPoint, distanceToPoint) = courseAndDistance(patternPoint);
|
|
|
|
requiredSpeed = pattern_speed;
|
|
}
|
|
else
|
|
{
|
|
(courseToPoint, distanceToPoint) = courseAndDistance(approachPoint);
|
|
|
|
requiredSpeed = approach_speed;
|
|
}
|
|
|
|
if(distanceToPoint < abs(approach_point_distance / 2))
|
|
approach_check_interval = approach_check_interval_near_point;
|
|
|
|
if(distanceToPoint < approach_turn_distance)
|
|
{
|
|
if(approachStatus == approach_status_to_pattern)
|
|
approachStatus = approach_status_to_approach;
|
|
else
|
|
approachStatus = approach_status_to_final;
|
|
|
|
approach_check_interval = approach_check_interval_final;
|
|
}
|
|
|
|
if(approachStatus == approach_status_to_pattern or approachStatus == approach_status_to_approach)
|
|
{
|
|
approachRouteTextInstructions = "";
|
|
approachRouteVoiceInstructions = "";
|
|
|
|
if(courseWithinDegrees(aircraftHeading, courseToPoint, 10) == 0)
|
|
{
|
|
(degreeDiff, turnToDiff) = degreesDifference(aircraftHeading, courseToPoint);
|
|
|
|
approachRouteTextInstructions = sprintf(atcMessageReply.turn_to_heading,
|
|
turnToDiff,
|
|
sprintf("%d", courseToPoint)
|
|
);
|
|
|
|
approachRouteVoiceInstructions = sprintf(atcMessageReply.turn_to_heading,
|
|
turnToDiff,
|
|
spellToPhonetic(sprintf("%d", courseToPoint), spell_number)
|
|
);
|
|
}
|
|
|
|
if(distanceToPoint < abs(approach_point_distance / 2) and abs(property_Aircraft_AltitudeFeet.getValue() - approachAltitude) > (assigned_altitude_delta / 2))
|
|
{
|
|
if(approachRouteTextInstructions != "")
|
|
{
|
|
approachRouteTextInstructions ~= ". ";
|
|
approachRouteVoiceInstructions ~= ". ";
|
|
}
|
|
|
|
if(property_Aircraft_AltitudeFeet.getValue() > approachAltitude)
|
|
actionTag = atcMessageAction.descend;
|
|
else
|
|
actionTag = atcMessageAction.climb;
|
|
|
|
approachRouteTextInstructions ~= sprintf("%s and maintain %s",
|
|
actionTag,
|
|
sprintf("%d", approachAltitude)
|
|
);
|
|
|
|
approachRouteVoiceInstructions ~= sprintf("%s and maintain %s",
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", approachAltitude),
|
|
spell_number_to_literal)
|
|
);
|
|
}
|
|
|
|
if(distanceToPoint < abs(approach_point_distance / 2) and abs(property_Aircraft_AirSpeedKnots.getValue() - requiredSpeed) > approach_speed_delta)
|
|
{
|
|
if(approachRouteTextInstructions != "")
|
|
{
|
|
approachRouteTextInstructions ~= ". ";
|
|
approachRouteVoiceInstructions ~= ". ";
|
|
}
|
|
|
|
if(property_Aircraft_AirSpeedKnots.getValue() > requiredSpeed)
|
|
actionTag = atcMessageAction.reduce;
|
|
else
|
|
actionTag = atcMessageAction.increase;
|
|
|
|
approachRouteTextInstructions ~= sprintf("%s speed %s knots",
|
|
actionTag,
|
|
sprintf("%d", requiredSpeed)
|
|
);
|
|
|
|
approachRouteVoiceInstructions ~= sprintf("%s speed %s knots",
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", requiredSpeed),
|
|
spell_number_to_literal)
|
|
);
|
|
}
|
|
|
|
if(approachRouteTextInstructions != "")
|
|
atcReplyToRequest(message_approach_route_instructions);
|
|
}
|
|
else if(approachStatus == approach_status_to_final)
|
|
{
|
|
var initialReportLetter = "R";
|
|
var contactMsgText = "";
|
|
var contactMsgVoice = "";
|
|
var towerContactText = "";
|
|
var towerContactVoice = "";
|
|
|
|
airport = airportinfo(selectedComAirportId);
|
|
|
|
runwayHeading = airport.runways[airportLandingRunway].heading;
|
|
|
|
(degreeDiff, turnToDiff) = degreesDifference(aircraftHeading, runwayHeading);
|
|
|
|
approachRouteTextInstructions = sprintf(atcMessageReply.turn_to_final,
|
|
turnToDiff,
|
|
sprintf("%d", runwayHeading),
|
|
airportLandingRunway
|
|
);
|
|
|
|
approachRouteVoiceInstructions = sprintf(atcMessageReply.turn_to_final,
|
|
turnToDiff,
|
|
spellToPhonetic(sprintf("%d", runwayHeading), spell_number),
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
|
|
if(abs(property_Aircraft_AirSpeedKnots.getValue() - final_speed) > approach_speed_delta)
|
|
{
|
|
if(approachRouteTextInstructions != "")
|
|
{
|
|
approachRouteTextInstructions ~= ". ";
|
|
approachRouteVoiceInstructions ~= ". ";
|
|
}
|
|
|
|
if(property_Aircraft_AirSpeedKnots.getValue() > final_speed)
|
|
actionTag = atcMessageAction.reduce;
|
|
else
|
|
actionTag = atcMessageAction.increase;
|
|
|
|
approachRouteTextInstructions ~= sprintf("%s speed %s knots",
|
|
actionTag,
|
|
sprintf("%d", final_speed)
|
|
);
|
|
|
|
approachRouteVoiceInstructions ~= sprintf("%s speed %s knots",
|
|
actionTag,
|
|
spellToPhonetic(sprintf("%d", final_speed), spell_number_to_literal)
|
|
);
|
|
}
|
|
|
|
if(isRadioFrequencyOfType(selectedComFrequency, radio_station_type_tower) == 0)
|
|
{
|
|
towerRadio = getRadio(radio_station_type_tower, radio_type_any);
|
|
|
|
if(towerRadio == nil)
|
|
{
|
|
showPopup(RGAtcName ~ ": " ~ atcMessageAction.tower_not_reachable ~ ".");
|
|
|
|
return;
|
|
}
|
|
|
|
if(selectedComFrequency != towerRadio.frequency)
|
|
{
|
|
towerContactText = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(towerRadio.name),
|
|
sprintf("%.3f", towerRadio.frequency)
|
|
);
|
|
|
|
towerContactText ~= " and ";
|
|
|
|
towerContactVoice = sprintf(atcMessageReply.contact_radio,
|
|
normalizeRadioStationName(towerRadio.name),
|
|
spellToPhonetic(sprintf("%.3f", towerRadio.frequency), spell_number)
|
|
);
|
|
|
|
towerContactVoice ~= " and ";
|
|
|
|
initialReportLetter = "r";
|
|
}
|
|
}
|
|
|
|
if(aircraft_status == status_requested_approach)
|
|
{
|
|
contactMsgText = sprintf(atcMessageReply.report_airfield_in_sight,
|
|
initialReportLetter
|
|
);
|
|
|
|
contactMsgText = towerContactText ~ contactMsgText;
|
|
|
|
contactMsgVoice = sprintf(atcMessageReply.report_airfield_in_sight,
|
|
initialReportLetter
|
|
);
|
|
|
|
contactMsgVoice = towerContactVoice ~ contactMsgVoice;
|
|
}
|
|
else
|
|
{
|
|
contactMsgText = sprintf(atcMessageReply.report_established_ils,
|
|
initialReportLetter,
|
|
"ILS",
|
|
airportLandingRunway
|
|
);
|
|
|
|
contactMsgText = towerContactText ~ contactMsgText;
|
|
|
|
contactMsgVoice = sprintf(atcMessageReply.report_established_ils,
|
|
initialReportLetter,
|
|
"I L S",
|
|
spellToPhonetic(airportLandingRunway, spell_runway)
|
|
);
|
|
|
|
contactMsgVoice = towerContactVoice ~ contactMsgVoice;
|
|
}
|
|
|
|
approachRouteTextInstructions ~= "\n" ~ contactMsgText;
|
|
approachRouteVoiceInstructions ~= "\n" ~ contactMsgVoice;
|
|
|
|
atcReplyToRequest(message_approach_route_instructions);
|
|
|
|
approachStatus = approach_status_landing;
|
|
}
|
|
}
|
|
|
|
var getCallSign = func(mode)
|
|
{
|
|
var cs = property_Setting_Callsign.getValue();
|
|
|
|
if(mode != "Complete" and size(cs) > 3)
|
|
{
|
|
if(mode == "Last three letters")
|
|
cs = substr(cs, size(cs) - 3);
|
|
else
|
|
cs = left(cs, 1) ~ substr(cs, size(cs) - 2);
|
|
}
|
|
|
|
return cs;
|
|
}
|
|
|
|
var getCallSignForAtc = func(initial)
|
|
{
|
|
var cs = property_Setting_Callsign.getValue();
|
|
var atcText = "";
|
|
var atcVoice = "";
|
|
|
|
if(includeManufacturer == "Yes" and aircraftManufacturer != "")
|
|
{
|
|
atcText ~= aircraftManufacturer ~ " ";
|
|
atcVoice ~= aircraftManufacturer ~ " ";
|
|
}
|
|
|
|
if(initial == 0)
|
|
cs = getCallSign(callsignMode);
|
|
|
|
atcText ~= cs;
|
|
atcVoice ~= spellToPhonetic(cs, spell_text);
|
|
|
|
return [atcText, atcVoice];
|
|
}
|
|
|
|
var checkRadioIsType = func(radioType)
|
|
{
|
|
if(selectedComStationType == radioType)
|
|
return 1;
|
|
|
|
var requestedRadio = nil;
|
|
var towerRadio = nil;
|
|
var i = 0;
|
|
var check = 0;
|
|
var radio = nil;
|
|
|
|
for(i = 0; i < size(availableRadio); i += 1)
|
|
{
|
|
radio = availableRadio[i];
|
|
|
|
if(radio.type == radioType and requestedRadio == nil)
|
|
requestedRadio = radio;
|
|
|
|
if(radio.type == radio_station_type_tower and towerRadio == nil)
|
|
towerRadio = radio;
|
|
}
|
|
|
|
if(requestedRadio != nil)
|
|
radio = requestedRadio;
|
|
else if(towerRadio != nil)
|
|
radio = towerRadio;
|
|
else
|
|
radio = nil;
|
|
|
|
if(radio != nil)
|
|
{
|
|
if(selectedComFrequency == radio.frequency)
|
|
return 1;
|
|
|
|
if(radio == towerRadio and selectedComStationType == radio_station_type_tower)
|
|
return 1;
|
|
|
|
var text = sprintf(atcMessageReply.wrong_radio,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
normalizeRadioStationName(radio.name),
|
|
sprintf("%.3f", radio.frequency)
|
|
);
|
|
|
|
var voice = sprintf(atcMessageReply.wrong_radio,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
normalizeRadioStationName(radio.name),
|
|
spellToPhonetic(sprintf("%.3f", radio.frequency), spell_number)
|
|
);
|
|
|
|
pilotResponseType = message_contact_radio;
|
|
contactRadio = radio;
|
|
|
|
atcMessage(text, voice);
|
|
|
|
check = 0;
|
|
}
|
|
else
|
|
check = 1;
|
|
|
|
return check;
|
|
}
|
|
|
|
var getAvailableRadios = func()
|
|
{
|
|
availableRadio = {};
|
|
|
|
if(selectedComStationType != nil and selectedComStationType != radio_station_type_unknown and selectedComAirportId != "")
|
|
airport = airportinfo(selectedComAirportId);
|
|
else if(currentAirport != nil)
|
|
airport = currentAirport;
|
|
else
|
|
return;
|
|
|
|
if(size(airport.comms()) == 0)
|
|
return;
|
|
|
|
var i = 0;
|
|
var radioType = radio_station_type_unknown;
|
|
|
|
foreach(var radio; airport.comms())
|
|
{
|
|
radioType = getRadioType(radio.ident);
|
|
|
|
radioData = {name:getRadioFullName(airport.id, radio.ident),
|
|
airport:airport.name,
|
|
location:split(" ", airport.name)[0],
|
|
ident:radio.ident,
|
|
frequency:radio.frequency,
|
|
type:radioType
|
|
};
|
|
|
|
availableRadio[i] = radioData;
|
|
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
var getRadio = func(radioType, type)
|
|
{
|
|
var requestedRadio = nil;
|
|
var i = 0;
|
|
var radio = nil;
|
|
var nradio = size(availableRadio);
|
|
|
|
if(nradio > 0)
|
|
{
|
|
for(i = 0; i < nradio; i += 1)
|
|
{
|
|
radio = availableRadio[i];
|
|
|
|
if(radio.type == radioType and requestedRadio == nil)
|
|
requestedRadio = radio;
|
|
}
|
|
|
|
if(requestedRadio == nil and type == radio_type_any)
|
|
requestedRadio = availableRadio[0];
|
|
}
|
|
|
|
return requestedRadio;
|
|
}
|
|
|
|
var getRadioType = func(radioIdent)
|
|
{
|
|
if(radioIdent == nil)
|
|
return radio_station_type_unknown;
|
|
|
|
var radioType = radio_station_type_unknown;
|
|
var name = string.lc(radioIdent);
|
|
|
|
if(find("TWR", radioIdent) != -1 or find("tower", name) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("APP", radioIdent) != -1 or find("approach", name) != -1)
|
|
radioType = radio_station_type_approach;
|
|
else if(find("GND", radioIdent) != -1 or find("ground", name) != -1 or find("grd", name) != -1)
|
|
radioType = radio_station_type_ground;
|
|
else if(find("ARR", radioIdent) != -1 or find("arrival", name) != -1 or find("director", name) != -1)
|
|
radioType = radio_station_type_approach;
|
|
else if(find("DEP", radioIdent) != -1 or find("departure", name) != -1)
|
|
radioType = radio_station_type_departure;
|
|
else if(find("DEL", radioIdent) != -1 or find("delivery", name) != -1 or find("clnc", name) != -1)
|
|
radioType = radio_station_type_clearance;
|
|
else if(find("apron", name) != -1 or find("APR", radioIdent) != -1)
|
|
radioType = radio_station_type_approach;
|
|
else if(find("traffic", name) != -1)
|
|
radioType = radio_station_type_approach;
|
|
else if(find("ATIS", radioIdent) != -1)
|
|
radioType = radio_station_type_atis;
|
|
else if(find("AFIS", radioIdent) != -1 or find("SERVICE", radioIdent) != -1)
|
|
radioType = radio_station_type_atis;
|
|
else if(find("CTAF", radioIdent) != -1)
|
|
radioType = radio_station_type_ground;
|
|
else if(find("CON", radioIdent) != -1)
|
|
radioType = radio_station_type_approach;
|
|
else if(find("radio", name) != -1 or find("rdo", name) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("info", name) != -1 or find("ATC", radioIdent) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("unicom", name) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("centre", name) != -1 or find("cntr", name) != -1 or find("ctr", name) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("MF", radioIdent) != -1 or find("MULT", radioIdent) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("FSS", radioIdent) != -1 or find("FIS", radioIdent) != -1 or find("FS", radioIdent) != -1)
|
|
radioType = radio_station_type_tower;
|
|
else if(find("start", name) != -1 or find("taxi", name) != -1)
|
|
radioType = radio_station_type_ground;
|
|
else
|
|
radioType = radio_station_type_tower;
|
|
|
|
return radioType;
|
|
}
|
|
|
|
var getRadioFullName = func(airportID, radioName)
|
|
{
|
|
if(airportID == nil or radioName == nil)
|
|
return "";
|
|
|
|
if(airportID == "" or radioName == "")
|
|
return "";
|
|
|
|
var airport = airportinfo(airportID);
|
|
var radioFullName = "";
|
|
|
|
if(airport != nil)
|
|
{
|
|
var airportCity = split(" ", airport.name)[0];
|
|
|
|
if(string.lc(airportCity) != string.lc(split(" ", radioName)[0]))
|
|
radioFullName = airportCity ~ " ";
|
|
|
|
radioFullName ~= radioName;
|
|
}
|
|
else
|
|
radioFullName = "";
|
|
|
|
return radioFullName;
|
|
}
|
|
|
|
var getAirportRadio = func(airport, radioType)
|
|
{
|
|
var requestedRadio = nil;
|
|
var i = 0;
|
|
var radio = nil;
|
|
|
|
if(airport == nil)
|
|
return nil;
|
|
|
|
var nradio = size(airport.comms());
|
|
|
|
if(nradio > 0)
|
|
{
|
|
foreach(radio; airport.comms())
|
|
{
|
|
if(getRadioType(radio.ident) == radioType and requestedRadio == nil)
|
|
requestedRadio = radio;
|
|
}
|
|
|
|
if(requestedRadio == nil)
|
|
{
|
|
foreach(radio; airport.comms())
|
|
{
|
|
if(getRadioType(radio.ident) == radio_station_type_tower and requestedRadio == nil)
|
|
requestedRadio = radio;
|
|
}
|
|
}
|
|
|
|
if(requestedRadio == nil)
|
|
requestedRadio = airport.comms()[0];
|
|
}
|
|
|
|
if(requestedRadio != nil)
|
|
{
|
|
requestedRadio.name = getRadioFullName(airport.id, requestedRadio.ident);
|
|
requestedRadio.airport = airport.name;
|
|
requestedRadio.location = split(" ", airport.name)[0];
|
|
}
|
|
|
|
return requestedRadio;
|
|
}
|
|
|
|
var isRadioFrequencyOfType = func(frequency, radioType)
|
|
{
|
|
var result = 0;
|
|
var i = 0;
|
|
var radio = nil;
|
|
var nradio = size(availableRadio);
|
|
|
|
if(nradio > 0)
|
|
{
|
|
for(i = 0; i < nradio and result == 0; i += 1)
|
|
{
|
|
radio = availableRadio[i];
|
|
|
|
if(radio.type == radioType and radio.frequency == frequency)
|
|
result = 1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
var getRadioVolume = func(volumeProperty, volumeSelectedProperty)
|
|
{
|
|
var commVolume = 0;
|
|
|
|
if(volumeProperty != nil)
|
|
commVolume = volumeProperty.getValue();
|
|
|
|
if(commVolume == 0 and volumeSelectedProperty != nil)
|
|
commVolume = volumeSelectedProperty.getValue();
|
|
|
|
return commVolume;
|
|
}
|
|
|
|
var getRadioFrequency = func(frequency, realFrequency)
|
|
{
|
|
var commFrequency = 0;
|
|
|
|
if(realFrequency != nil)
|
|
commFrequency = realFrequency.getValue();
|
|
|
|
if(commFrequency == 0 and frequency != nil)
|
|
commFrequency = frequency.getValue();
|
|
|
|
return commFrequency;
|
|
}
|
|
|
|
var isRadioServiceable = func()
|
|
{
|
|
var msg = "";
|
|
|
|
if(selectedComServiceableProperty == nil)
|
|
msg = atcMessageAction.bad_radio_data;
|
|
else if(selectedComServiceable == 0 or selectedComPowerStatus == 0 or selectedComOperable == 0)
|
|
msg = atcMessageAction.turn_radio_on;
|
|
else if(selectedComVolume < 0.1)
|
|
{
|
|
if(selectedComRadio != "")
|
|
msg = selectedComRadio ~ ": ";
|
|
else
|
|
msg = "";
|
|
|
|
msg ~= atcMessageAction.radio_volume_up;
|
|
}
|
|
else if(radioSignalQuality() == 0)
|
|
{
|
|
if(selectedComRadio != "")
|
|
msg = selectedComRadio ~ ": ";
|
|
else
|
|
msg = "";
|
|
|
|
msg ~= atcMessageAction.no_radio_tuned;
|
|
}
|
|
|
|
if(msg != "")
|
|
{
|
|
showPopup(RGAtcName ~ ": " ~ msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
var isRadioTunedToApprovedCtrRadio = func()
|
|
{
|
|
var radio = nil;
|
|
var isTuned = 0;
|
|
|
|
if(approvedCtr == nil)
|
|
return 0;
|
|
|
|
radio = getCtrRadio(approvedCtr);
|
|
|
|
if(radio.frequency == selectedComFrequency)
|
|
isTuned = 1;
|
|
|
|
return isTuned;
|
|
}
|
|
|
|
var isRealMeteoEnabled = func()
|
|
{
|
|
return property_RealWeather.getValue();
|
|
}
|
|
|
|
var getMeteoText = func(meteoType, voice)
|
|
{
|
|
var meteo = "";
|
|
var windFromDegrees = 0;
|
|
var windSpeed = 0;
|
|
var temperature = 0;
|
|
var dewpoint = 0;
|
|
var visibility = 0;
|
|
var rain = 0;
|
|
var snow = 0;
|
|
var clouds = "";
|
|
var cloudsElevation = 0;
|
|
|
|
if(isRealMeteoEnabled() == 1)
|
|
{
|
|
windFromDegrees = int(property_Weather_Metar_WindDirectionDeg.getValue());
|
|
windSpeed = int(property_Weather_Metar_WindSpeedKnots.getValue());
|
|
temperature = int(property_Weather_Metar_Temperature.getValue());
|
|
dewpoint = int(property_Weather_Metar_Dewpoint.getValue());
|
|
visibility = int(property_Weather_Metar_Visibility.getValue() / 1000);
|
|
|
|
if(property_Weather_Metar_Rain != nil)
|
|
rain = property_Weather_Metar_Rain.getValue();
|
|
else
|
|
rain = 0;
|
|
|
|
if(property_Weather_Metar_Snow != nil)
|
|
snow = property_Weather_Metar_Snow.getValue();
|
|
else
|
|
snow = 0;
|
|
|
|
if(property_Weather_Metar_CloudsCoverage != nil)
|
|
clouds = property_Weather_Metar_CloudsCoverage.getValue();
|
|
else
|
|
clouds = "clear";
|
|
|
|
if(property_Weather_Metar_CloudsElevationFeet != nil)
|
|
cloudsElevation = property_Weather_Metar_CloudsElevationFeet.getValue();
|
|
else
|
|
cloudsElevation = 0;
|
|
}
|
|
else
|
|
{
|
|
windFromDegrees = int(property_Weather_WindDirectionDeg.getValue());
|
|
windSpeed = int(property_Weather_WindSpeedKnots.getValue());
|
|
temperature = int(property_Weather_Temperature.getValue());
|
|
dewpoint = int(property_Weather_Dewpoint.getValue());
|
|
visibility = int(property_Weather_Visibility.getValue() / 1000);
|
|
|
|
if(property_Weather_Rain != nil)
|
|
rain = property_Weather_Rain.getValue();
|
|
else
|
|
rain = 0;
|
|
|
|
if(property_Weather_Snow != nil)
|
|
snow = property_Weather_Snow.getValue();
|
|
else
|
|
snow = 0;
|
|
|
|
if(property_Weather_CloudsCoverage != nil)
|
|
clouds = property_Weather_CloudsCoverage.getValue();
|
|
else
|
|
clouds = "clear";
|
|
|
|
if(property_Weather_CloudsElevationFeet != nil)
|
|
cloudsElevation = property_Weather_CloudsElevationFeet.getValue();
|
|
else
|
|
cloudsElevation = 0;
|
|
}
|
|
|
|
(qnhValue, qnhLiteralValue) = getQNH();
|
|
|
|
if(windSpeed > 0)
|
|
{
|
|
if(voice == 0)
|
|
{
|
|
meteo = sprintf(meteoMessage.wind_report,
|
|
sprintf("%d", windFromDegrees),
|
|
sprintf("%d", windSpeed)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
meteo = sprintf(meteoMessage.wind_report,
|
|
spellToPhonetic(sprintf("%d", windFromDegrees), spell_number),
|
|
spellToPhonetic(sprintf("%d", windSpeed), spell_number)
|
|
);
|
|
}
|
|
}
|
|
else
|
|
meteo = meteoMessage.wind_calm;
|
|
|
|
if(meteoType == meteo_type_full)
|
|
{
|
|
meteo ~= ", ";
|
|
|
|
if(voice == 0)
|
|
{
|
|
meteo ~= sprintf(meteoMessage.full,
|
|
"QNH",
|
|
qnhValue,
|
|
sprintf("%d", temperature),
|
|
sprintf("%d", dewpoint),
|
|
sprintf("%d", visibility)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
meteo ~= sprintf(meteoMessage.full,
|
|
"Q N H",
|
|
qnhLiteralValue,
|
|
spellToPhonetic(sprintf("%d", temperature), spell_number),
|
|
spellToPhonetic(sprintf("%d", dewpoint), spell_number),
|
|
spellToPhonetic(sprintf("%d", visibility), spell_number)
|
|
);
|
|
}
|
|
|
|
if(clouds != "clear")
|
|
{
|
|
meteo ~= ", ";
|
|
|
|
if(voice == 0)
|
|
{
|
|
meteo ~= sprintf(meteoMessage.cloud_report,
|
|
clouds,
|
|
sprintf("%d", cloudsElevation)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
meteo ~= sprintf(meteoMessage.cloud_report,
|
|
clouds,
|
|
spellToPhonetic(sprintf("%d", cloudsElevation), spell_number_to_literal)
|
|
);
|
|
}
|
|
}
|
|
else
|
|
meteo ~= ", " ~ meteoMessage.sky_clear;
|
|
|
|
if(rain > 0)
|
|
{
|
|
var rainTag = "";
|
|
|
|
if(rain < 0.3)
|
|
rainTag = meteoMessage.light;
|
|
else if(rain < 0.6)
|
|
rainTag = meteoMessage.moderate;
|
|
else
|
|
rainTag = meteoMessage.heavy;
|
|
|
|
meteo ~= ", ";
|
|
|
|
meteo ~= sprintf(meteoMessage.rain_report,
|
|
rainTag
|
|
);
|
|
}
|
|
|
|
if(snow > 0)
|
|
{
|
|
var snowTag = "";
|
|
|
|
if(snow < 0.3)
|
|
snowTag = meteoMessage.light;
|
|
else if(snow < 0.6)
|
|
snowTag = meteoMessage.moderate;
|
|
else
|
|
snowTag = meteoMessage.heavy;
|
|
|
|
meteo ~= ", ";
|
|
|
|
meteo ~= sprintf(meteoMessage.snow_report,
|
|
snowTag
|
|
);
|
|
|
|
if(isRealMeteoEnabled() == 1 and property_Weather_Metar_SnowCover != nil)
|
|
{
|
|
if(property_Weather_Metar_SnowCover.getValue() > 0)
|
|
meteo ~= " " ~ meteoMessage.cover;
|
|
}
|
|
}
|
|
}
|
|
else if(meteoType == meteo_type_qnh)
|
|
{
|
|
meteo ~= ", ";
|
|
|
|
if(voice == 0)
|
|
{
|
|
meteo ~= sprintf(meteoMessage.qnh_report,
|
|
"QNH",
|
|
qnhValue
|
|
);
|
|
}
|
|
else
|
|
{
|
|
meteo ~= sprintf(meteoMessage.qnh_report,
|
|
"Q N H",
|
|
qnhLiteralValue
|
|
);
|
|
}
|
|
}
|
|
|
|
return meteo;
|
|
}
|
|
|
|
var radioSignalQuality = func()
|
|
{
|
|
var signal = 0;
|
|
|
|
if(selectedComSignalQuality == nil)
|
|
return 0;
|
|
|
|
if(selectedComSignalQuality > 0)
|
|
{
|
|
if(selectedComSignalQuality < 0.05)
|
|
signal = 0;
|
|
else if(selectedComSignalQuality < 0.2)
|
|
signal = 1;
|
|
else if(selectedComSignalQuality < 0.3)
|
|
signal = 2;
|
|
else if(selectedComSignalQuality < 0.4)
|
|
signal = 3;
|
|
else if(selectedComSignalQuality < 0.5)
|
|
signal = 4;
|
|
else
|
|
signal = 5;
|
|
}
|
|
else
|
|
signal = 0;
|
|
|
|
return signal;
|
|
}
|
|
|
|
var minPathDistance = func(pos, pathPos, pathHeading, pathLength, minDistance)
|
|
{
|
|
var minDist = 9999;
|
|
var course = 0;
|
|
var dist = 0;
|
|
var step = minDistance / 4;
|
|
var cDist = 0;
|
|
var cPos = pathPos;
|
|
|
|
for(cDist = 0; cDist < pathLength; cDist += step)
|
|
{
|
|
cPos.apply_course_distance(pathHeading, step);
|
|
|
|
(course, dist) = courseAndDistance(pos, cPos);
|
|
|
|
if(dist < minDist)
|
|
minDist = dist;
|
|
}
|
|
|
|
return minDist * NM2M;
|
|
}
|
|
|
|
var normalizeAltitudeHeading = func(altitude, heading, minAltitude)
|
|
{
|
|
var normalizedAltitude = altitude;
|
|
|
|
if(normalizedAltitude < minAltitude)
|
|
normalizedAltitude = minAltitude;
|
|
|
|
var normalizedAltitude = int(normalizedAltitude / 1000) * 1000;
|
|
|
|
if(heading < 180)
|
|
{
|
|
if(math.mod(int(normalizedAltitude / 1000), 2) == 0)
|
|
normalizedAltitude += 1000;
|
|
}
|
|
else
|
|
{
|
|
if(math.mod(int(normalizedAltitude / 1000), 2) == 1)
|
|
normalizedAltitude += 1000;
|
|
}
|
|
|
|
normalizedAltitude += 500;
|
|
|
|
return normalizedAltitude;
|
|
}
|
|
|
|
var getFlightPlanAltitude = func()
|
|
{
|
|
var altitude = -1;
|
|
var distance = 9999;
|
|
var minCruiseAltidude = getMinCruiseAltitude();
|
|
|
|
if(!property_Autopilot_RouteManagerActive.getValue())
|
|
return -1;
|
|
|
|
var wpnum = property_Autopilot_RouteManagerRouteNum.getValue() - 1;
|
|
|
|
for(var i = property_Autopilot_RouteManagerCurrentWayPoint.getValue(); i < wpnum; i += 1)
|
|
{
|
|
var prop = sprintf("/autopilot/route-manager/route/wp[%d]/", i);
|
|
|
|
var wpalt = getprop(prop ~ "altitude-ft");
|
|
|
|
if(wpalt > 0)
|
|
{
|
|
var (wpcourse, wpdist) = courseAndDistance(geo.Coord.new().set_latlon(getprop(prop ~ "latitude-deg"), getprop(prop ~ "longitude-deg")));
|
|
|
|
if(wpdist < distance and wpdist < flight_plan_min_distance)
|
|
{
|
|
distance = wpdist;
|
|
|
|
altitude = wpalt;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(altitude == -1)
|
|
{
|
|
altitude = property_Autopilot_RouteManagerCruiseAltitudeFeet.getValue();
|
|
|
|
if(altitude < minCruiseAltidude)
|
|
altitude = normalizeAltitudeHeading(property_Aircraft_AltitudeFeet.getValue(), heading, minCruiseAltidude);
|
|
}
|
|
|
|
return math.round(altitude, 100);
|
|
}
|
|
|
|
var getFlightLevelCode = func(level)
|
|
{
|
|
var len = 0;
|
|
|
|
if(level >= 10000)
|
|
len = 3;
|
|
else if(level >= 1000)
|
|
len = 2;
|
|
else
|
|
len = 1;
|
|
|
|
return substr(sprintf("%d", level), 0, len);
|
|
}
|
|
|
|
var flightLevelChangeSeconds = func(finalAltitude)
|
|
{
|
|
var altitudeChange = abs(property_Aircraft_AltitudeFeet.getValue() - finalAltitude);
|
|
|
|
return int((altitudeChange / flight_level_rate) * 60);
|
|
}
|
|
|
|
var getMinCruiseAltitude = func()
|
|
{
|
|
var minCruiseAltidude = min_cruise_altitude;
|
|
var safeAltitude = property_Aircraft_AltitudeFeet.getValue() - property_Aircraft_AltitudeAglFeet.getValue() + min_safe_altitude;
|
|
|
|
if(minCruiseAltidude < safeAltitude)
|
|
minCruiseAltidude = safeAltitude;
|
|
|
|
return minCruiseAltidude;
|
|
}
|
|
|
|
var courseWithinDegrees = func(course, degrees, range)
|
|
{
|
|
var inRange = 0;
|
|
var degreeDiff = 360;
|
|
var turnToDiff = "";
|
|
|
|
(degreeDiff, turnToDiff) = degreesDifference(course, degrees);
|
|
|
|
if(degreeDiff <= (range / 2))
|
|
inRange = 1;
|
|
|
|
return inRange;
|
|
}
|
|
|
|
var degreesDifference = func(fromDegrees, toDegrees)
|
|
{
|
|
var degreeDiff = 0;
|
|
var turnToDiff = "";
|
|
|
|
degreeDiff = int(math.mod(((toDegrees - fromDegrees) + 180), 360) - 180);
|
|
|
|
if(degreeDiff == 0)
|
|
turnToDiff = "";
|
|
else if(degreeDiff < 0)
|
|
turnToDiff = "left";
|
|
else
|
|
turnToDiff = "right";
|
|
|
|
return [abs(degreeDiff), turnToDiff];
|
|
}
|
|
|
|
var resetAircraftStatus = func()
|
|
{
|
|
if(property_Aircraft_AltitudeAglFeet.getValue() > min_ground_altitude)
|
|
aircraft_status = status_flying;
|
|
else
|
|
aircraft_status = status_going_around;
|
|
}
|
|
|
|
var spellToPhonetic = func(text, spellMode)
|
|
{
|
|
var phoneticText = "";
|
|
var length = size(text);
|
|
|
|
if(spellMode == spell_number_to_literal)
|
|
phoneticText = numberToLiteral(int(text));
|
|
else
|
|
{
|
|
for(var i = 0; i < length; i += 1)
|
|
{
|
|
var character = chr(text[i]);
|
|
|
|
if(string.isalpha(text[i]))
|
|
{
|
|
character = chr(string.toupper(text[i]));
|
|
|
|
if(spellMode == spell_text or spellMode == spell_number)
|
|
phoneticText ~= phoneticLetter[character] ~ " ";
|
|
else if(spellMode == spell_runway)
|
|
{
|
|
var rwTag = "";
|
|
|
|
if(character == "L")
|
|
rwTag = "left";
|
|
else if(character == "R")
|
|
rwTag = "right";
|
|
else if(character == "C")
|
|
rwTag = "center";
|
|
else
|
|
rwTag = character;
|
|
|
|
phoneticText ~= rwTag ~ " ";
|
|
}
|
|
}
|
|
else if(string.isdigit(text[i]))
|
|
phoneticText ~= phoneticDigit[text[i] - 48] ~ " ";
|
|
else if(character == ".")
|
|
phoneticText ~= "decimal";
|
|
else if(character == "-")
|
|
{
|
|
if(spellMode == spell_number)
|
|
phoneticText ~= "minus";
|
|
}
|
|
else if(character == "/")
|
|
{
|
|
# ignore slash
|
|
}
|
|
else if(character == "\n")
|
|
{
|
|
phoneticText ~= " ";
|
|
}
|
|
else
|
|
phoneticText ~= character;
|
|
|
|
if(i < length - 1)
|
|
phoneticText ~= " ";
|
|
}
|
|
}
|
|
|
|
return phoneticText;
|
|
}
|
|
|
|
var numberToLiteral = func(number)
|
|
{
|
|
var text = "";
|
|
var digit = 0;
|
|
var tens = 0;
|
|
var units = 0;
|
|
|
|
digit = int(number / 1000);
|
|
|
|
if(digit > 0)
|
|
{
|
|
if(digit < 20)
|
|
text ~= phoneticNumber[digit];
|
|
else
|
|
{
|
|
tens = int(digit / 10);
|
|
|
|
if(tens > 0)
|
|
text ~= phoneticTen[tens] ~ " ";
|
|
|
|
units = digit - (tens * 10);
|
|
|
|
if(units < 10 and units > 0)
|
|
text ~= phoneticNumber[units];
|
|
}
|
|
|
|
text ~= " Thousand ";
|
|
}
|
|
|
|
number -= digit * 1000;
|
|
|
|
digit = int(number / 100);
|
|
|
|
if(digit > 0)
|
|
text ~= phoneticNumber[digit] ~ " Hundred ";
|
|
|
|
number -= digit * 100;
|
|
|
|
if(number > 0)
|
|
{
|
|
if(size(text) > 0)
|
|
text ~= "and ";
|
|
|
|
if(number < 20)
|
|
text ~= phoneticNumber[number];
|
|
else
|
|
{
|
|
digit = int(number / 10);
|
|
|
|
if(digit > 0)
|
|
text ~= phoneticTen[digit] ~ " ";
|
|
|
|
number -= digit * 10;
|
|
|
|
if(number < 10 and number > 0)
|
|
text ~= phoneticNumber[number];
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
var getMessageText = func(messageType)
|
|
{
|
|
var message = "";
|
|
|
|
if(messageType == message_radio_check)
|
|
message = atcMessageRequest.radio_check;
|
|
else if(messageType == message_engine_start)
|
|
message = atcMessageRequest.engine_start;
|
|
else if(messageType == message_departure_information)
|
|
message = atcMessageRequest.departure_information;
|
|
else if(messageType == message_request_taxi)
|
|
message = atcMessageRequest.request_taxi;
|
|
else if(messageType == message_ready_for_departure)
|
|
message = atcMessageRequest.ready_departure;
|
|
else if(messageType == message_abort_departure)
|
|
message = atcMessageRequest.abort_departure;
|
|
else if(messageType == message_request_approach)
|
|
message = atcMessageRequest.request_approach;
|
|
else if(messageType == message_request_ils)
|
|
message = atcMessageRequest.request_ils;
|
|
else if(messageType == message_airfield_in_sight)
|
|
message = atcMessageRequest.airfield_in_sight;
|
|
else if(messageType == message_ils_established)
|
|
message = atcMessageRequest.ils_established;
|
|
|
|
return message;
|
|
}
|
|
|
|
var normalizeRadioStationName = func(text)
|
|
{
|
|
if(text == nil or text == "")
|
|
return "";
|
|
|
|
var word = split(" ", text);
|
|
var wlen = size(word);
|
|
var wspace = wlen - 1;
|
|
var stationName = "";
|
|
|
|
for(var i = 0; i < wlen; i += 1)
|
|
{
|
|
var w = string.lc(word[i]);
|
|
|
|
if(w == "twr")
|
|
w = "tower";
|
|
else if(w == "app")
|
|
w = "approach";
|
|
else if(w == "apron")
|
|
w = "approach On";
|
|
else if(w == "gnd")
|
|
w = "ground";
|
|
else if(w == "gnd/apron")
|
|
w = "ground";
|
|
else if(w == "arr")
|
|
w = "arrival";
|
|
else if(w == "dep")
|
|
w = "departure";
|
|
else if(w == "del")
|
|
w = "delivery";
|
|
else if(w == "clnc")
|
|
w = "clearance";
|
|
else if(w == "ctaf")
|
|
w = "CTAF";
|
|
else if(w == "awos")
|
|
w = "AWOS";
|
|
else if(w == "afis")
|
|
w = "AFIS";
|
|
else if(w == "atis")
|
|
w = "ATIS";
|
|
else if(w == "unicom")
|
|
w = "Universal communications";
|
|
|
|
stationName ~= string.uc(left(w, 1)) ~ substr(w, 1) ;
|
|
|
|
if(i < wspace)
|
|
stationName ~= " ";
|
|
}
|
|
|
|
return stationName;
|
|
}
|
|
|
|
var setPilotMessageSeconds = func(delay)
|
|
{
|
|
pilot_message_wait_seconds = delay;
|
|
|
|
pilot_message_counter = 0;
|
|
}
|
|
|
|
var cancelPilotPendingMessage = func()
|
|
{
|
|
pilot_message_wait_seconds = -1;
|
|
pilot_message_counter = 0;
|
|
|
|
pilot_response_wait_seconds = -1;
|
|
pilot_response_counter = 0;
|
|
}
|
|
|
|
var setAtcAutoCallbackAfterSeconds = func(delay)
|
|
{
|
|
atc_callback_wait_seconds = delay;
|
|
|
|
atc_callback_seconds_counter = 0;
|
|
}
|
|
|
|
var addSecondsToAtcAutoCallback = func(delay)
|
|
{
|
|
atc_callback_wait_seconds += delay;
|
|
}
|
|
|
|
var cancelAtcPendingMessage = func()
|
|
{
|
|
atc_callback_seconds_counter = 0;
|
|
|
|
altitude_check_counter = 0;
|
|
|
|
altitude_change_counter = 0;
|
|
}
|
|
|
|
var getNearbyCtr = func(range)
|
|
{
|
|
var airport = nil;
|
|
var nearByAirports = nil;
|
|
var minDistance = range;
|
|
var nearestCtr = nil;
|
|
var ctrData = nil;
|
|
var radio = nil;
|
|
|
|
airport = airportinfo();
|
|
|
|
if(airport != nil)
|
|
{
|
|
ctrData = getCtrData(airport);
|
|
|
|
if(ctrData != nil and ctrData.status == ctr_status_inside)
|
|
{
|
|
if(approvedCtr != nil)
|
|
{
|
|
if(ctrData.ident != approvedCtr.ident or isRadioTunedToApprovedCtrRadio == 0)
|
|
return ctrData;
|
|
}
|
|
else
|
|
return ctrData;
|
|
}
|
|
}
|
|
|
|
nearByAirports = findAirportsWithinRange(range);
|
|
|
|
foreach(airport; nearByAirports)
|
|
{
|
|
ctrData = getCtrData(airport);
|
|
|
|
if(ctrData != nil)
|
|
{
|
|
if(approvedCtr != nil and ctrData.ident == approvedCtr.ident)
|
|
{
|
|
# ignore currently approved CTR
|
|
}
|
|
else if(ctrData.status == ctr_status_inside)
|
|
{
|
|
nearestCtr = ctrData;
|
|
|
|
minDistance = 0;
|
|
}
|
|
else if(ctrData.status == ctr_status_in_range and ctrData.distance_from_range < minDistance)
|
|
{
|
|
minDistance = ctrData.distance_from_range;
|
|
|
|
nearestCtr = ctrData;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearestCtr;
|
|
}
|
|
|
|
var getCtrData = func(airport)
|
|
{
|
|
var course = 0;
|
|
var distance = 0;
|
|
var range = 0;
|
|
var rangeDistance = 0;
|
|
var status = ctr_status_outside;
|
|
var aircraftHeading = property_Aircraft_HeadingDeg.getValue();
|
|
|
|
if(airport == nil)
|
|
return nil;
|
|
|
|
var nradios = size(airport.comms());
|
|
|
|
if(nradios == 0)
|
|
return nil;
|
|
|
|
var pos = geo.Coord.new().set_latlon(airport.lat, airport.lon);
|
|
|
|
(course, distance) = courseAndDistance(pos);
|
|
|
|
if(nradios > 5)
|
|
range = ctr_range_wide;
|
|
else if(nradios > 1)
|
|
range = ctr_range_medium;
|
|
else
|
|
range = ctr_range_short;
|
|
|
|
if(distance < range)
|
|
{
|
|
status = ctr_status_inside;
|
|
|
|
rangeDistance = 0;
|
|
}
|
|
else if(courseWithinDegrees(aircraftHeading, course, ctr_maximum_range_angle) == 1)
|
|
{
|
|
if((distance - range) < ctr_maximum_range_distance)
|
|
{
|
|
status = ctr_status_in_range;
|
|
|
|
rangeDistance = distance - range;
|
|
}
|
|
else
|
|
{
|
|
status = ctr_status_outside;
|
|
|
|
rangeDistance = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ctr_status_outside;
|
|
|
|
rangeDistance = 0;
|
|
}
|
|
|
|
var ctrData = {
|
|
ident:airport.id,
|
|
airport:airport.name,
|
|
lat:airport.lat,
|
|
lon:airport.lon,
|
|
range:range,
|
|
course:course,
|
|
distance:distance,
|
|
distance_from_range:rangeDistance,
|
|
status:status
|
|
};
|
|
|
|
return ctrData;
|
|
}
|
|
|
|
var getCtrRadio = func(ctr)
|
|
{
|
|
var radioType = radio_station_type_approach;
|
|
var radio = nil;
|
|
|
|
if(ctr == nil)
|
|
return nil;
|
|
|
|
if(aircraftIsDeparting == 1)
|
|
radioType = radio_station_type_departure;
|
|
|
|
radio = getAirportRadio(airportinfo(ctr.ident), radioType);
|
|
|
|
if(getRadioType(radio.ident) != radioType)
|
|
radio = getAirportRadio(airportinfo(ctr.ident), radio_station_type_approach);
|
|
|
|
return radio;
|
|
}
|
|
|
|
var getQNH = func()
|
|
{
|
|
var qnhinhg = 0;
|
|
var qnhhpa = 0;
|
|
var qnhValue = "";
|
|
var qnhLiteralValue = "";
|
|
|
|
if(isRealMeteoEnabled() == 1)
|
|
{
|
|
if(property_Weather_QnhInHg != nil)
|
|
qnhinhg = property_Weather_Metar_QnhInHg.getValue();
|
|
else
|
|
qnhinhg = 0;
|
|
}
|
|
else
|
|
{
|
|
if(property_Weather_QnhInHg != nil)
|
|
qnhinhg = property_Weather_QnhInHg.getValue();
|
|
else
|
|
qnhinhg = 0;
|
|
}
|
|
|
|
qnhhpa = int(qnhinhg / 0.02953);
|
|
|
|
if(qnhUnitMeasure == "hPa")
|
|
{
|
|
qnhValue = sprintf("%d hPa", qnhhpa);
|
|
qnhLiteralValue = spellToPhonetic(sprintf("%d", qnhhpa), spell_number) ~ " hecto pascal";
|
|
}
|
|
else if(qnhUnitMeasure == "inHg")
|
|
{
|
|
qnhValue = sprintf("%.2f inHg", qnhinhg);
|
|
qnhLiteralValue = spellToPhonetic(sprintf("%.2f" ,qnhinhg), spell_number) ~ " inches of mercury";
|
|
}
|
|
else
|
|
{
|
|
qnhValue = sprintf("%d hPa or %.2f inHg", qnhhpa, qnhinhg);
|
|
qnhLiteralValue = spellToPhonetic(sprintf("%d", qnhhpa), spell_number) ~ " hecto pascal or ";
|
|
qnhLiteralValue ~= spellToPhonetic(sprintf("%.2f", qnhinhg), spell_number) ~ " inches of mercury";
|
|
}
|
|
|
|
return [qnhValue, qnhLiteralValue];
|
|
}
|
|
|
|
var isInsideCtr = func(airport)
|
|
{
|
|
if(airport == nil)
|
|
return 0;
|
|
|
|
var ctrData = getCtrData(airport);
|
|
var isInside = 0;
|
|
|
|
if(ctrData != nil and ctrData.status == ctr_status_inside)
|
|
isInside = 1;
|
|
else
|
|
isInside = 0;
|
|
|
|
return isInside;
|
|
}
|
|
|
|
var getCtrAtcMessage = func(request)
|
|
{
|
|
var text = "";
|
|
var voice = "";
|
|
var extraText = "";
|
|
var extraVoice = "";
|
|
|
|
(atcCallsignText, atcCallsignVoice) = getCallSignForAtc(0);
|
|
|
|
if(request == ctr_request_approved)
|
|
{
|
|
if(squawkingMode == "On")
|
|
{
|
|
var code = getSquawkCode();
|
|
|
|
if(code != squawkCode)
|
|
{
|
|
squawkCode = code;
|
|
|
|
extraText = sprintf(", Squawk %s and IDENT", squawkCode);
|
|
extraVoice = sprintf(", Squawk %s and ident", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
squawkChange = 1;
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
else
|
|
{
|
|
extraText = ", Squawk IDENT";
|
|
extraVoice = ", Squawk ident";
|
|
|
|
squawkChange = 0;
|
|
|
|
setSquawkIdentMode(squawk_ident_only);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.ctr_approved,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"CTR",
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.ctr_approved,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"C T R",
|
|
extraVoice
|
|
);
|
|
}
|
|
else if(request == ctr_already_approved)
|
|
{
|
|
if(squawkingMode == "On")
|
|
{
|
|
if(squawkCode == "")
|
|
squawkCode = getSquawkCode();
|
|
|
|
extraText = sprintf(", Squawk %s", squawkCode);
|
|
extraVoice = sprintf(", Squawk %s", spellToPhonetic(squawkCode, spell_number));
|
|
|
|
setSquawkIdentMode(squawk_ident_code);
|
|
}
|
|
else
|
|
{
|
|
extraText = "";
|
|
extraVoice = "";
|
|
|
|
setSquawkIdentMode(squawk_ident_off);
|
|
}
|
|
|
|
text = sprintf(atcMessageReply.ctr_already_approved,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"CTR",
|
|
extraText
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.ctr_already_approved,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"C T R",
|
|
extraVoice
|
|
);
|
|
}
|
|
else
|
|
{
|
|
text = sprintf(atcMessageReply.ctr_not_approved,
|
|
atcCallsignText,
|
|
selectedComStationName,
|
|
"CTR",
|
|
"CTR"
|
|
);
|
|
|
|
voice = sprintf(atcMessageReply.ctr_not_approved,
|
|
atcCallsignVoice,
|
|
selectedComStationName,
|
|
"C T R",
|
|
"C T R"
|
|
);
|
|
}
|
|
|
|
return [text, voice];
|
|
}
|
|
|
|
var isTerrainSafeAhead = func()
|
|
{
|
|
var safe = 0;
|
|
var aircraftPosition = geo.aircraft_position();
|
|
var pathPosition = geo.aircraft_position().apply_course_distance(property_Aircraft_HeadingDeg.getValue(), min_safety_distance_from_terrain_miles * NM2M);
|
|
|
|
var intersection = get_cart_ground_intersection({
|
|
"x":aircraftPosition.x(),
|
|
"y":aircraftPosition.y(),
|
|
"z":aircraftPosition.z()
|
|
},
|
|
{
|
|
"x":pathPosition.x()-aircraftPosition.x(),
|
|
"y":pathPosition.y()-aircraftPosition.y(),
|
|
"z":pathPosition.z()-aircraftPosition.z()
|
|
}
|
|
);
|
|
|
|
if(intersection == nil)
|
|
safe = 1;
|
|
else
|
|
{
|
|
var terrainPos = geo.Coord.new();
|
|
|
|
terrainPos.set_latlon(intersection.lat, intersection.lon, intersection.elevation);
|
|
|
|
var maxDist = aircraftPosition.direct_distance_to(pathPosition);
|
|
var terrainDist = aircraftPosition.direct_distance_to(terrainPos);
|
|
|
|
if(terrainDist < maxDist)
|
|
safe = 0;
|
|
else
|
|
safe = 1;
|
|
}
|
|
|
|
return safe;
|
|
}
|
|
|
|
var isSimulationPaused = func()
|
|
{
|
|
var paused = 0;
|
|
|
|
if(property_Simulator_Freeze.getValue() == 1 or property_Simulator_Replay.getValue() == 1)
|
|
paused = 1;
|
|
|
|
return paused;
|
|
}
|
|
|
|
var altitudeApproachSlope = func(altitude, distance, roundHundred = 0)
|
|
{
|
|
if(altitude < 0 or distance < 0)
|
|
return -1;
|
|
|
|
slopeRadians = approach_slope_angle * D2R;
|
|
ralt = math.sin(slopeRadians);
|
|
rdist = math.cos(slopeRadians);
|
|
|
|
slopeAltitude = ((distance / rdist) * ralt) * NM2FT;
|
|
|
|
slopeAltitude += altitude * M2FT;
|
|
|
|
if(roundHundred == 1)
|
|
slopeAltitude = (100 * int(slopeAltitude / 100));
|
|
|
|
return slopeAltitude;
|
|
}
|
|
|
|
var getSquawkCode = func()
|
|
{
|
|
code = squawkCode;
|
|
|
|
if(code == "" or rand() < 0.3)
|
|
{
|
|
codeOk = 0;
|
|
|
|
while(codeOk == 0)
|
|
{
|
|
tempCode = int(rand() * 7776) + 1;
|
|
|
|
codeOk = 1;
|
|
|
|
foreach(var c; reservedSquawkCodes)
|
|
{
|
|
if(tempCode == c)
|
|
codeOk = 0;
|
|
}
|
|
|
|
newCode = sprintf("0000%d", tempCode);
|
|
|
|
newCode = substr(newCode, size(newCode) - 4);
|
|
clen = size(newCode);
|
|
|
|
for(var i = 0; i < clen; i += 1)
|
|
{
|
|
if(int(chr(newCode[i])) > 7)
|
|
codeOk = 0;
|
|
}
|
|
}
|
|
|
|
code = newCode;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
var getOperatingTransponder = func()
|
|
{
|
|
if(property_Transponder1_Serviceable != nil)
|
|
{
|
|
if(property_Transponder1_Serviceable.getValue() == 1 and property_Transponder1_Operable.getValue() == 1 and property_Transponder1_KnobMode.getValue() > 3)
|
|
return 1;
|
|
}
|
|
|
|
if(property_Transponder2_Serviceable != nil)
|
|
{
|
|
if(property_Transponder2_Serviceable.getValue() == 1 and property_Transponder2_Operable.getValue() == 1 and property_Transponder2_KnobMode.getValue() > 3)
|
|
return 2;
|
|
}
|
|
|
|
if(property_Transponder3_Serviceable != nil)
|
|
{
|
|
if(property_Transponder3_Serviceable.getValue() == 1 and property_Transponder3_Operable.getValue() == 1 and property_Transponder3_KnobMode.getValue() > 3)
|
|
return 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
var checkTransponder = func(transponder)
|
|
{
|
|
var serviceable = nil;
|
|
var operable = nil;
|
|
var idcode = nil;
|
|
|
|
if(transponder == 1 and property_Transponder1_Serviceable != nil)
|
|
{
|
|
serviceable = property_Transponder1_Serviceable.getValue();
|
|
operable = property_Transponder1_Operable.getValue();
|
|
idcode = property_Transponder1_IdCode.getValue();
|
|
}
|
|
else if(transponder == 2 and property_Transponder2_Serviceable != nil)
|
|
{
|
|
serviceable = property_Transponder2_Serviceable.getValue();
|
|
operable = property_Transponder2_Operable.getValue();
|
|
idcode = property_Transponder2_IdCode.getValue();
|
|
}
|
|
else if(transponder == 3 and property_Transponder3_Serviceable != nil)
|
|
{
|
|
serviceable = property_Transponder3_Serviceable.getValue();
|
|
operable = property_Transponder3_Operable.getValue();
|
|
idcode = property_Transponder3_IdCode.getValue();
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
if(serviceable == 0)
|
|
return 0;
|
|
|
|
if(operable == 0)
|
|
return 0;
|
|
|
|
if(idcode != squawkCode)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
var checkTransponderIdent = func(transponder)
|
|
{
|
|
var ident = 0;
|
|
|
|
if(transponder == 1 and property_Transponder1_Ident != nil)
|
|
ident = property_Transponder1_Ident.getValue();
|
|
else if(transponder == 2 and property_Transponder2_Ident != nil)
|
|
ident = property_Transponder2_Ident.getValue();
|
|
else if(transponder == 3 and property_Transponder3_Ident != nil)
|
|
ident = property_Transponder3_Ident.getValue();
|
|
else
|
|
return 0;
|
|
|
|
return ident;
|
|
}
|
|
|
|
var setSquawkIdentMode = func(mode)
|
|
{
|
|
squawkIdent = mode;
|
|
|
|
if(mode == squawk_ident_off)
|
|
squawkIdentButtonPushed = 0;
|
|
|
|
squawk_check_counter = 0;
|
|
}
|
|
|
|
var getPilotVoice = func()
|
|
{
|
|
var done = 0;
|
|
var i = 0;
|
|
var pvoice = "";
|
|
var ptype = "";
|
|
var vdesc = "";
|
|
|
|
while(done == 0)
|
|
{
|
|
if(i == 0)
|
|
vprop = "/sim/sound/voices/voice";
|
|
else
|
|
vprop = sprintf("/sim/sound/voices/voice[%d]", i);
|
|
|
|
vdesc = vprop ~ "/desc";
|
|
|
|
if(getprop(vdesc) == nil)
|
|
{
|
|
done = 1;
|
|
|
|
pvoice = "/sim/sound/voices/pilot";
|
|
}
|
|
else
|
|
{
|
|
if(string.lc(getprop(vdesc)) == "pilot")
|
|
{
|
|
pvoice = props.globals.getNode(vprop ~ "/text");
|
|
|
|
if(getprop(sprintf("%s/festival", vprop)) == 1)
|
|
{
|
|
if(string.match(getprop(sprintf("%s/preamble", vprop)), "*(audio_mode 'async)*") == 1)
|
|
ptype = "festival-async";
|
|
else
|
|
ptype = "festival";
|
|
}
|
|
else
|
|
ptype = "flite";
|
|
|
|
done = 1;
|
|
}
|
|
}
|
|
|
|
i += 1;
|
|
}
|
|
|
|
return { text:pvoice, type:ptype };
|
|
}
|
|
|
|
var initAtcVoice = func()
|
|
{
|
|
synthVoice = [];
|
|
var done = 0;
|
|
var i = 0;
|
|
var vdesc = "";
|
|
|
|
synthVoice = [];
|
|
usedSynthVoice = [];
|
|
stationVoice = {};
|
|
stationVoicePool = [];
|
|
|
|
while(done == 0)
|
|
{
|
|
if(i == 0)
|
|
vprop = "/sim/sound/voices/voice";
|
|
else
|
|
vprop = sprintf("/sim/sound/voices/voice[%d]", i);
|
|
|
|
vdesc = vprop ~ "/desc";
|
|
|
|
if(getprop(vdesc) == nil)
|
|
done = 1;
|
|
else
|
|
{
|
|
if(string.lc(getprop(vdesc)) != "pilot")
|
|
{
|
|
var pvoice = {};
|
|
|
|
pvoice['text'] = props.globals.getNode(vprop ~ "/text");
|
|
|
|
if(getprop(sprintf("/sim/sound/voices/voice[%d]/festival", i)) == 1)
|
|
{
|
|
if(string.match(getprop(sprintf("/sim/sound/voices/voice[%d]/preamble", i)), "*(audio_mode 'async)*") == 1)
|
|
pvoice['type'] = "festival-async";
|
|
else
|
|
pvoice['type'] = "festival";
|
|
}
|
|
else
|
|
pvoice['type'] = "flite";
|
|
|
|
append(synthVoice, pvoice);
|
|
}
|
|
}
|
|
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
var getSynthVoice = func(frequency)
|
|
{
|
|
var voiceIsValid = 0;
|
|
var svoice = {};
|
|
var i = 0;
|
|
var vndx = 0;
|
|
var svsize = size(synthVoice);
|
|
var usvsize = size(usedSynthVoice);
|
|
var svpsize = size(stationVoicePool);
|
|
|
|
if(frequency == "")
|
|
{
|
|
if(svsize > 0)
|
|
return synthVoice[0];
|
|
else
|
|
return { text:"/sim/sound/voices/voice/atc", type:"flite" };
|
|
}
|
|
|
|
if(svpsize > 0)
|
|
{
|
|
for(i = 0; i < svpsize; i += 1)
|
|
{
|
|
svoice = stationVoicePool[i];
|
|
|
|
if(svoice['frequency'] == frequency)
|
|
return svoice;
|
|
}
|
|
}
|
|
|
|
voiceIsValid = 0;
|
|
|
|
while(voiceIsValid == 0)
|
|
{
|
|
vndx = int(rand() * svsize);
|
|
|
|
voiceIsValid = 1;
|
|
|
|
foreach(var usv; usedSynthVoice)
|
|
{
|
|
if(usv['index'] == vndx)
|
|
voiceIsValid = 0;
|
|
}
|
|
}
|
|
|
|
svoice = {};
|
|
|
|
svoice['index'] = vndx;
|
|
svoice['text'] = synthVoice[vndx]['text'];
|
|
svoice['type'] = synthVoice[vndx]['type'];
|
|
svoice['frequency'] = frequency;
|
|
|
|
append(usedSynthVoice, svoice);
|
|
|
|
append(stationVoicePool, svoice);
|
|
|
|
if(size(usedSynthVoice) == svsize)
|
|
usedSynthVoice = [];
|
|
|
|
return svoice;
|
|
}
|
|
|
|
var speak = func(text, voice, type)
|
|
{
|
|
if(type == "festival-async")
|
|
{
|
|
var tpart = split(",", text);
|
|
|
|
foreach(var t; tpart)
|
|
{
|
|
var tpart1 = split("\n", t);
|
|
|
|
foreach(var t1; tpart1)
|
|
voice.setValue(t1 ~ ".");
|
|
}
|
|
}
|
|
else
|
|
voice.setValue(text);
|
|
}
|
|
|
|
var autoATCMessageDelay = func(seconds)
|
|
{
|
|
ctr_update_counter -= seconds;
|
|
ctr_check_counter -= seconds;
|
|
|
|
terrain_warning_counter -= seconds;
|
|
|
|
if(terrain_warning_counter < 0)
|
|
terrain_warning_counter = 0;
|
|
|
|
altitude_check_counter -= seconds;
|
|
|
|
if(altitude_check_counter < 0)
|
|
altitude_check_counter = 0;
|
|
|
|
squawk_check_counter -= seconds;
|
|
|
|
if(squawk_check_counter < 0)
|
|
squawk_check_counter = 0;
|
|
|
|
approach_check_counter -= seconds;
|
|
|
|
if(approach_check_counter < 0)
|
|
approach_check_counter = 0;
|
|
}
|