I'm working on this atc.nas script, and it's time to submit to you the beta version.
This code is not intended to compete with FGComm, Festival or other similar facilities. On the contrary, their use is indicated when they are not available (eg, few hardware resources, no Internet connection, etc.)
1.- How to use it
Once installed, tune Comm1 to the desired frequency and press the ">" key to transmit your request.
You will hear the ATC's answer according the standard VFR phraseology, depending on your current position:
- * If you are on ground => The script interprets it's a taxi request (if you are far from the runway) or a take-off request (if you are on the correct Runway or at his holding point).
* If you are flying => The script interprets it's an approach request (if you tunned an Approach freq.), or a landing request (if you tunned a Tower one).
2.- How to install it
Include theese lines into your $FGFS_ROOT/keyboard.xml file:
- Code: Select all
<key n="60">
<name>less-than</name>
<desc>Spoken ATC</desc>
<binding>
<command>nasal</command>
<script>
atc.speak()
</script>
</binding>
</key>
and copy&paste this code into a new $FGFS_ROOT/Nasal/atc.nas file:
- Code: Select all
# ** atc.nas (save in $FG_ROOT/Nasal) **
# ** v.: 0.1 beta **
# ********************************************
# ** by Rodolfo Leibner (rleibner@gmail.com) **
# ** Comments & enheacements are wellcome **
var speak = func() {
# **** spell func. **************************
var spell = func(str) {
var s = split("",str);
for(var i=0;i<size(s);i=i+1) {
if(streq(s[i],".")) s[i]="point" ;
}
return string.join(" ",s);
};
# **** abc func. *****************************
var abc = func(str) {
var alpha = {A:"alpha", B:"bravo", C:"charlie", D:"delta", E:"echo", F:"foxtrot",
G:"golf", H:"hotel", I:"india", J:"juliet", K:"kilo", L:"lima", M:"mike",
N:"november", O:"oscar", P:"papa",Q:"quebec", R:"romeo", S:"sierra",
T:"tango", U:"uniform", V:"victor", W:"whiskey", X:"X ray", Y:"yanki", Z:"zulu"};
var s = split("",str);
for(var i=0;i<size(s);i=i+1) {
if(int(s[i])==nil) s[i]=alpha[s[i]]; # Translate only letters
};
return string.join(" ",s);
};
# *** Main ****************************************
# 1) Initialization
var a=call(func {
return getprop("/instrumentation/comm/spk-atc");
}, nil, nil, nil,);
if(a==nil) setprop("/instrumentation/comm/spk-atc", 0.0);
# 2) Check comm frequency
var cs = sprintf(getprop("/ai/models/aircraft/callsign"));
var icao = getprop("/instrumentation/comm/airport-id");
var info = airportinfo(icao);
var qlty = getprop("/instrumentation/comm/signal-quality-norm");
var station_type = sprintf(getprop("/instrumentation/comm/station-type"));
var atc = string.replace(info.name,"Intl","International") ~" "~station_type;
if((atc==nil)or(qlty<0.01)) { # if invalid freq or out of range
gui.popupTip("Check comm freq.!",3);
die("Check comm freq.");}
# 3) Get env. values
var q = sprintf("%.2f",getprop("/environment/metar/pressure-sea-level-inhg"));
var qnh = spell(sprintf("%d",q/0.02953));
var wd = sprintf("%d",getprop("/environment/metar/base-wind-dir-deg"));
var wv = sprintf("%d",getprop("/environment/metar/base-wind-speed-kt"));
var rws = info.runways;
# 4) choose best rwy
var best = "";
var ang = 180.0;
foreach(var rw; keys(rws)){
var a = abs(info.runways[rw].heading - getprop("/environment/metar/base-wind-dir-deg"));
if(a<ang) {
ang = a;
best = rw;}
}
# 5) Check current position
var pos_v = (getprop("/position/altitude-agl-ft") < 30)? "onground": "flying";
var to = {lat: info.runways[rw].lat, lon: info.runways[rw].lon};
var (course, dist) = courseAndDistance(to);
var pos_h = ((dist * NM2M) < 100)? "onrwy": "far";
# 6) Choose pertinent instruction
var tunned = getprop("/instrumentation/comm/frequencies/selected-mhz");
var voice = (getprop("/instrumentation/comm/spk-atc")==tunned)? abc(cs): abc(cs)~ ". This is " ~atc ;
var tip = "";
if(streq(pos_v,"onground")) {
if(streq(pos_h,"far")) { # Request for Taxi
voice ~= ". Taxi to holding point Runway " ~spell(best) ~" and Contact when ready.";
tip = " Rwy: " ~best ;
} elsif (!streq(station_type, "tower")) { # yet on rwy => Request for Takeoff
voice ~= ". Contact Tower." ;
} else {
voice ~= ". Runway " ~spell(best) ~", cleared for takeoff, wind "~spell(wd) ~" degrees " ~spell(wv) ~" knots";
tip = " Wind: " ~wd ~" deg. " ~wv ~" kt.\n Rwy: " ~best ~"\n Cleared for takeoff";
}
} elsif (streq(station_type, "tower")) { # flying => Request for landing.
voice ~= ". Runway " ~spell(best) ~", cleared to land, wind "~spell(wd) ~" degrees " ~spell(wv) ~" knots.";
tip = " Cleared to land " ~best ;
} elsif (string.match(station_type, "approach*")) { # Request for approach.
voice ~". Make approach Runway " ~spell(best) ~", wind "~spell(wd) ~" degrees " ~spell(wv) ~" knots."
~" QNH " ~qnh ~" or " ~q ~"inches and contact Tower.";
tip = " Approach Rwy " ~best ;
} else {
voice ~= ". Contact Tower." ;
}
# 7) Speach instruction
gui.popupTip(info.name ~":\n" ~tip,5);
setprop("/sim/sound/voices/atc", voice);
setprop("/instrumentation/comm/spk-atc", tunned);
};
I count on your collaboration to debug, improve and optimize this beta.
Regards,