From 1dc3ecf016f633e145540e614443ea15a409589a Mon Sep 17 00:00:00 2001
From: Vivian Meazza <vivian.meazza@lineone.net>
Date: Fri, 10 Sep 2010 23:51:25 +0100
Subject: [PATCH] Make AI Objects of type Wingman, Escort, and GroundVehicle
 able to be stationed or formated to any AI Object type which can be named -
 Carrier, Ship, Tanker, Wingman etc.

Signed-off-by: Vivian Meazza <vivian.meazza@lineone.net>
---
 src/AIModel/AIBallistic.cxx     |  45 ++---
 src/AIModel/AIBallistic.hxx     |   3 +-
 src/AIModel/AIBase.cxx          |  10 +-
 src/AIModel/AIBase.hxx          |  16 ++
 src/AIModel/AIGroundVehicle.cxx | 117 ++++---------
 src/AIModel/AIManager.cxx       |   5 +-
 src/AIModel/AIManager.hxx       |   4 +
 src/AIModel/AIShip.cxx          |   7 +-
 src/AIModel/AIShip.hxx          | 294 ++++++++++++++++----------------
 src/AIModel/AITanker.cxx        | 173 ++++++++++---------
 10 files changed, 332 insertions(+), 342 deletions(-)

diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx
index 5446a5d35..261885b24 100644
--- a/src/AIModel/AIBallistic.cxx
+++ b/src/AIModel/AIBallistic.cxx
@@ -392,10 +392,6 @@ void FGAIBallistic::setImpactReportNode(const string& path) {
         _impact_report_node = fgGetNode(path.c_str(), true);
 }
 
