]> git.mxchange.org Git - flightgear.git/commitdiff
Further progress towards interactive ATC control
authordaveluff <daveluff>
Wed, 5 Nov 2003 10:06:57 +0000 (10:06 +0000)
committerdaveluff <daveluff>
Wed, 5 Nov 2003 10:06:57 +0000 (10:06 +0000)
src/ATC/ATC.cxx
src/ATC/ATC.hxx
src/ATC/ATCDialog.cxx
src/ATC/ATCDialog.hxx
src/ATC/tower.cxx
src/ATC/tower.hxx

index 3bc1f0607716870647885ec86d3632b84f452a71..7adb85c4f7d97b00d45f5cd005858ae6d9ba14f4 100644 (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
                                                // Shouldn't happen with AI only, but user could confuse things??
        responseID = rid;
+       runResponseCounter = true;
        responseCounter = 0.0;
-       responseTime = 2.5;             // TODO - randomize this slightly.
+       responseTime = 1.8;             // TODO - randomize this slightly.
 }
 
 void FGATC::NotifyTransmissionFinished(string rid) {
@@ -75,7 +76,7 @@ void FGATC::NotifyTransmissionFinished(string rid) {
        if(responseReqd) {
                runResponseCounter = true;
                responseCounter = 0.0;
-               responseTime = 2.5;             // TODO - randomize this slightly.
+               responseTime = 1.8;             // TODO - randomize this slightly.
        } else {
                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) {
        switch(atc) {
                case(INVALID):    return(os << "INVALID");
index ca6689d36b5d709a294f3fb54af84b754c93379b..c0ba92241cdb76bd53346bfe9826ce5ff8e2e24a 100644 (file)
@@ -126,6 +126,9 @@ public:
        // Indicate that this instance should not output to the display
        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
        inline bool GetFreqClear() { return freqClear; }
        // Indicate that the frequency is in use
@@ -242,15 +245,15 @@ operator >> ( istream& fin, ATCData& a )
        
        a.name = "";
        fin >> ch;
-       a.name += ch;
+       if(ch != '"') a.name += ch;
        while(1) {
                //in >> noskipws
                fin.unsetf(ios::skipws);
                fin >> ch;
-               a.name += ch;
                if((ch == '"') || (ch == 0x0A)) {
                        break;
                }   // 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);
        //cout << "Comm name = " << a.name << '\n';
index 6b55eb7708562d9f60083ab980a1b6b3133c1cac..8d390f1b874d476dc613ab9fab0224ecc85e29a3 100644 (file)
@@ -28,6 +28,7 @@
 #include "ATCDialog.hxx"
 #include "ATC.hxx"
 #include "ATCmgr.hxx"
+#include "ATCdisplay.hxx"
 #include "commlist.hxx"
 #include "ATCutils.hxx"
 #include <Airports/simple.hxx>
@@ -67,12 +68,12 @@ static void atcUppercase(string &s) {
 }
 
 // ----------------------- Popup Dialog Statics------------------
-static puDialogBox*            atcDialog;
-static puFrame*                        atcDialogFrame;
-static puText*                 atcDialogMessage;
-static puOneShot*              atcDialogOkButton;
-static puOneShot*              atcDialogCancelButton;
-static puButtonBox*            atcDialogCommunicationOptions;
+static puDialogBox*     atcDialog;
+static puFrame*         atcDialogFrame;
+static puText*          atcDialogMessage;
+static puOneShot*       atcDialogOkButton;
+static puOneShot*       atcDialogCancelButton;
+static puButtonBox*     atcDialogCommunicationOptions;
 // --------------------------------------------------------------
 
 // ----------------------- Freq Dialog Statics-------------------
@@ -93,33 +94,12 @@ static puText*          atcFreqDisplayText[ATC_MAX_FREQ_DISPLAY];
 // --------------------------------------------------------------
 
 //////////////// Popup callbacks ///////////////////
-static void ATCDialogOK(puObject *)
-{
-       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;
-       }
+static void ATCDialogOK(puObject*) {
+       current_atcdialog->PopupCallback();
        FG_POP_PUI_DIALOG( atcDialog );
 }
 
-static void ATCDialogCancel(puObject *)
-{
+static void ATCDialogCancel(puObject*) {
     FG_POP_PUI_DIALOG( atcDialog );
 }
 //////////////////////////////////////////////////
@@ -143,6 +123,11 @@ static void FreqDisplayOK(puObject*) {
 
 
 FGATCDialog::FGATCDialog() {
+       _callbackPending = false;
+       _callbackTimer = 0.0;
+       _callbackWait = 0.0;
+       _callbackPtr = NULL;
+       _callbackCode = 0;
 }
 
 FGATCDialog::~FGATCDialog() {
@@ -247,6 +232,18 @@ void FGATCDialog::Init() {
        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
 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);
 }
 
+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() {
 
index d5295c8a3d68ba4056207ab39a54b09fe6453794..85a6721e6a300fd0473b6355d9cbce94e1fdc8ae 100644 (file)
@@ -60,16 +60,22 @@ public:
        
        void Init();
        
+       void Update(double dt);
+       
        void PopupDialog();
        
+       void PopupCallback();
+       
        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, 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 );
        
+       // query the database whether the transmission is already registered; 
        bool trans_reg( const string &station, int code, atc_type type );
        
        // Display a frequency search dialog for nearby stations
@@ -86,6 +92,11 @@ private:
        int  freq;
        bool reset;
        
+       bool _callbackPending;
+       double _callbackTimer;
+       double _callbackWait;
+       FGATC* _callbackPtr;
+       int _callbackCode;
 };
        
 extern FGATCDialog *current_atcdialog; 
index a747f74f37b8353709af98b324eb1fa4e6082416..d7fb6c9ff738fd9249d10cb0f1e1c7682007910d 100644 (file)
@@ -27,6 +27,7 @@
 #include "ATCdisplay.hxx"
 #include "ATCmgr.hxx"
 #include "ATCutils.hxx"
+#include "ATCDialog.hxx"
 #include "commlist.hxx"
 #include "AILocalTraffic.hxx"
 
@@ -35,86 +36,94 @@ SG_USING_STD(cout);
 // TowerPlaneRec
 
 TowerPlaneRec::TowerPlaneRec() :
-clearedToLand(false),
-clearedToLineUp(false),
-clearedToTakeOff(false),
-holdShortReported(false),
-downwindReported(false),
-longFinalReported(false),
-longFinalAcknowledged(false),
-finalReported(false),
-finalAcknowledged(false),
-instructedToGoAround(false),
-onRwy(false),
-nextOnRwy(false),
-opType(TTT_UNKNOWN),
-leg(LEG_UNKNOWN),
-landingType(AIP_LT_UNKNOWN),
-isUser(false)
+       clearedToLand(false),
+       clearedToLineUp(false),
+       clearedToTakeOff(false),
+       holdShortReported(false),
+       downwindReported(false),
+       longFinalReported(false),
+       longFinalAcknowledged(false),
+       finalReported(false),
+       finalAcknowledged(false),
+       instructedToGoAround(false),
+       onRwy(false),
+       nextOnRwy(false),
+       vfrArrivalReported(false),
+       vfrArrivalAcknowledged(false),
+       opType(TTT_UNKNOWN),
+       leg(LEG_UNKNOWN),
+       landingType(AIP_LT_UNKNOWN),
+       isUser(false) 
 {
        plane.callsign = "UNKNOWN";
 }
 
 TowerPlaneRec::TowerPlaneRec(PlaneRec p) :
-clearedToLand(false),
-clearedToLineUp(false),
-clearedToTakeOff(false),
-holdShortReported(false),
-downwindReported(false),
-longFinalReported(false),
-longFinalAcknowledged(false),
-finalReported(false),
-finalAcknowledged(false),
-instructedToGoAround(false),
-onRwy(false),
-nextOnRwy(false),
-opType(TTT_UNKNOWN),
-leg(LEG_UNKNOWN),
-landingType(AIP_LT_UNKNOWN),
-isUser(false)
+       clearedToLand(false),
+       clearedToLineUp(false),
+       clearedToTakeOff(false),
+       holdShortReported(false),
+       downwindReported(false),
+       longFinalReported(false),
+       longFinalAcknowledged(false),
+       finalReported(false),
+       finalAcknowledged(false),
+       instructedToGoAround(false),
+       onRwy(false),
+       nextOnRwy(false),
+       vfrArrivalReported(false),
+       vfrArrivalAcknowledged(false),
+       opType(TTT_UNKNOWN),
+       leg(LEG_UNKNOWN),
+       landingType(AIP_LT_UNKNOWN),
+       isUser(false)
 {
        plane = p;
 }
 
 TowerPlaneRec::TowerPlaneRec(Point3D pt) :
-clearedToLand(false),
-clearedToLineUp(false),
-clearedToTakeOff(false),
-holdShortReported(false),
-downwindReported(false),
-longFinalReported(false),
-longFinalAcknowledged(false),
-finalReported(false),
-finalAcknowledged(false),
-instructedToGoAround(false),
-onRwy(false),
-nextOnRwy(false),
-opType(TTT_UNKNOWN),
-leg(LEG_UNKNOWN),
-landingType(AIP_LT_UNKNOWN),
-isUser(false)
+       clearedToLand(false),
+       clearedToLineUp(false),
+       clearedToTakeOff(false),
+       holdShortReported(false),
+       downwindReported(false),
+       longFinalReported(false),
+       longFinalAcknowledged(false),
+       finalReported(false),
+       finalAcknowledged(false),
+       instructedToGoAround(false),
+       onRwy(false),
+       nextOnRwy(false),
+       vfrArrivalReported(false),
+       vfrArrivalAcknowledged(false),
+       opType(TTT_UNKNOWN),
+       leg(LEG_UNKNOWN),
+       landingType(AIP_LT_UNKNOWN),
+       isUser(false)
 {
        plane.callsign = "UNKNOWN";
        pos = pt;
 }
 
 TowerPlaneRec::TowerPlaneRec(PlaneRec p, Point3D pt) :
-clearedToLand(false),
-clearedToLineUp(false),
-clearedToTakeOff(false),
-holdShortReported(false),
-downwindReported(false),
-longFinalReported(false),
-longFinalAcknowledged(false),
-finalReported(false),
-finalAcknowledged(false),
-instructedToGoAround(false),
-onRwy(false),
-nextOnRwy(false),
-opType(TTT_UNKNOWN),
-leg(LEG_UNKNOWN),
-landingType(AIP_LT_UNKNOWN),
-isUser(false)
+       clearedToLand(false),
+       clearedToLineUp(false),
+       clearedToTakeOff(false),
+       holdShortReported(false),
+       downwindReported(false),
+       longFinalReported(false),
+       longFinalAcknowledged(false),
+       finalReported(false),
+       finalAcknowledged(false),
+       instructedToGoAround(false),
+       onRwy(false),
+       nextOnRwy(false),
+       vfrArrivalReported(false),
+       vfrArrivalAcknowledged(false),
+       opType(TTT_UNKNOWN),
+       leg(LEG_UNKNOWN),
+       landingType(AIP_LT_UNKNOWN),
+       isUser(false)
 {
        plane = p;
        pos = pt;
@@ -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.
 
-AI plane lands even when user on rwy - make it go-around instead.
-
 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.
@@ -242,8 +249,8 @@ void FGTower::Init() {
        if(rwyOccupied) {
                // Assume the user is started at the threshold ready to take-off
                TowerPlaneRec* t = new TowerPlaneRec;
-               t->plane.callsign = "Charlie Foxtrot Sierra";   // C-FGFS !!! - fixme - this is a bit hardwired
-               t->plane.type = GA_SINGLE;
+               t->plane.callsign = fgGetString("/sim/user/callsign");
+               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->landingType = AIP_LT_UNKNOWN;
                t->leg = TAKEOFF_ROLL;
@@ -252,6 +259,10 @@ void FGTower::Init() {
                t->clearedToTakeOff = true;
                rwyList.push_back(t);
                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';
        }
        */
+       //if(ident == "EGNX") cout << display << '\n';
        
        if(departed != false) {
                timeSinceLastDeparture += dt;
@@ -368,17 +380,36 @@ void FGTower::Update(double dt) {
 }
 
 void FGTower::ReceiveUserCallback(int code) {
-       if(code == (int)USER_REQUEST_DEPARTURE) {
+       if(code == (int)USER_REQUEST_VFR_DEPARTURE) {
                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() {
-       //cout << "Entering Respond..." << endl;
+       cout << "Entering Respond, responseID = " << responseID << endl;
        TowerPlaneRec* t = FindPlane(responseID);
        if(t) {
                // 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;
                        int i = 1;
                        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();
 }
 
-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";
        
-       // Assume this comes from the user - have another function taking a pointer to the AIplane for the AI traffic.
-       // 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;
-       t->isUser = true;
-       t->clearedToLand = false;
-       t->pos.setlon(user_lon_node->getDoubleValue());
-       t->pos.setlat(user_lat_node->getDoubleValue());
-       t->pos.setelev(user_elev_node->getDoubleValue());
+       // For now we'll assume that the user is a light plane and can get him/her to join the circuit if necessary.
+
+       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->pos.setlon(user_lon_node->getDoubleValue());
+                       t->pos.setlat(user_lat_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
-       // 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.
        
        // 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->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
        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) {
        switch(ttt) {
        case(CIRCUIT):      return(os << "CIRCUIT");
index ace19d982c2d0d6798d9b637bbb89240cbde3694..57341e913f38511210624e49f0334db933b377a1 100644 (file)
@@ -54,8 +54,10 @@ enum tower_traffic_type {
 ostream& operator << (ostream& os, tower_traffic_type ttt);
 
 enum tower_callback_type {
-       USER_REQUEST_DEPARTURE = 1,
-       USER_REQUEST_ARRIVAL = 2
+       USER_REQUEST_VFR_DEPARTURE = 1,
+       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.
@@ -90,6 +92,9 @@ public:
        bool instructedToGoAround;      // set true if told by tower to go around
        bool onRwy;             // is physically 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
        tower_traffic_type opType;
@@ -121,7 +126,11 @@ public:
        
        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 ReportFinal(string ID);
        void ReportLongFinal(string ID);
@@ -158,6 +167,8 @@ public:
        bool GetCrosswindConstraint(double& cpos);
        bool GetDownwindConstraint(double& dpos);
        bool GetBaseConstraint(double& bpos);
+       
+       string GenText(const string& m, int c);
 
 private:
        FGATCMgr* ATCmgr;