1
0
Fork 0

Further progress towards interactive ATC control

This commit is contained in:
daveluff 2003-11-05 10:06:57 +00:00
parent f4b3bad58e
commit 6162d4462b
6 changed files with 387 additions and 120 deletions

View file

@ -65,8 +65,9 @@ void FGATC::SetResponseReqd(string rid) {
respond = false; // TODO - this ignores the fact that more than one plane could call this before response respond = false; // TODO - this ignores the fact that more than one plane could call this before response
// Shouldn't happen with AI only, but user could confuse things?? // Shouldn't happen with AI only, but user could confuse things??
responseID = rid; responseID = rid;
runResponseCounter = true;
responseCounter = 0.0; responseCounter = 0.0;
responseTime = 2.5; // TODO - randomize this slightly. responseTime = 1.8; // TODO - randomize this slightly.
} }
void FGATC::NotifyTransmissionFinished(string rid) { void FGATC::NotifyTransmissionFinished(string rid) {
@ -75,7 +76,7 @@ void FGATC::NotifyTransmissionFinished(string rid) {
if(responseReqd) { if(responseReqd) {
runResponseCounter = true; runResponseCounter = true;
responseCounter = 0.0; responseCounter = 0.0;
responseTime = 2.5; // TODO - randomize this slightly. responseTime = 1.8; // TODO - randomize this slightly.
} else { } else {
freqClear = true; freqClear = true;
} }
@ -165,6 +166,11 @@ void FGATC::NoRender(string refname) {
} }
} }
// Generate the text of a message from its parameters and the current context.
string FGATC::GenText(const string& m, int c) {
return("");
}
ostream& operator << (ostream& os, atc_type atc) { ostream& operator << (ostream& os, atc_type atc) {
switch(atc) { switch(atc) {
case(INVALID): return(os << "INVALID"); case(INVALID): return(os << "INVALID");

View file

@ -126,6 +126,9 @@ public:
// Indicate that this instance should not output to the display // Indicate that this instance should not output to the display
virtual void SetNoDisplay(); virtual void SetNoDisplay();
// Generate the text of a message from its parameters and the current context.
virtual string GenText(const string& m, int c);
// Returns true if OK to transmit on this frequency // Returns true if OK to transmit on this frequency
inline bool GetFreqClear() { return freqClear; } inline bool GetFreqClear() { return freqClear; }
// Indicate that the frequency is in use // Indicate that the frequency is in use
@ -242,15 +245,15 @@ operator >> ( istream& fin, ATCData& a )
a.name = ""; a.name = "";
fin >> ch; fin >> ch;
a.name += ch; if(ch != '"') a.name += ch;
while(1) { while(1) {
//in >> noskipws //in >> noskipws
fin.unsetf(ios::skipws); fin.unsetf(ios::skipws);
fin >> ch; fin >> ch;
a.name += ch;
if((ch == '"') || (ch == 0x0A)) { if((ch == '"') || (ch == 0x0A)) {
break; break;
} // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the " } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the "
a.name += ch;
} }
fin.setf(ios::skipws); fin.setf(ios::skipws);
//cout << "Comm name = " << a.name << '\n'; //cout << "Comm name = " << a.name << '\n';

View file

@ -28,6 +28,7 @@
#include "ATCDialog.hxx" #include "ATCDialog.hxx"
#include "ATC.hxx" #include "ATC.hxx"
#include "ATCmgr.hxx" #include "ATCmgr.hxx"
#include "ATCdisplay.hxx"
#include "commlist.hxx" #include "commlist.hxx"
#include "ATCutils.hxx" #include "ATCutils.hxx"
#include <Airports/simple.hxx> #include <Airports/simple.hxx>
@ -93,33 +94,12 @@ static puText* atcFreqDisplayText[ATC_MAX_FREQ_DISPLAY];
// -------------------------------------------------------------- // --------------------------------------------------------------
//////////////// Popup callbacks /////////////////// //////////////// Popup callbacks ///////////////////
static void ATCDialogOK(puObject *) static void ATCDialogOK(puObject*) {
{ current_atcdialog->PopupCallback();
switch(atcDialogCommunicationOptions->getValue()) {
case 0:
//cout << "Option 0 chosen\n";
fgSetBool("/sim/atc/opt0",true);
break;
case 1:
//cout << "Option 1 chosen\n";
fgSetBool("/sim/atc/opt1",true);
break;
case 2:
//cout << "Option 2 chosen\n";
fgSetBool("/sim/atc/opt2",true);
break;
case 3:
//cout << "Option 2 chosen\n";
fgSetBool("/sim/atc/opt3",true);
break;
default:
break;
}
FG_POP_PUI_DIALOG( atcDialog ); FG_POP_PUI_DIALOG( atcDialog );
} }
static void ATCDialogCancel(puObject *) static void ATCDialogCancel(puObject*) {
{
FG_POP_PUI_DIALOG( atcDialog ); FG_POP_PUI_DIALOG( atcDialog );
} }
////////////////////////////////////////////////// //////////////////////////////////////////////////
@ -143,6 +123,11 @@ static void FreqDisplayOK(puObject*) {
FGATCDialog::FGATCDialog() { FGATCDialog::FGATCDialog() {
_callbackPending = false;
_callbackTimer = 0.0;
_callbackWait = 0.0;
_callbackPtr = NULL;
_callbackCode = 0;
} }
FGATCDialog::~FGATCDialog() { FGATCDialog::~FGATCDialog() {
@ -247,6 +232,18 @@ void FGATCDialog::Init() {
FG_FINALIZE_PUI_DIALOG(atcDialog); FG_FINALIZE_PUI_DIALOG(atcDialog);
} }
void FGATCDialog::Update(double dt) {
if(_callbackPending) {
if(_callbackTimer > _callbackWait) {
_callbackPtr->ReceiveUserCallback(_callbackCode);
_callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
_callbackPending = false;
} else {
_callbackTimer += dt;
}
}
}
// Add an entry // Add an entry
void FGATCDialog::add_entry(string station, string transmission, string menutext, atc_type type, int code) { void FGATCDialog::add_entry(string station, string transmission, string menutext, atc_type type, int code) {
@ -389,7 +386,39 @@ void FGATCDialog::PopupDialog() {
FG_PUSH_PUI_DIALOG(atcDialog); FG_PUSH_PUI_DIALOG(atcDialog);
} }
void FGATCDialog::PopupCallback() {
FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // FIXME - Hardwired to comm1 at the moment
if(atcptr) {
if(atcptr->GetType() == APPROACH) {
switch(atcDialogCommunicationOptions->getValue()) {
case 0:
fgSetBool("/sim/atc/opt0",true);
break;
case 1:
fgSetBool("/sim/atc/opt1",true);
break;
case 2:
fgSetBool("/sim/atc/opt2",true);
break;
case 3:
fgSetBool("/sim/atc/opt3",true);
break;
default:
break;
}
} else if(atcptr->GetType() == TOWER) {
ATCMenuEntry a = ((available_dialog[TOWER])[(string)atcptr->get_ident()])[atcDialogCommunicationOptions->getValue()];
atcptr->SetFreqInUse();
globals->get_ATC_display()->RegisterSingleMessage(atcptr->GenText(a.transmission, a.callback_code));
_callbackPending = true;
_callbackTimer = 0.0;
_callbackWait = 5.0;
_callbackPtr = atcptr;
_callbackCode = a.callback_code;
}
}
}
void FGATCDialog::FreqDialog() { void FGATCDialog::FreqDialog() {

View file

@ -60,16 +60,22 @@ public:
void Init(); void Init();
void Update(double dt);
void PopupDialog(); void PopupDialog();
void PopupCallback();
void add_entry( string station, string transmission, string menutext, atc_type type, int code); void add_entry( string station, string transmission, string menutext, atc_type type, int code);
void remove_entry( const string &station, const string &trans, atc_type type ); void remove_entry( const string &station, const string &trans, atc_type type );
void remove_entry( const string &station, int code, atc_type type ); void remove_entry( const string &station, int code, atc_type type );
// query the database whether the transmission is already registered;
bool trans_reg( const string &station, const string &trans, atc_type type ); bool trans_reg( const string &station, const string &trans, atc_type type );
// query the database whether the transmission is already registered;
bool trans_reg( const string &station, int code, atc_type type ); bool trans_reg( const string &station, int code, atc_type type );
// Display a frequency search dialog for nearby stations // Display a frequency search dialog for nearby stations
@ -86,6 +92,11 @@ private:
int freq; int freq;
bool reset; bool reset;
bool _callbackPending;
double _callbackTimer;
double _callbackWait;
FGATC* _callbackPtr;
int _callbackCode;
}; };
extern FGATCDialog *current_atcdialog; extern FGATCDialog *current_atcdialog;

View file

@ -27,6 +27,7 @@
#include "ATCdisplay.hxx" #include "ATCdisplay.hxx"
#include "ATCmgr.hxx" #include "ATCmgr.hxx"
#include "ATCutils.hxx" #include "ATCutils.hxx"
#include "ATCDialog.hxx"
#include "commlist.hxx" #include "commlist.hxx"
#include "AILocalTraffic.hxx" #include "AILocalTraffic.hxx"
@ -47,6 +48,8 @@ finalAcknowledged(false),
instructedToGoAround(false), instructedToGoAround(false),
onRwy(false), onRwy(false),
nextOnRwy(false), nextOnRwy(false),
vfrArrivalReported(false),
vfrArrivalAcknowledged(false),
opType(TTT_UNKNOWN), opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN), leg(LEG_UNKNOWN),
landingType(AIP_LT_UNKNOWN), landingType(AIP_LT_UNKNOWN),
@ -68,6 +71,8 @@ finalAcknowledged(false),
instructedToGoAround(false), instructedToGoAround(false),
onRwy(false), onRwy(false),
nextOnRwy(false), nextOnRwy(false),
vfrArrivalReported(false),
vfrArrivalAcknowledged(false),
opType(TTT_UNKNOWN), opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN), leg(LEG_UNKNOWN),
landingType(AIP_LT_UNKNOWN), landingType(AIP_LT_UNKNOWN),
@ -89,6 +94,8 @@ finalAcknowledged(false),
instructedToGoAround(false), instructedToGoAround(false),
onRwy(false), onRwy(false),
nextOnRwy(false), nextOnRwy(false),
vfrArrivalReported(false),
vfrArrivalAcknowledged(false),
opType(TTT_UNKNOWN), opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN), leg(LEG_UNKNOWN),
landingType(AIP_LT_UNKNOWN), landingType(AIP_LT_UNKNOWN),
@ -111,6 +118,8 @@ finalAcknowledged(false),
instructedToGoAround(false), instructedToGoAround(false),
onRwy(false), onRwy(false),
nextOnRwy(false), nextOnRwy(false),
vfrArrivalReported(false),
vfrArrivalAcknowledged(false),
opType(TTT_UNKNOWN), opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN), leg(LEG_UNKNOWN),
landingType(AIP_LT_UNKNOWN), landingType(AIP_LT_UNKNOWN),
@ -128,8 +137,6 @@ isUser(false)
Currently user is assumed to have taken off again when leaving the runway - check speed/elev for taxiing-in. Currently user is assumed to have taken off again when leaving the runway - check speed/elev for taxiing-in.
AI plane lands even when user on rwy - make it go-around instead.
Tell AI plane to contact ground when taxiing in. Tell AI plane to contact ground when taxiing in.
Use track instead of heading to determine what leg of the circuit the user is flying. Use track instead of heading to determine what leg of the circuit the user is flying.
@ -242,8 +249,8 @@ void FGTower::Init() {
if(rwyOccupied) { if(rwyOccupied) {
// Assume the user is started at the threshold ready to take-off // Assume the user is started at the threshold ready to take-off
TowerPlaneRec* t = new TowerPlaneRec; TowerPlaneRec* t = new TowerPlaneRec;
t->plane.callsign = "Charlie Foxtrot Sierra"; // C-FGFS !!! - fixme - this is a bit hardwired t->plane.callsign = fgGetString("/sim/user/callsign");
t->plane.type = GA_SINGLE; t->plane.type = GA_SINGLE; // FIXME - hardwired!!
t->opType = TTT_UNKNOWN; // We don't know if the user wants to do circuits or a departure... t->opType = TTT_UNKNOWN; // We don't know if the user wants to do circuits or a departure...
t->landingType = AIP_LT_UNKNOWN; t->landingType = AIP_LT_UNKNOWN;
t->leg = TAKEOFF_ROLL; t->leg = TAKEOFF_ROLL;
@ -252,6 +259,10 @@ void FGTower::Init() {
t->clearedToTakeOff = true; t->clearedToTakeOff = true;
rwyList.push_back(t); rwyList.push_back(t);
departed = false; departed = false;
} else {
// For now assume that this means the user is not at the airport and is in the air.
// TODO FIXME - this will break when user starts on apron, at hold short, etc.
current_atcdialog->add_entry(ident, "@AP Tower @CS @MI miles @CD of the airport for full stop with the ATIS", "Contact tower for VFR arrival (full stop)", TOWER, (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
} }
} }
@ -274,6 +285,7 @@ void FGTower::Update(double dt) {
cout << update_count << "\ttL: " << trafficList.size() << " cL: " << circuitList.size() << " hL: " << holdList.size() << " aL: " << appList.size() << '\n'; cout << update_count << "\ttL: " << trafficList.size() << " cL: " << circuitList.size() << " hL: " << holdList.size() << " aL: " << appList.size() << '\n';
} }
*/ */
//if(ident == "EGNX") cout << display << '\n';
if(departed != false) { if(departed != false) {
timeSinceLastDeparture += dt; timeSinceLastDeparture += dt;
@ -368,17 +380,36 @@ void FGTower::Update(double dt) {
} }
void FGTower::ReceiveUserCallback(int code) { void FGTower::ReceiveUserCallback(int code) {
if(code == (int)USER_REQUEST_DEPARTURE) { if(code == (int)USER_REQUEST_VFR_DEPARTURE) {
cout << "User requested departure\n"; cout << "User requested departure\n";
} else if(code == (int)USER_REQUEST_VFR_ARRIVAL) {
VFRArrivalContact("USER");
} else if(code == (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP) {
VFRArrivalContact("USER", FULL_STOP);
} else if(code == (int)USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO) {
VFRArrivalContact("USER", TOUCH_AND_GO);
} }
} }
void FGTower::Respond() { void FGTower::Respond() {
//cout << "Entering Respond..." << endl; cout << "Entering Respond, responseID = " << responseID << endl;
TowerPlaneRec* t = FindPlane(responseID); TowerPlaneRec* t = FindPlane(responseID);
if(t) { if(t) {
// This will grow!!! // This will grow!!!
if(t->downwindReported) { if(t->vfrArrivalReported && !t->vfrArrivalAcknowledged) {
// Testing - hardwire straight in for now
string trns = t->plane.callsign;
trns += " ";
trns += name;
trns += " tower Report three mile straight in for runway ";
trns += ConvertRwyNumToSpokenString(activeRwy);
if(display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
} else {
cout << "Not displaying, trns was " << trns << '\n';
}
t->vfrArrivalAcknowledged = true;
} else if(t->downwindReported) {
t->downwindReported = false; t->downwindReported = false;
int i = 1; int i = 1;
for(tower_plane_rec_list_iterator twrItr = circuitList.begin(); twrItr != circuitList.end(); twrItr++) { for(tower_plane_rec_list_iterator twrItr = circuitList.begin(); twrItr != circuitList.end(); twrItr++) {
@ -1384,28 +1415,51 @@ void FGTower::RegisterAIPlane(PlaneRec plane, FGAIPlane* ai, tower_traffic_type
doThresholdUseOrder(); doThresholdUseOrder();
} }
void FGTower::RequestLandingClearance(string ID) { // Contact tower for VFR approach
// eg "Cessna Charlie Foxtrot Golf Foxtrot Sierra eight miles South of the airport for full stop with Bravo"
// This function probably only called via user interaction - AI planes will have an overloaded function taking a planerec.
// opt defaults to AIP_LT_UNKNOWN
void FGTower::VFRArrivalContact(string ID, LandingType opt) {
//cout << "Request Landing Clearance called...\n"; //cout << "Request Landing Clearance called...\n";
// Assume this comes from the user - have another function taking a pointer to the AIplane for the AI traffic. // For now we'll assume that the user is a light plane and can get him/her to join the circuit if necessary.
// For now we'll also assume that the user is a light plane and can get him/her to join the circuit if necessary.
TowerPlaneRec* t = new TowerPlaneRec; TowerPlaneRec* t;
string usercall = fgGetString("/sim/user/callsign");
if(ID == "USER" || ID == usercall) {
t = FindPlane(usercall);
if(!t) {
cout << "NOT t\n";
t = new TowerPlaneRec;
t->isUser = true; t->isUser = true;
t->clearedToLand = false;
t->pos.setlon(user_lon_node->getDoubleValue()); t->pos.setlon(user_lon_node->getDoubleValue());
t->pos.setlat(user_lat_node->getDoubleValue()); t->pos.setlat(user_lat_node->getDoubleValue());
t->pos.setelev(user_elev_node->getDoubleValue()); t->pos.setelev(user_elev_node->getDoubleValue());
} else {
cout << "IS t\n";
// Oops - the plane is already registered with this tower - maybe we took off and flew a giant circuit without
// quite getting out of tower airspace - just ignore for now and treat as new arrival.
// TODO - Maybe should remove from departure and circuit list if in there though!!
}
} else {
// Oops - something has gone wrong - put out a warning
cout << "WARNING - FGTower::VFRContact(string ID, LandingType lt) called with ID " << ID << " which does not appear to be the user.\n";
return;
}
// TODO // TODO
// Calculate where the user is in relation to the active runway and it's circuit // Calculate where the plane is in relation to the active runway and it's circuit
// and set the op-type as appropriate. // and set the op-type as appropriate.
// HACK - to get up and running I'm going to assume that the user contacts tower on a staight-in final for now. // HACK - to get up and running I'm going to assume that the user contacts tower on a staight-in final for now.
t->opType = STRAIGHT_IN; t->opType = STRAIGHT_IN;
t->plane.type = GA_SINGLE; // FIXME - Another assumption! t->plane.type = GA_SINGLE; // FIXME - Another assumption!
t->plane.callsign = ID; t->plane.callsign = usercall;
t->vfrArrivalReported = true;
responseReqd = true;
appList.push_back(t); // Not necessarily permanent appList.push_back(t); // Not necessarily permanent
AddToTrafficList(t); AddToTrafficList(t);
@ -1468,6 +1522,159 @@ void FGTower::ReportDownwind(string ID) {
} }
} }
string FGTower::GenText(const string& m, int c) {
const int cmax = 300;
//string message;
char tag[4];
char crej = '@';
char mes[cmax];
char dum[cmax];
//char buf[10];
char *pos;
int len;
//FGTransmission t;
string usercall = fgGetString("/sim/user/callsign");
//transmission_list_type tmissions = transmissionlist_station[station];
//transmission_list_iterator current = tmissions.begin();
//transmission_list_iterator last = tmissions.end();
//for ( ; current != last ; ++current ) {
// if ( current->get_code().c1 == code.c1 &&
// current->get_code().c2 == code.c2 &&
// current->get_code().c3 == code.c3 ) {
//if ( ttext ) message = current->get_transtext();
//else message = current->get_menutext();
strcpy( &mes[0], m.c_str() );
// Replace all the '@' parameters with the actual text.
int check = 0; // If mes gets overflowed the while loop can go infinite
while ( strchr(&mes[0], crej) != NULL ) { // ie. loop until no more occurances of crej ('@') found
pos = strchr( &mes[0], crej );
bcopy(pos, &tag[0], 3);
tag[3] = '\0';
int i;
len = 0;
for ( i=0; i<cmax; i++ ) {
if ( mes[i] == crej ) {
len = i;
break;
}
}
strncpy( &dum[0], &mes[0], len );
dum[len] = '\0';
if ( strcmp ( tag, "@ST" ) == 0 )
//strcat( &dum[0], tpars.station.c_str() );
strcat(&dum[0], ident.c_str());
else if ( strcmp ( tag, "@AP" ) == 0 )
//strcat( &dum[0], tpars.airport.c_str() );
strcat(&dum[0], name.c_str());
else if ( strcmp ( tag, "@CS" ) == 0 )
//strcat( &dum[0], tpars.callsign.c_str() );
strcat(&dum[0], usercall.c_str());
else if ( strcmp ( tag, "@TD" ) == 0 ) {
/*
if ( tpars.tdir == 1 ) {
char buf[] = "left";
strcat( &dum[0], &buf[0] );
}
else {
char buf[] = "right";
strcat( &dum[0], &buf[0] );
}
*/
}
else if ( strcmp ( tag, "@HE" ) == 0 ) {
/*
char buf[10];
sprintf( buf, "%i", (int)(tpars.heading) );
strcat( &dum[0], &buf[0] );
*/
}
else if ( strcmp ( tag, "@VD" ) == 0 ) {
/*
if ( tpars.VDir == 1 ) {
char buf[] = "Descend and maintain";
strcat( &dum[0], &buf[0] );
}
else if ( tpars.VDir == 2 ) {
char buf[] = "Maintain";
strcat( &dum[0], &buf[0] );
}
else if ( tpars.VDir == 3 ) {
char buf[] = "Climb and maintain";
strcat( &dum[0], &buf[0] );
}
*/
}
else if ( strcmp ( tag, "@AL" ) == 0 ) {
/*
char buf[10];
sprintf( buf, "%i", (int)(tpars.alt) );
strcat( &dum[0], &buf[0] );
*/
}
else if ( strcmp ( tag, "@MI" ) == 0 ) {
char buf[10];
//sprintf( buf, "%3.1f", tpars.miles );
int dist_miles = dclGetHorizontalSeparation(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue())) / 1600;
sprintf(buf, "%i", dist_miles);
strcat( &dum[0], &buf[0] );
}
else if ( strcmp ( tag, "@FR" ) == 0 ) {
/*
char buf[10];
sprintf( buf, "%6.2f", tpars.freq );
strcat( &dum[0], &buf[0] );
*/
}
else if ( strcmp ( tag, "@RW" ) == 0 ) {
strcat(&dum[0], ConvertRwyNumToSpokenString(activeRwy).c_str());
} else if(strcmp(tag, "@CD") == 0) { // @CD = compass direction
double h = GetHeadingFromTo(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
while(h < 0.0) h += 360.0;
while(h > 360.0) h -= 360.0;
if(h < 22.5 || h > 337.5) {
strcat(&dum[0], "North");
} else if(h < 67.5) {
strcat(&dum[0], "North-East");
} else if(h < 112.5) {
strcat(&dum[0], "East");
} else if(h < 157.5) {
strcat(&dum[0], "South-East");
} else if(h < 202.5) {
strcat(&dum[0], "South");
} else if(h < 247.5) {
strcat(&dum[0], "South-West");
} else if(h < 292.5) {
strcat(&dum[0], "West");
} else {
strcat(&dum[0], "North-West");
}
} else {
cout << "Tag " << tag << " not found" << endl;
break;
}
strcat( &dum[0], &mes[len+3] );
strcpy( &mes[0], &dum[0] );
++check;
if(check > 10) {
SG_LOG(SG_ATC, SG_WARN, "WARNING: Possibly endless loop terminated in FGTransmissionlist::gen_text(...)");
break;
}
}
//cout << mes << endl;
//break;
//}
//}
if ( mes != "" ) return mes;
else return "No transmission found";
}
ostream& operator << (ostream& os, tower_traffic_type ttt) { ostream& operator << (ostream& os, tower_traffic_type ttt) {
switch(ttt) { switch(ttt) {
case(CIRCUIT): return(os << "CIRCUIT"); case(CIRCUIT): return(os << "CIRCUIT");

View file

@ -54,8 +54,10 @@ enum tower_traffic_type {
ostream& operator << (ostream& os, tower_traffic_type ttt); ostream& operator << (ostream& os, tower_traffic_type ttt);
enum tower_callback_type { enum tower_callback_type {
USER_REQUEST_DEPARTURE = 1, USER_REQUEST_VFR_DEPARTURE = 1,
USER_REQUEST_ARRIVAL = 2 USER_REQUEST_VFR_ARRIVAL = 2,
USER_REQUEST_VFR_ARRIVAL_FULL_STOP = 3,
USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO = 4
}; };
// TODO - need some differentiation of IFR and VFR traffic in order to give the former priority. // TODO - need some differentiation of IFR and VFR traffic in order to give the former priority.
@ -91,6 +93,9 @@ public:
bool onRwy; // is physically on the runway bool onRwy; // is physically on the runway
bool nextOnRwy; // currently projected by tower to be the next on the runway bool nextOnRwy; // currently projected by tower to be the next on the runway
bool vfrArrivalReported;
bool vfrArrivalAcknowledged;
// Type of operation the plane is doing // Type of operation the plane is doing
tower_traffic_type opType; tower_traffic_type opType;
@ -121,7 +126,11 @@ public:
void ReceiveUserCallback(int code); void ReceiveUserCallback(int code);
void RequestLandingClearance(string ID); // Contact tower for VFR approach
// eg "Cessna Charlie Foxtrot Golf Foxtrot Sierra eight miles South of the airport for full stop with Bravo"
// This function probably only called via user interaction - AI planes will have an overloaded function taking a planerec.
void VFRArrivalContact(string ID, LandingType opt = AIP_LT_UNKNOWN);
void RequestDepartureClearance(string ID); void RequestDepartureClearance(string ID);
void ReportFinal(string ID); void ReportFinal(string ID);
void ReportLongFinal(string ID); void ReportLongFinal(string ID);
@ -159,6 +168,8 @@ public:
bool GetDownwindConstraint(double& dpos); bool GetDownwindConstraint(double& dpos);
bool GetBaseConstraint(double& bpos); bool GetBaseConstraint(double& bpos);
string GenText(const string& m, int c);
private: private:
FGATCMgr* ATCmgr; FGATCMgr* ATCmgr;
// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code! // This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!