-void FGAIBallistic::setName(const string& n) {
-    _name = n;
-}
-
 void FGAIBallistic::setSMPath(const string& s) {
     _path = s;
     //cout << "submodel path " << _path << endl;
@@ -458,6 +454,8 @@ void FGAIBallistic::setParentNodes(SGPropertyNode_ptr node) {
         _p_lat_node = _p_pos_node->getChild("latitude-deg", 0, true);
         _p_lon_node = _p_pos_node->getChild("longitude-deg", 0, true);
         _p_alt_node = _p_pos_node->getChild("altitude-ft", 0, true);
+        _p_agl_node = _p_pos_node->getChild("altitude-agl-ft", 0, true);
+
 
         _p_ori_node = _pnode->getChild("orientation", 0, true);
         _p_pch_node = _p_ori_node->getChild("pitch-deg", 0, true);
@@ -472,7 +470,7 @@ void FGAIBallistic::setParentNodes(SGPropertyNode_ptr node) {
 
 void FGAIBallistic::setParentPos() {
 
-    if (_pnode != 0) {
+    if (_pnode != 0) { 
         double lat = _p_lat_node->getDoubleValue();
         double lon = _p_lon_node->getDoubleValue();
         double alt = _p_alt_node->getDoubleValue();
@@ -480,6 +478,7 @@ void FGAIBallistic::setParentPos() {
         _parentpos.setLongitudeDeg(lon);
         _parentpos.setLatitudeDeg(lat);
         _parentpos.setElevationFt(alt);
+
     }
 
 }
@@ -623,19 +622,21 @@ void FGAIBallistic::setTgtZOffset(double z){
 
 void FGAIBallistic::slaveToAC(double dt){
 
-    double hdg, pch, rll = 0;
+    double hdg, pch, rll, agl = 0;
 
     if (_pnode != 0) {
         setParentPos();
         hdg = _p_hdg_node->getDoubleValue();
         pch = _p_pch_node->getDoubleValue();
         rll = _p_rll_node->getDoubleValue();
+        agl = _p_agl_node->getDoubleValue();
         setOffsetPos(_parentpos, hdg, pch, rll);
         setSpeed(_p_spd_node->getDoubleValue());
     }else {
         hdg = manager->get_user_heading();
         pch = manager->get_user_pitch();
         rll = manager->get_user_roll();
+        agl = manager->get_user_agl();
         setOffsetPos(userpos, hdg, pch, rll);
         setSpeed(manager->get_user_speed());
     }
@@ -1149,7 +1150,7 @@ void FGAIBallistic::setTgtOffsets(double dt, double coeff){
 
 void FGAIBallistic::formateToAC(double dt){
 
-    double hdg, pch, rll = 0;
+    double hdg, pch, rll, agl, ht = 0;
 
     setTgtOffsets(dt, 25);
 
@@ -1158,12 +1159,16 @@ void FGAIBallistic::formateToAC(double dt){
         hdg = _p_hdg_node->getDoubleValue();
         pch = _p_pch_node->getDoubleValue();
         rll = _p_rll_node->getDoubleValue();
+        agl = _p_agl_node->getDoubleValue();
+        ht  = _p_alt_node->getDoubleValue();
         setOffsetPos(_parentpos, hdg, pch, rll);
         setSpeed(_p_spd_node->getDoubleValue());
     }else {
         hdg = manager->get_user_heading();
         pch = manager->get_user_pitch();
         rll = manager->get_user_roll();
+        agl = manager->get_user_agl();
+        ht  = manager->get_user_altitude();
         setOffsetPos(userpos, hdg, pch, rll);
         setSpeed(manager->get_user_speed());
     }
@@ -1183,20 +1188,22 @@ void FGAIBallistic::formateToAC(double dt){
     pos.setLatitudeDeg(_offsetpos.getLatitudeDeg());
     pos.setLongitudeDeg(_offsetpos.getLongitudeDeg());
 
-    if (getHtAGL(10000)){
-
-        if(_ht_agl_ft <= 10) {
-            _height = userpos.getElevationFt();
-        } else if (_ht_agl_ft > 10 && _ht_agl_ft <= 150 ) {
-            setHt(userpos.getElevationFt(), dt, 1.0);
-        } else if (_ht_agl_ft > 150 && _ht_agl_ft <= 250) {
-            setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.75);
-        } else
-            setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.5);
-
-        pos.setElevationFt(_height);
+    if(agl <= 10) {
+        _height = ht;
+        //cout << "ht case1" << endl;
+    } else if (agl > 10 && agl <= 150 ) {
+        setHt(ht, dt, 1.0);
+        //cout << "ht case2" << endl;
+    } else if (agl > 150 && agl <= 250) {
+        setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.75);
+        //cout << "ht case3" << endl;
+    } else{
+        setHt(_offsetpos.getElevationFt()+ h_feet, dt, 0.5);
+        //cout << "ht case4" << endl;
     }
 
+    pos.setElevationFt(_height);
+
     // these calculations are unreliable at slow speeds
     if(speed >= 10) {
         setHdg(_azimuth + h_angle, dt, 0.9);
diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx
index a9566221f..843c3db6b 100644
--- a/src/AIModel/AIBallistic.hxx
+++ b/src/AIModel/AIBallistic.hxx
@@ -69,7 +69,7 @@ public:
     void setNoRoll( bool nr );
     void setRandom( bool r );
     void setRandomness( double r );
-    void setName(const string&);
+//    void setName(const string&);
     void setCollision(bool c);
     void setExpiry(bool e);
     void setImpact(bool i);
@@ -179,6 +179,7 @@ private:
     SGPropertyNode_ptr _p_lat_node;
     SGPropertyNode_ptr _p_lon_node;
     SGPropertyNode_ptr _p_alt_node;
+    SGPropertyNode_ptr _p_agl_node;
     SGPropertyNode_ptr _p_ori_node;
     SGPropertyNode_ptr _p_pch_node;
     SGPropertyNode_ptr _p_rll_node;
diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx
index 8681bc1b1..501bb32cb 100644
--- a/src/AIModel/AIBase.cxx
+++ b/src/AIModel/AIBase.cxx
@@ -69,7 +69,9 @@ FGAIBase::FGAIBase(object_type ot) :
     _refID( _newAIModelID() ),
     _otype(ot),
     _initialized(false),
-    _parent("")
+    _parent(""),
+    _name("")
+
 {
     tgt_heading = hdg = tgt_altitude_ft = tgt_speed = 0.0;
     tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0;
@@ -615,6 +617,12 @@ double FGAIBase::_getAltitude() const {
     return altitude_ft;
 }
 
+double FGAIBase::_getAltitudeAGL(SGGeod inpos, double start){
+    getGroundElevationM(SGGeod::fromGeodM(inpos, start),
+        _elevation_m, &_material);
+    return inpos.getElevationFt() - _elevation_m * SG_METER_TO_FEET;
+}
+
 bool FGAIBase::_getServiceable() const {
     return serviceable;
 }
diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx
index c1a533bed..fbaccd38f 100644
--- a/src/AIModel/AIBase.hxx
+++ b/src/AIModel/AIBase.hxx
@@ -66,6 +66,7 @@ public:
     void setCallSign(const string& );
     void setSpeed( double speed_KTAS );
     void setAltitude( double altitude_ft );
+    void setAltitudeAGL( double altitude_agl_ft );
     void setHeading( double heading );
     void setLatitude( double latitude );
     void setLongitude( double longitude );
@@ -86,6 +87,7 @@ public:
     void setImpactLon( double lon );
     void setImpactElev( double e );
     void setParentName(const string& p);
+    void setName(const string& n);
     bool setParentNode();
 
     int getID() const;
@@ -99,6 +101,9 @@ public:
     bool getGroundElevationM(const SGGeod& pos, double& elev,
         const SGMaterial** material) const;
 
+    double _elevation_m;
+    const SGMaterial* _material;
+
     double _getCartPosX() const;
     double _getCartPosY() const;
     double _getCartPosZ() const;
@@ -139,6 +144,7 @@ protected:
     double speed_north_deg_sec;
     double speed_east_deg_sec;
     double turn_radius_ft; // turn radius ft at 15 kts rudder angle 15 degrees
+    double altitude_agl_ft;
 
     double ft_per_deg_lon;
     double ft_per_deg_lat;
@@ -216,6 +222,8 @@ public:
     void _setSubID( int s );
     void _setUserPos();
 
+    double _getAltitudeAGL(SGGeod inpos, double start);
+
     double _getVS_fps() const;
     double _getAltitude() const;
     double _getLongitude() const;
@@ -317,6 +325,10 @@ inline void FGAIBase::setAltitude( double alt_ft ) {
     pos.setElevationFt(altitude_ft);
 }
 
+inline void FGAIBase::setAltitudeAGL( double alt_ft ) {
+    altitude_agl_ft = alt_ft;
+}
+
 inline void FGAIBase::setBank( double bank ) {
     roll = tgt_roll = bank;
     no_roll = false;
@@ -365,6 +377,10 @@ inline void FGAIBase::setParentName(const string& p) {
     _parent = p;
 }
 
+inline void FGAIBase::setName(const string& n) {
+    _name = n;
+}
+
 inline void FGAIBase::setDie( bool die ) { delete_me = die; }
 
 inline bool FGAIBase::getDie() { return delete_me; }
diff --git a/src/AIModel/AIGroundVehicle.cxx b/src/AIModel/AIGroundVehicle.cxx
index 1303b60e0..83e67626d 100644
--- a/src/AIModel/AIGroundVehicle.cxx
+++ b/src/AIModel/AIGroundVehicle.cxx
@@ -232,38 +232,38 @@ void FGAIGroundVehicle::setTowAngle(double ta, double dt, double coeff){
     SG_CLAMP_RANGE(_tow_angle, -limit, limit);
 }
 
-bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
-
-    double height_m ;
-
-    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 3000), height_m, &_material,0)){
-            _ht_agl_ft = inpos.getElevationFt() - height_m * SG_METER_TO_FEET;
-
-            if (_material) {
-                const vector<string>& names = _material->get_names();
-
-                _solid = _material->get_solid();
-
-                if (!names.empty())
-                    props->setStringValue("material/name", names[0].c_str());
-                else
-                    props->setStringValue("material/name", "");
-
-                //cout << "material " << names[0].c_str()
-                //    << " _elevation_m " << _elevation_m
-                //    << " solid " << _solid
-                //    << " load " << _load_resistance
-                //    << " frictionFactor " << _frictionFactor
-                //    << endl;
-
-            }
-
-            return true;
-    } else {
-        return false;
-    }
-
-}
+//bool FGAIGroundVehicle::getGroundElev(SGGeod inpos) {
+//
+//    double height_m ;
+//
+//    if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 3000), height_m, &_material,0)){
+//            _ht_agl_ft = inpos.getElevationFt() - height_m * SG_METER_TO_FEET;
+//
+//            if (_material) {
+//                const vector<string>& names = _material->get_names();
+//
+//                _solid = _material->get_solid();
+//
+//                if (!names.empty())
+//                    props->setStringValue("material/name", names[0].c_str());
+//                else
+//                    props->setStringValue("material/name", "");
+//
+//                //cout << "material " << names[0].c_str()
+//                //    << " _elevation_m " << _elevation_m
+//                //    << " solid " << _solid
+//                //    << " load " << _load_resistance
+//                //    << " frictionFactor " << _frictionFactor
+//                //    << endl;
+//
+//            }
+//
+//            return true;
+//    } else {
+//        return false;
+//    }
+//
+//}
 
 bool FGAIGroundVehicle::getPitch() {
 
@@ -351,62 +351,9 @@ bool FGAIGroundVehicle::getPitch() {
 
     }
 
-    //getGroundElev(pos);
-
     return true;
 }
 
-//void FGAIGroundVehicle::setParentNode() {
-//
-//    if(_parent == "")
-//        return;
-//
-//    const SGPropertyNode_ptr ai = fgGetNode("/ai/models", true);
-//
-//    for (int i = ai->nChildren() - 1; i >= -1; i--) {
-//        SGPropertyNode_ptr model;
-//
-//        if (i < 0) { // last iteration: selected model
-//            model = _selected_ac;
-//        } else {
-//            model = ai->getChild(i);
-//            string path = ai->getPath();
-//            const string name = model->getStringValue("name");
-//
-//            if (!model->nChildren()){
-//                continue;
-//            }
-//            if (name == _parent) {
-//                _selected_ac = model;  // save selected model for last iteration
-//                break;
-//            }
-//
-//        }
-//        if (!model)
-//            continue;
-//
-//    }// end for loop
-//
-//    if (_selected_ac != 0){
-//        const string name = _selected_ac->getStringValue("name");
-//        //_parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
-//        //_parent_y_offset = _selected_ac->getDoubleValue("hitch/y-offset-ft");
-//        //_parent_z_offset = _selected_ac->getDoubleValue("hitch/z-offset-ft");
-//        //_hitch_x_offset_m = _selected_ac->getDoubleValue("hitch/x-offset-ft")
-//        //    * SG_FEET_TO_METER;
-//        //_hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
-//        //    * SG_FEET_TO_METER;
-//        //_hitch_z_offset_m = _selected_ac->getDoubleValue("hitch/z-offset-ft")
-//        //    * SG_FEET_TO_METER;
-//        //setParent();
-//    } else {
-//        SG_LOG(SG_GENERAL, SG_ALERT, "AIGroundVeh1cle: " << _name
-//                << " parent not found: dying ");
-//        setDie(true);
-//    }
-//
-//}
-
 void FGAIGroundVehicle::setParent(){
 
     double lat = _selected_ac->getDoubleValue("position/latitude-deg");
diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx
index 4255709ab..e54a5bcee 100644
--- a/src/AIModel/AIManager.cxx
+++ b/src/AIModel/AIManager.cxx
@@ -76,6 +76,7 @@ FGAIManager::init() {
     user_latitude_node  = fgGetNode("/position/latitude-deg", true);
     user_longitude_node = fgGetNode("/position/longitude-deg", true);
     user_altitude_node  = fgGetNode("/position/altitude-ft", true);
+    user_altitude_agl_node  = fgGetNode("/position/altitude-agl-ft", true);
     user_heading_node   = fgGetNode("/orientation/heading-deg", true);
     user_pitch_node     = fgGetNode("/orientation/pitch-deg", true);
     user_yaw_node       = fgGetNode("/orientation/side-slip-deg", true);
@@ -248,7 +249,9 @@ FGAIManager::fetchUserState( void ) {
     user_speed     = user_speed_node->getDoubleValue() * 0.592484;
     user_roll      = user_roll_node->getDoubleValue();
     wind_from_east = wind_from_east_node->getDoubleValue();
-    wind_from_north = wind_from_north_node->getDoubleValue();
+    wind_from_north   = wind_from_north_node->getDoubleValue();
+    user_altitude_agl = user_altitude_agl_node->getDoubleValue();
+
 }
 
 // only keep the results from the nearest thermal
diff --git a/src/AIModel/AIManager.hxx b/src/AIModel/AIManager.hxx
index 8f582801a..891d3a506 100644
--- a/src/AIModel/AIManager.hxx
+++ b/src/AIModel/AIManager.hxx
@@ -81,6 +81,7 @@ public:
     inline double get_wind_from_east() const {return wind_from_east; }
     inline double get_wind_from_north() const {return wind_from_north; }
     inline double get_user_roll() const { return user_roll; }
+    inline double get_user_agl() const { return user_agl; }
 
     int getNumAiObjects(void) const;
 
@@ -104,6 +105,7 @@ private:
     SGPropertyNode_ptr user_latitude_node;
     SGPropertyNode_ptr user_longitude_node;
     SGPropertyNode_ptr user_altitude_node;
+    SGPropertyNode_ptr user_altitude_agl_node;
     SGPropertyNode_ptr user_heading_node;
     SGPropertyNode_ptr user_pitch_node;
     SGPropertyNode_ptr user_yaw_node;
@@ -115,11 +117,13 @@ private:
     double user_latitude;
     double user_longitude;
     double user_altitude;
+    double user_altitude_agl;
     double user_heading;
     double user_pitch;
     double user_yaw;
     double user_roll;
     double user_speed;
+    double user_agl;
     double wind_from_east;
     double wind_from_north;
     double _dt;
diff --git a/src/AIModel/AIShip.cxx b/src/AIModel/AIShip.cxx
index a00f9c941..d0a3f3b65 100644
--- a/src/AIModel/AIShip.cxx
+++ b/src/AIModel/AIShip.cxx
@@ -70,8 +70,7 @@ _range_rate(0),
 _roll_constant(0.001),
 _hdg_constant(0.01),
 _roll_factor(-0.0083335),
-_restart(false),
-_name("")
+_restart(false)
 
 {
         invisible = false;
@@ -491,10 +490,6 @@ void FGAIShip::setFlightPlan(FGAIFlightPlan* f) {
     fp = f;
 }
 
-void FGAIShip::setName(const string& n) {
-    _name = n;
-}
-
 void FGAIShip::setStartTime(const string& st) {
     _start_time = st;
 }
diff --git a/src/AIModel/AIShip.hxx b/src/AIModel/AIShip.hxx
index c240dabf3..c15b45731 100644
--- a/src/AIModel/AIShip.hxx
+++ b/src/AIModel/AIShip.hxx
@@ -1,147 +1,147 @@
-// FGAIShip - AIBase derived class creates an AI ship
-//
-// Written by David Culp, started November 2003.
-// with major amendments and additions by Vivian Meazza, 2004 - 2007 
-//
-// Copyright (C) 2003  David P. Culp - davidculp2@comcast.net
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifndef _FG_AISHIP_HXX
-#define _FG_AISHIP_HXX
-
-#include "AIBase.hxx"
-#include "AIFlightPlan.hxx"
-#include <simgear/scene/material/mat.hxx>
-
-class FGAIManager;
-
-class FGAIShip : public FGAIBase {
-
-public:
-
-    FGAIShip(object_type ot = otShip);
-    virtual ~FGAIShip();
-
-    virtual void readFromScenario(SGPropertyNode* scFileNode);
-
-    virtual bool init(bool search_in_AI_path=false);
-    virtual void bind();
-    virtual void unbind();
-    virtual void update(double dt);
-    void setFlightPlan(FGAIFlightPlan* f);
-    void setName(const string&);
-    void setRudder(float r);
-    void setRoll(double rl);
-    void ProcessFlightPlan( double dt);
-    void AccelTo(double speed);
-    void PitchTo(double angle);
-    void RollTo(double angle);
-    void YawTo(double angle);
-    void ClimbTo(double altitude);
-    void TurnTo(double heading);
-    void setCurrName(const string&);
-    void setNextName(const string&);
-    void setPrevName(const string&);
-    void setLeadAngleGain(double g);
-    void setLeadAngleLimit(double l);
-    void setLeadAngleProp(double p);
-    void setRudderConstant(double rc);
-    void setSpeedConstant(double sc);
-    void setFixedTurnRadius(double ft);
-    void setTunnel(bool t);
-    void setInitialTunnel(bool t);
-
-    void setWPNames();
-    void setWPPos();
-    double sign(double x);
-
-    bool _hdg_lock;
-    bool _serviceable;
-    bool _waiting;
-    bool _new_waypoint;
-    bool _tunnel, _initial_tunnel;
-    bool _restart;
-
-    virtual const char* getTypeString(void) const { return "ship"; }
-    double _rudder_constant, _speed_constant, _hdg_constant, _limit ;
-    double _elevation_m, _elevation_ft;
-    double _missed_range, _tow_angle, _wait_count, _missed_count,_wp_range;
-    double _dt_count, _next_run;
-
-    FGAIFlightPlan::waypoint* prev; // the one behind you
-    FGAIFlightPlan::waypoint* curr; // the one ahead
-    FGAIFlightPlan::waypoint* next; // the next plus 1
-
-protected:
-
-    string _name; // The name of this ship.
-
-private:
-
-
-
-    virtual void reinit() { init(); }
-
-    void setRepeat(bool r);
-    void setRestart(bool r);
-    void setMissed(bool m);
-
-    void setServiceable(bool s);
-    void Run(double dt);
-    void setStartTime(const string&);
-    void setUntilTime(const string&);
-    //void setWPPos();
-    void setWPAlt();
-    void setXTrackError();
-
-    SGGeod wppos;
-
-    const SGMaterial* _material;
-
-    double getRange(double lat, double lon, double lat2, double lon2) const;
-    double getCourse(double lat, double lon, double lat2, double lon2) const;
-    double getDaySeconds();
-    double processTimeString(const string& time);
-
-    bool initFlightPlan();
-    bool advanceFlightPlan (double elapsed_sec, double day_sec);
-
-    float _rudder, _tgt_rudder;
-
-    double _roll_constant, _roll_factor;
-    double _sp_turn_radius_ft, _rd_turn_radius_ft, _fixed_turn_radius;
-    double _old_range, _range_rate;
-    double _missed_time_sec;
-    double _start_sec;
-    double _day;
-    double _lead_angle;
-    double _lead_angle_gain, _lead_angle_limit, _proportion;
-    double _course;
-    double _xtrack_error;
-    double _curr_alt, _prev_alt;
-
-    string _prev_name, _curr_name, _next_name;
-    string _path;
-    string _start_time, _until_time;
-
-    bool _repeat;
-    bool _fp_init;
-    bool _missed;
-   
-
-};
-
-#endif  // _FG_AISHIP_HXX
+// FGAIShip - AIBase derived class creates an AI ship
+//
+// Written by David Culp, started November 2003.
+// with major amendments and additions by Vivian Meazza, 2004 - 2007 
+//
+// Copyright (C) 2003  David P. Culp - davidculp2@comcast.net
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifndef _FG_AISHIP_HXX
+#define _FG_AISHIP_HXX
+
+#include "AIBase.hxx"
+#include "AIFlightPlan.hxx"
+#include <simgear/scene/material/mat.hxx>
+
+class FGAIManager;
+
+class FGAIShip : public FGAIBase {
+
+public:
+
+    FGAIShip(object_type ot = otShip);
+    virtual ~FGAIShip();
+
+    virtual void readFromScenario(SGPropertyNode* scFileNode);
+
+    virtual bool init(bool search_in_AI_path=false);
+    virtual void bind();
+    virtual void unbind();
+    virtual void update(double dt);
+    void setFlightPlan(FGAIFlightPlan* f);
+//    void setName(const string&);
+    void setRudder(float r);
+    void setRoll(double rl);
+    void ProcessFlightPlan( double dt);
+    void AccelTo(double speed);
+    void PitchTo(double angle);
+    void RollTo(double angle);
+    void YawTo(double angle);
+    void ClimbTo(double altitude);
+    void TurnTo(double heading);
+    void setCurrName(const string&);
+    void setNextName(const string&);
+    void setPrevName(const string&);
+    void setLeadAngleGain(double g);
+    void setLeadAngleLimit(double l);
+    void setLeadAngleProp(double p);
+    void setRudderConstant(double rc);
+    void setSpeedConstant(double sc);
+    void setFixedTurnRadius(double ft);
+    void setTunnel(bool t);
+    void setInitialTunnel(bool t);
+
+    void setWPNames();
+    void setWPPos();
+    double sign(double x);
+
+    bool _hdg_lock;
+    bool _serviceable;
+    bool _waiting;
+    bool _new_waypoint;
+    bool _tunnel, _initial_tunnel;
+    bool _restart;
+
+    virtual const char* getTypeString(void) const { return "ship"; }
+    double _rudder_constant, _speed_constant, _hdg_constant, _limit ;
+    double _elevation_m, _elevation_ft;
+    double _missed_range, _tow_angle, _wait_count, _missed_count,_wp_range;
+    double _dt_count, _next_run;
+
+    FGAIFlightPlan::waypoint* prev; // the one behind you
+    FGAIFlightPlan::waypoint* curr; // the one ahead
+    FGAIFlightPlan::waypoint* next; // the next plus 1
+
+protected:
+
+//    string _name; // The name of this ship.
+
+private:
+
+
+
+    virtual void reinit() { init(); }
+
+    void setRepeat(bool r);
+    void setRestart(bool r);
+    void setMissed(bool m);
+
+    void setServiceable(bool s);
+    void Run(double dt);
+    void setStartTime(const string&);
+    void setUntilTime(const string&);
+    //void setWPPos();
+    void setWPAlt();
+    void setXTrackError();
+
+    SGGeod wppos;
+
+    const SGMaterial* _material;
+
+    double getRange(double lat, double lon, double lat2, double lon2) const;
+    double getCourse(double lat, double lon, double lat2, double lon2) const;
+    double getDaySeconds();
+    double processTimeString(const string& time);
+
+    bool initFlightPlan();
+    bool advanceFlightPlan (double elapsed_sec, double day_sec);
+
+    float _rudder, _tgt_rudder;
+
+    double _roll_constant, _roll_factor;
+    double _sp_turn_radius_ft, _rd_turn_radius_ft, _fixed_turn_radius;
+    double _old_range, _range_rate;
+    double _missed_time_sec;
+    double _start_sec;
+    double _day;
+    double _lead_angle;
+    double _lead_angle_gain, _lead_angle_limit, _proportion;
+    double _course;
+    double _xtrack_error;
+    double _curr_alt, _prev_alt;
+
+    string _prev_name, _curr_name, _next_name;
+    string _path;
+    string _start_time, _until_time;
+
+    bool _repeat;
+    bool _fp_init;
+    bool _missed;
+   
+
+};
+
+#endif  // _FG_AISHIP_HXX
diff --git a/src/AIModel/AITanker.cxx b/src/AIModel/AITanker.cxx
index b123c4512..de9adbb26 100644
--- a/src/AIModel/AITanker.cxx
+++ b/src/AIModel/AITanker.cxx
@@ -1,82 +1,91 @@
-// AITanker.cxx  Based on David Culp's AIModel code
-// - Tanker specific code isolated from AI Aircraft code
-// by Thomas Foerster, started June 2007
-//
-// 
-// Original code written by David Culp, started October 2003.
-// - davidculp2@comcast.net/
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "AITanker.hxx"
-
-FGAITanker::FGAITanker(FGAISchedule* ref): FGAIAircraft(ref){
-}
-
-FGAITanker::~FGAITanker() {}
-
-void FGAITanker::readFromScenario(SGPropertyNode* scFileNode) {
-    if (!scFileNode)
-        return;
-
-    FGAIAircraft::readFromScenario(scFileNode);
-    setTACANChannelID(scFileNode->getStringValue("TACAN-channel-ID"));
-}
-
-void FGAITanker::bind() {
-    FGAIAircraft::bind();
-
-    props->tie("refuel/contact", SGRawValuePointer<bool>(&contact));
-    props->setStringValue("navaids/tacan/channel-ID", TACAN_channel_id.c_str());
-    props->setBoolValue("tanker", true);
-}
-
-void FGAITanker::unbind() {
-    FGAIAircraft::unbind();
-    props->untie("refuel/contact");
-}
-
-void FGAITanker::setTACANChannelID(const string& id) {
-    TACAN_channel_id = id;
-}
-
-void FGAITanker::Run(double dt) {
-    //FGAIAircraft::Run(dt);
-
-    //###########################//
-    // do calculations for radar //
-    //###########################//
-    double range_ft2 = UpdateRadar(manager);
-
-    // check if radar contact
-    if ( (range_ft2 < 250.0 * 250.0) && (y_shift > 0.0)
-              && (elevation > 0.0) ) {
-        //refuel_node->setBoolValue(true);
-        contact = true;
-    } else {
-        //refuel_node->setBoolValue(false);
-        contact = false;
-    }
-}
-
-
-void FGAITanker::update(double dt) {
-     FGAIAircraft::update(dt);
-     Run(dt);
-     Transform();
-}
+// AITanker.cxx  Based on David Culp's AIModel code
+// - Tanker specific code isolated from AI Aircraft code
+// by Thomas Foerster, started June 2007
+//
+// 
+// Original code written by David Culp, started October 2003.
+// - davidculp2@comcast.net/
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "AITanker.hxx"
+
+FGAITanker::FGAITanker(FGAISchedule* ref): FGAIAircraft(ref){
+}
+
+FGAITanker::~FGAITanker() {}
+
+void FGAITanker::readFromScenario(SGPropertyNode* scFileNode) {
+    if (!scFileNode)
+        return;
+
+    FGAIAircraft::readFromScenario(scFileNode);
+    setTACANChannelID(scFileNode->getStringValue("TACAN-channel-ID",""));
+    setName(scFileNode->getStringValue("name", "Tanker"));
+
+}
+
+void FGAITanker::bind() {
+    FGAIAircraft::bind();
+
+    props->tie("refuel/contact", SGRawValuePointer<bool>(&contact));
+    props->tie("position/altitude-agl-ft",SGRawValuePointer<double>(&altitude_agl_ft));
+    props->setStringValue("navaids/tacan/channel-ID", TACAN_channel_id.c_str());
+    props->setStringValue("name", _name.c_str());
+    props->setBoolValue("tanker", true);
+}
+
+void FGAITanker::unbind() {
+    FGAIAircraft::unbind();
+    props->untie("refuel/contact");
+    props->untie("position/altitude-agl-ft");
+
+}
+
+void FGAITanker::setTACANChannelID(const string& id) {
+    TACAN_channel_id = id;
+}
+
+void FGAITanker::Run(double dt) {
+    //FGAIAircraft::Run(dt);
+
+    double start = pos.getElevationFt() + 1000;
+    altitude_agl_ft = _getAltitudeAGL(pos, start);
+
+    //###########################//
+    // do calculations for radar //
+    //###########################//
+    double range_ft2 = UpdateRadar(manager);
+
+    // check if radar contact
+    if ( (range_ft2 < 250.0 * 250.0) && (y_shift > 0.0)
+              && (elevation > 0.0) ) {
+        //refuel_node->setBoolValue(true);
+        contact = true;
+    } else {
+        //refuel_node->setBoolValue(false);
+        contact = false;
+    }
+}
+
+
+void FGAITanker::update(double dt) {
+     FGAIAircraft::update(dt);
+     Run(dt);
+     Transform();
+}