From bc12f0be21d703653620743b6bf86db7c78a69cd Mon Sep 17 00:00:00 2001
From: Vivian Meazza <vivian.meazza@lineone.net>
Date: Thu, 2 Sep 2010 09:24:45 +0100
Subject: [PATCH 1/8] Walk the AImodels property tree only once at init, rather
 than at update. Should have a beneficial effect on frame rate, but in
 practice makes no discernible improvement. It is cleaner code though.

Signed-off-by: Vivian Meazza <vivian.meazza@lineone.net>
---
 src/AIModel/AIBallistic.cxx     |   4 +
 src/AIModel/AIBallistic.hxx     |   1 +
 src/AIModel/AIEscort.cxx        | 926 +++++++++++++++++---------------
 src/AIModel/AIEscort.hxx        | 213 ++++----
 src/AIModel/AIGroundVehicle.cxx |  83 +--
 src/AIModel/AIGroundVehicle.hxx | 212 ++++----
 src/AIModel/AIShip.cxx          |  15 +-
 src/AIModel/AIWingman.cxx       |   7 +
 8 files changed, 763 insertions(+), 698 deletions(-)

diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx
index 0306c3ec5..2f5bb4f6f 100644
--- a/src/AIModel/AIBallistic.cxx
+++ b/src/AIModel/AIBallistic.cxx
@@ -479,6 +479,10 @@ bool FGAIBallistic::getSlaved() const {
     return _slave_to_ac;
 }
 
+bool FGAIBallistic::getFormate() const {
+    return _formate_to_ac;
+}
+
 double FGAIBallistic::getMass() const {
     return _mass;
 }
diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx
index c9613de89..91a50acbd 100644
--- a/src/AIModel/AIBallistic.hxx
+++ b/src/AIModel/AIBallistic.hxx
@@ -105,6 +105,7 @@ public:
 
     bool getHtAGL(double start);
     bool getSlaved() const;
+    bool getFormate() const;
     bool getSlavedLoad() const;
 
     virtual const char* getTypeString(void) const { return "ballistic"; }
diff --git a/src/AIModel/AIEscort.cxx b/src/AIModel/AIEscort.cxx
index c9901ca24..5ef848535 100644
--- a/src/AIModel/AIEscort.cxx
+++ b/src/AIModel/AIEscort.cxx
@@ -1,443 +1,483 @@
-// FGAIEscort - FGAIShip-derived class creates an AI Ground Vehicle
-// by adding a ground following utility
-//
-// Written by Vivian Meazza, started August 2009.
-// - vivian.meazza at lineone.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 <algorithm>
-#include <string>
-#include <vector>
-
-#include <simgear/sg_inlines.h>
-#include <simgear/math/SGMath.hxx>
-#include <simgear/math/sg_geodesy.hxx>
-
-#include <math.h>
-#include <Main/util.hxx>
-#include <Main/viewer.hxx>
-
-#include <Scenery/scenery.hxx>
-#include <Scenery/tilemgr.hxx>
-
-#include "AIEscort.hxx"
-
-using std::string;
-
-FGAIEscort::FGAIEscort() :
-FGAIShip(otEscort),
-
-_selected_ac(0),
-_relbrg (0),
-_stn_truebrg(0),
-_parent_speed(0),
-_stn_limit(0),
-_stn_angle_limit(0),
-_stn_speed(0),
-_stn_height(0),
-_max_speed(0),
-_interval(0),
-_MPControl(false),
-_patrol(false),
-_stn_deg_true(false),
-_parent("")
-
-{
-    invisible = false;
-}
-
-FGAIEscort::~FGAIEscort() {}
-
-void FGAIEscort::readFromScenario(SGPropertyNode* scFileNode) {
-    if (!scFileNode)
-        return;
-
-    FGAIShip::readFromScenario(scFileNode);
-
-    setName(scFileNode->getStringValue("name", "Escort"));
-    setSMPath(scFileNode->getStringValue("submodel-path", ""));
-    setStnRange(scFileNode->getDoubleValue("station/range-nm", 1));
-    setStnBrg(scFileNode->getDoubleValue("station/brg-deg", 0.0));
-    setStnLimit(scFileNode->getDoubleValue("station/range-limit-nm", 0.2));
-    setStnAngleLimit(scFileNode->getDoubleValue("station/angle-limit-deg", 15.0));
-    setStnSpeed(scFileNode->getDoubleValue("station/speed-kts", 2.5));
-    setStnPatrol(scFileNode->getBoolValue("station/patrol", false));
-    setStnHtFt(scFileNode->getDoubleValue("station/height-ft", 0.0));
-    setStnDegTrue(scFileNode->getBoolValue("station/deg-true", false));
-    setParentName(scFileNode->getStringValue("station/parent", ""));
-    setMaxSpeed(scFileNode->getDoubleValue("max-speed-kts", 30.0));
-    setUpdateInterval(scFileNode->getDoubleValue("update-interval-sec", 10.0));
-    setCallSign(scFileNode->getStringValue("callsign", ""));
-
-    if(_patrol)
-        sg_srandom_time();
-
-}
-
-void FGAIEscort::bind() {
-    FGAIShip::bind();
-
-    props->tie("station/rel-bearing-deg",
-        SGRawValuePointer<double>(&_stn_relbrg));
-    props->tie("station/true-bearing-deg",
-        SGRawValuePointer<double>(&_stn_truebrg));
-    props->tie("station/range-nm",
-        SGRawValuePointer<double>(&_stn_range));
-    props->tie("station/range-limit-nm",
-        SGRawValuePointer<double>(&_stn_limit));
-    props->tie("station/angle-limit-deg",
-        SGRawValuePointer<double>(&_stn_angle_limit));
-    props->tie("station/speed-kts",
-        SGRawValuePointer<double>(&_stn_speed));
-    props->tie("station/height-ft",
-        SGRawValuePointer<double>(&_stn_height));
-    props->tie("controls/update-interval-sec",
-        SGRawValuePointer<double>(&_interval));
-    props->tie("controls/parent-mp-control",
-        SGRawValuePointer<bool>(&_MPControl));
-    props->tie("station/target-range-nm",
-        SGRawValuePointer<double>(&_tgtrange));
-    props->tie("station/target-brg-deg-t",
-        SGRawValuePointer<double>(&_tgtbrg));
-    props->tie("station/patrol",
-        SGRawValuePointer<bool>(&_patrol));
-}
-
-void FGAIEscort::unbind() {
-    FGAIShip::unbind();
-
-    props->untie("station/rel-bearing-deg");
-    props->untie("station/true-bearing-deg");
-    props->untie("station/range-nm");
-    props->untie("station/range-limit-nm");
-    props->untie("station/angle-limit-deg");
-    props->untie("station/speed-kts");
-    props->untie("station/height-ft");
-    props->untie("controls/update-interval-sec");
-
-}
-
-bool FGAIEscort::init(bool search_in_AI_path) {
-    if (!FGAIShip::init(search_in_AI_path))
-        return false;
-
-    invisible = false;
-    no_roll = false;
-
-    props->setStringValue("controls/parent-name", _parent.c_str());
-    setParent();
-    pos = _tgtpos;
-    speed = _parent_speed;
-    hdg = _parent_hdg;
-
-    return true;
-}
-
-void FGAIEscort::update(double dt) {
-    FGAIShip::update(dt);
-
-    RunEscort(dt);
-}
-
-void FGAIEscort::setStnRange(double r) {
-    _stn_range = r;
-}
-
-void FGAIEscort::setStnBrg(double b) {
-    _stn_brg = b;
-}
-
-void FGAIEscort::setStnLimit(double l) {
-    _stn_limit = l;
-}
-
-void FGAIEscort::setStnAngleLimit(double al) {
-    _stn_angle_limit = al;
-}
-
-void FGAIEscort::setStnSpeed(double s) {
-    _stn_speed = s;
-}
-
-void FGAIEscort::setStnHtFt(double h) {
-    _stn_height = h;
-}
-
-void FGAIEscort::setStnDegTrue(bool t) {
-    _stn_deg_true = t;
-}
-
-void FGAIEscort::setMaxSpeed(double m) {
-    _max_speed = m;
-}
-
-void FGAIEscort::setUpdateInterval(double i) {
-    _interval = i;
-}
-
-void FGAIEscort::setStnPatrol(bool p) {
-    _patrol = p;
-}
-
-void FGAIEscort::setParentName(const string& p) {
-    _parent = p;
-}
-
-bool FGAIEscort::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;
-    }
-
-}
-
-void FGAIEscort::setParent() {
-
-    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");
-        double lat = _selected_ac->getDoubleValue("position/latitude-deg");
-        double lon = _selected_ac->getDoubleValue("position/longitude-deg");
-        double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
-        _MPControl = _selected_ac->getBoolValue("controls/mp-control");
-
-        _selectedpos.setLatitudeDeg(lat);
-        _selectedpos.setLongitudeDeg(lon);
-        _selectedpos.setElevationFt(elevation);
-
-        _parent_speed    = _selected_ac->getDoubleValue("velocities/speed-kts");
-        _parent_hdg      = _selected_ac->getDoubleValue("orientation/true-heading-deg");
-
-        if(!_stn_deg_true){
-            _stn_truebrg = calcTrueBearingDeg(_stn_brg, _parent_hdg);
-            _stn_relbrg = _stn_brg;
-            //cout << _name <<" set rel"<<endl;
-        } else {
-            _stn_truebrg = _stn_brg;
-            _stn_relbrg = calcRelBearingDeg(_stn_brg, _parent_hdg); 
-            //cout << _name << " set true"<<endl;
-        }
-
-        double course2;
-
-        SGGeodesy::direct( _selectedpos, _stn_truebrg, _stn_range * SG_NM_TO_METER,
-            _tgtpos, course2);
-
-        _tgtpos.setElevationFt(_stn_height);
-
-        calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
-            _tgtpos.getLatitudeDeg(), _tgtpos.getLongitudeDeg(), _tgtrange, _tgtbrg);
-
-        _relbrg = calcRelBearingDeg(_tgtbrg, hdg);
-
-    } else {
-        SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
-            << " parent not found: dying ");
-        setDie(true);
-    }
-
-}
-
-void FGAIEscort::calcRangeBearing(double lat, double lon, double lat2, double lon2,
-                                  double &range, double &bearing) const
-{
-    // calculate the bearing and range of the second pos from the first
-    double az2, distance;
-    geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
-    range = distance * SG_METER_TO_NM;
-}
-
-double FGAIEscort::calcRelBearingDeg(double bearing, double heading)
-{
-    double angle = bearing - heading;
-    SG_NORMALIZE_RANGE(angle, -180.0, 180.0);
-    return angle;
-}
-
-double FGAIEscort::calcTrueBearingDeg(double bearing, double heading)
-{
-    double angle = bearing + heading;
-    SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
-    return angle;
-}
-
-double FGAIEscort::calcRecipBearingDeg(double bearing)
-{
-    double angle = bearing - 180;
-    SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
-    return angle;
-}
-
-SGVec3d FGAIEscort::getCartHitchPosAt(const SGVec3d& _off) const {
-    double hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
-    double pitch = _selected_ac->getDoubleValue("orientation/pitch-deg");
-    double roll = _selected_ac->getDoubleValue("orientation/roll-deg");
-
-    // Transform that one to the horizontal local coordinate system.
-    SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
-
-    // and postrotate the orientation of the AIModel wrt the horizontal
-    // local frame
-    hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
-
-    // The offset converted to the usual body fixed coordinate system
-    // rotated to the earth fiexed coordinates axis
-    SGVec3d off = hlTrans.backTransform(_off);
-
-    // Add the position offset of the AIModel to gain the earth centered position
-    SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
-
-    return cartPos + off;
-}
-
-
-void FGAIEscort::setStationSpeed(){
-
-    double speed = 0;
-    double angle = 0;
-
-    // these are the AI rules for the manoeuvring of escorts
-
-    if (_MPControl && _tgtrange > 4 * _stn_limit){
-        SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
-            << " re-aligning to MP pos");
-        pos = _tgtpos;
-        speed = 0;
-        angle = 0;
-    }else if ((_relbrg < -90 || _relbrg > 90) && _tgtrange > _stn_limit ){
-        angle =_relbrg;
-
-        if(_tgtrange > 4 * _stn_limit)
-            speed = 4 * -_stn_speed;
-        else
-            speed = -_stn_speed;
-
-    }else if ((_relbrg >= -90 || _relbrg <= 90) && _tgtrange > _stn_limit){
-        angle = _relbrg;
-
-        if(_tgtrange > 4 * _stn_limit)
-            speed = 4 * _stn_speed;
-        else
-            speed = _stn_speed;
-
-    } else {
-
-        if(_patrol){
-            angle = 15 * sg_random();
-            speed =  5 * sg_random();
-        } else {
-            angle = 0;
-            speed = 0;
-        }
-
-    }
-
-    double station_speed = _parent_speed + speed;
-
-    SG_CLAMP_RANGE(station_speed, 5.0, _max_speed);
-    SG_CLAMP_RANGE(angle, -_stn_angle_limit, _stn_angle_limit);
-
-    AccelTo(station_speed);
-    TurnTo(_parent_hdg + angle);
-    ClimbTo(_stn_height);
-
-}
-
-void FGAIEscort::RunEscort(double dt){
-
-    _dt_count += dt;
-
-
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Check execution time (currently once every 0.05 sec or 20 fps)
-    // Add a bit of randomization to prevent the execution of all flight plans
-    // in synchrony, which can add significant periodic framerate flutter.
-    // Randomization removed to get better appearance
-    ///////////////////////////////////////////////////////////////////////////
-
-    //cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
-    if (_dt_count < _next_run)
-        return;
-    _next_run = _interval /*+ (0.015 * sg_random())*/;
-
-    if(_parent == ""){
-        return;
-    }
-
-    setParent();
-    setStationSpeed();
-    //getGroundElev(pos);
-
-    _dt_count = 0;
-
-}
-
-// end AIGroundvehicle
+// FGAIEscort - FGAIShip-derived class creates an AI Ground Vehicle
+// by adding a ground following utility
+//
+// Written by Vivian Meazza, started August 2009.
+// - vivian.meazza at lineone.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 <algorithm>
+#include <string>
+#include <vector>
+
+#include <simgear/sg_inlines.h>
+#include <simgear/math/SGMath.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+
+#include <math.h>
+#include <Main/util.hxx>
+#include <Main/viewer.hxx>
+
+#include <Scenery/scenery.hxx>
+#include <Scenery/tilemgr.hxx>
+
+#include "AIEscort.hxx"
+
+using std::string;
+
+FGAIEscort::FGAIEscort() :
+FGAIShip(otEscort),
+
+_selected_ac(0),
+_relbrg (0),
+_stn_truebrg(0),
+_parent_speed(0),
+_stn_limit(0),
+_stn_angle_limit(0),
+_stn_speed(0),
+_stn_height(0),
+_max_speed(0),
+_interval(0),
+_MPControl(false),
+_patrol(false),
+_stn_deg_true(false),
+_parent("")
+
+{
+    invisible = false;
+}
+
+FGAIEscort::~FGAIEscort() {}
+
+void FGAIEscort::readFromScenario(SGPropertyNode* scFileNode) {
+    if (!scFileNode)
+        return;
+
+    FGAIShip::readFromScenario(scFileNode);
+
+    setName(scFileNode->getStringValue("name", "Escort"));
+    setSMPath(scFileNode->getStringValue("submodel-path", ""));
+    setStnRange(scFileNode->getDoubleValue("station/range-nm", 1));
+    setStnBrg(scFileNode->getDoubleValue("station/brg-deg", 0.0));
+    setStnLimit(scFileNode->getDoubleValue("station/range-limit-nm", 0.2));
+    setStnAngleLimit(scFileNode->getDoubleValue("station/angle-limit-deg", 15.0));
+    setStnSpeed(scFileNode->getDoubleValue("station/speed-kts", 2.5));
+    setStnPatrol(scFileNode->getBoolValue("station/patrol", false));
+    setStnHtFt(scFileNode->getDoubleValue("station/height-ft", 0.0));
+    setStnDegTrue(scFileNode->getBoolValue("station/deg-true", false));
+    setParentName(scFileNode->getStringValue("station/parent", ""));
+    setMaxSpeed(scFileNode->getDoubleValue("max-speed-kts", 30.0));
+    setUpdateInterval(scFileNode->getDoubleValue("update-interval-sec", 10.0));
+    setCallSign(scFileNode->getStringValue("callsign", ""));
+
+    if(_patrol)
+        sg_srandom_time();
+
+}
+
+void FGAIEscort::bind() {
+    FGAIShip::bind();
+
+    props->tie("station/rel-bearing-deg",
+        SGRawValuePointer<double>(&_stn_relbrg));
+    props->tie("station/true-bearing-deg",
+        SGRawValuePointer<double>(&_stn_truebrg));
+    props->tie("station/range-nm",
+        SGRawValuePointer<double>(&_stn_range));
+    props->tie("station/range-limit-nm",
+        SGRawValuePointer<double>(&_stn_limit));
+    props->tie("station/angle-limit-deg",
+        SGRawValuePointer<double>(&_stn_angle_limit));
+    props->tie("station/speed-kts",
+        SGRawValuePointer<double>(&_stn_speed));
+    props->tie("station/height-ft",
+        SGRawValuePointer<double>(&_stn_height));
+    props->tie("controls/update-interval-sec",
+        SGRawValuePointer<double>(&_interval));
+    props->tie("controls/parent-mp-control",
+        SGRawValuePointer<bool>(&_MPControl));
+    props->tie("station/target-range-nm",
+        SGRawValuePointer<double>(&_tgtrange));
+    props->tie("station/target-brg-deg-t",
+        SGRawValuePointer<double>(&_tgtbrg));
+    props->tie("station/patrol",
+        SGRawValuePointer<bool>(&_patrol));
+}
+
+void FGAIEscort::unbind() {
+    FGAIShip::unbind();
+
+    props->untie("station/rel-bearing-deg");
+    props->untie("station/true-bearing-deg");
+    props->untie("station/range-nm");
+    props->untie("station/range-limit-nm");
+    props->untie("station/angle-limit-deg");
+    props->untie("station/speed-kts");
+    props->untie("station/height-ft");
+    props->untie("controls/update-interval-sec");
+
+}
+
+bool FGAIEscort::init(bool search_in_AI_path) {
+    if (!FGAIShip::init(search_in_AI_path))
+        return false;
+
+    invisible = false;
+    no_roll = false;
+
+    props->setStringValue("controls/parent-name", _parent.c_str());
+    setParentNode();
+    pos = _tgtpos;
+    speed = _parent_speed;
+    hdg = _parent_hdg;
+
+    return true;
+}
+
+void FGAIEscort::update(double dt) {
+    FGAIShip::update(dt);
+
+    RunEscort(dt);
+}
+
+void FGAIEscort::setStnRange(double r) {
+    _stn_range = r;
+}
+
+void FGAIEscort::setStnBrg(double b) {
+    _stn_brg = b;
+}
+
+void FGAIEscort::setStnLimit(double l) {
+    _stn_limit = l;
+}
+
+void FGAIEscort::setStnAngleLimit(double al) {
+    _stn_angle_limit = al;
+}
+
+void FGAIEscort::setStnSpeed(double s) {
+    _stn_speed = s;
+}
+
+void FGAIEscort::setStnHtFt(double h) {
+    _stn_height = h;
+}
+
+void FGAIEscort::setStnDegTrue(bool t) {
+    _stn_deg_true = t;
+}
+
+void FGAIEscort::setMaxSpeed(double m) {
+    _max_speed = m;
+}
+
+void FGAIEscort::setUpdateInterval(double i) {
+    _interval = i;
+}
+
+void FGAIEscort::setStnPatrol(bool p) {
+    _patrol = p;
+}
+
+void FGAIEscort::setParentName(const string& p) {
+    _parent = p;
+}
+
+bool FGAIEscort::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;
+    }
+
+}
+
+void FGAIEscort::setParentNode() {
+
+    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");
+        setParent();
+
+        //double lat = _selected_ac->getDoubleValue("position/latitude-deg");
+        //double lon = _selected_ac->getDoubleValue("position/longitude-deg");
+        //double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
+        //_MPControl = _selected_ac->getBoolValue("controls/mp-control");
+
+        //_selectedpos.setLatitudeDeg(lat);
+        //_selectedpos.setLongitudeDeg(lon);
+        //_selectedpos.setElevationFt(elevation);
+
+        //_parent_speed    = _selected_ac->getDoubleValue("velocities/speed-kts");
+        //_parent_hdg      = _selected_ac->getDoubleValue("orientation/true-heading-deg");
+
+        //if(!_stn_deg_true){
+        //    _stn_truebrg = calcTrueBearingDeg(_stn_brg, _parent_hdg);
+        //    _stn_relbrg = _stn_brg;
+        //    //cout << _name <<" set rel"<<endl;
+        //} else {
+        //    _stn_truebrg = _stn_brg;
+        //    _stn_relbrg = calcRelBearingDeg(_stn_brg, _parent_hdg); 
+        //    //cout << _name << " set true"<<endl;
+        //}
+
+        //double course2;
+
+        //SGGeodesy::direct( _selectedpos, _stn_truebrg, _stn_range * SG_NM_TO_METER,
+        //    _tgtpos, course2);
+
+        //_tgtpos.setElevationFt(_stn_height);
+
+        //calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
+        //    _tgtpos.getLatitudeDeg(), _tgtpos.getLongitudeDeg(), _tgtrange, _tgtbrg);
+
+        //_relbrg = calcRelBearingDeg(_tgtbrg, hdg);
+
+    } else {
+        SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
+            << " parent not found: dying ");
+        setDie(true);
+    }
+
+}
+
+void FGAIEscort::setParent()
+{
+    double lat = _selected_ac->getDoubleValue("position/latitude-deg");
+    double lon = _selected_ac->getDoubleValue("position/longitude-deg");
+    double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
+    _MPControl = _selected_ac->getBoolValue("controls/mp-control");
+
+    _selectedpos.setLatitudeDeg(lat);
+    _selectedpos.setLongitudeDeg(lon);
+    _selectedpos.setElevationFt(elevation);
+
+    _parent_speed    = _selected_ac->getDoubleValue("velocities/speed-kts");
+    _parent_hdg      = _selected_ac->getDoubleValue("orientation/true-heading-deg");
+
+    if(!_stn_deg_true){
+        _stn_truebrg = calcTrueBearingDeg(_stn_brg, _parent_hdg);
+        _stn_relbrg = _stn_brg;
+        //cout << _name <<" set rel"<<endl;
+    } else {
+        _stn_truebrg = _stn_brg;
+        _stn_relbrg = calcRelBearingDeg(_stn_brg, _parent_hdg); 
+        //cout << _name << " set true"<<endl;
+    }
+
+            double course2;
+
+        SGGeodesy::direct( _selectedpos, _stn_truebrg, _stn_range * SG_NM_TO_METER,
+            _tgtpos, course2);
+
+        _tgtpos.setElevationFt(_stn_height);
+
+        calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
+            _tgtpos.getLatitudeDeg(), _tgtpos.getLongitudeDeg(), _tgtrange, _tgtbrg);
+
+        _relbrg = calcRelBearingDeg(_tgtbrg, hdg);
+
+}
+
+void FGAIEscort::calcRangeBearing(double lat, double lon, double lat2, double lon2,
+                                  double &range, double &bearing) const
+{
+    // calculate the bearing and range of the second pos from the first
+    double az2, distance;
+    geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
+    range = distance * SG_METER_TO_NM;
+}
+
+double FGAIEscort::calcRelBearingDeg(double bearing, double heading)
+{
+    double angle = bearing - heading;
+    SG_NORMALIZE_RANGE(angle, -180.0, 180.0);
+    return angle;
+}
+
+double FGAIEscort::calcTrueBearingDeg(double bearing, double heading)
+{
+    double angle = bearing + heading;
+    SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
+    return angle;
+}
+
+double FGAIEscort::calcRecipBearingDeg(double bearing)
+{
+    double angle = bearing - 180;
+    SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
+    return angle;
+}
+
+SGVec3d FGAIEscort::getCartHitchPosAt(const SGVec3d& _off) const {
+    double hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
+    double pitch = _selected_ac->getDoubleValue("orientation/pitch-deg");
+    double roll = _selected_ac->getDoubleValue("orientation/roll-deg");
+
+    // Transform that one to the horizontal local coordinate system.
+    SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
+
+    // and postrotate the orientation of the AIModel wrt the horizontal
+    // local frame
+    hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
+
+    // The offset converted to the usual body fixed coordinate system
+    // rotated to the earth fiexed coordinates axis
+    SGVec3d off = hlTrans.backTransform(_off);
+
+    // Add the position offset of the AIModel to gain the earth centered position
+    SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
+
+    return cartPos + off;
+}
+
+
+void FGAIEscort::setStationSpeed(){
+
+    double speed = 0;
+    double angle = 0;
+
+    // these are the AI rules for the manoeuvring of escorts
+
+    if (_MPControl && _tgtrange > 4 * _stn_limit){
+        SG_LOG(SG_GENERAL, SG_ALERT, "AIEscort: " << _name
+            << " re-aligning to MP pos");
+        pos = _tgtpos;
+        speed = 0;
+        angle = 0;
+    }else if ((_relbrg < -90 || _relbrg > 90) && _tgtrange > _stn_limit ){
+        angle =_relbrg;
+
+        if(_tgtrange > 4 * _stn_limit)
+            speed = 4 * -_stn_speed;
+        else
+            speed = -_stn_speed;
+
+    }else if ((_relbrg >= -90 || _relbrg <= 90) && _tgtrange > _stn_limit){
+        angle = _relbrg;
+
+        if(_tgtrange > 4 * _stn_limit)
+            speed = 4 * _stn_speed;
+        else
+            speed = _stn_speed;
+
+    } else {
+
+        if(_patrol){
+            angle = 15 * sg_random();
+            speed =  5 * sg_random();
+        } else {
+            angle = 0;
+            speed = 0;
+        }
+
+    }
+
+    double station_speed = _parent_speed + speed;
+
+    SG_CLAMP_RANGE(station_speed, 5.0, _max_speed);
+    SG_CLAMP_RANGE(angle, -_stn_angle_limit, _stn_angle_limit);
+
+    AccelTo(station_speed);
+    TurnTo(_parent_hdg + angle);
+    ClimbTo(_stn_height);
+
+}
+
+void FGAIEscort::RunEscort(double dt){
+
+    _dt_count += dt;
+
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Check execution time (currently once every 0.05 sec or 20 fps)
+    // Add a bit of randomization to prevent the execution of all flight plans
+    // in synchrony, which can add significant periodic framerate flutter.
+    // Randomization removed to get better appearance
+    ///////////////////////////////////////////////////////////////////////////
+
+    //cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
+    if (_dt_count < _next_run)
+        return;
+    _next_run = _interval /*+ (0.015 * sg_random())*/;
+
+    if(_parent == ""){
+        return;
+    }
+
+    setParent();
+    setStationSpeed();
+    //getGroundElev(pos);
+
+    _dt_count = 0;
+
+}
+
+// end AIGroundvehicle
diff --git a/src/AIModel/AIEscort.hxx b/src/AIModel/AIEscort.hxx
index d5adff5d5..a2e0ab678 100644
--- a/src/AIModel/AIEscort.hxx
+++ b/src/AIModel/AIEscort.hxx
@@ -1,106 +1,107 @@
-// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
-// by adding a ground following utility
-//
-// Written by Vivian Meazza, started August 2009.
-// - vivian.meazza at lineone.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_AIESCORT_HXX
-#define _FG_AIESCORT_HXX
-
-#include <string>
-#include <list>
-
-#include <simgear/compiler.h>
-
-#include "AIBase.hxx"
-
-#include "AIShip.hxx"
-
-#include "AIManager.hxx"
-#include "AIBase.hxx"
-
-class FGAIEscort : public FGAIShip {
-public:
-    FGAIEscort();
-    virtual ~FGAIEscort();
-
-    virtual void readFromScenario(SGPropertyNode* scFileNode);
-    virtual void bind();
-    virtual void unbind();
-    virtual const char* getTypeString(void) const { return "escort"; }
-
-    bool init(bool search_in_AI_path=false);
-
-private:
-
-    virtual void reinit() { init(); }
-    virtual void update (double dt);
-
-    void setParentName(const std::string& p);
-    void setParent();
-    void setStnRange(double r);
-    void setStnBrg(double y);
-    void setStationSpeed();
-    void setStnLimit(double l);
-    void setStnAngleLimit(double l);
-    void setStnSpeed(double s);
-    void setStnHtFt(double h);
-    void setStnPatrol(bool p);
-    void setStnDegTrue(bool t);
-
-    void setMaxSpeed(double m);
-    void setUpdateInterval(double i);
-
-    void RunEscort(double dt);
-
-    bool getGroundElev(SGGeod inpos);
-
-    SGVec3d getCartHitchPosAt(const SGVec3d& off) const;
-
-    void calcRangeBearing(double lat, double lon, double lat2, double lon2,
-        double &range, double &bearing) const;
-    double calcRelBearingDeg(double bearing, double heading);
-    double calcTrueBearingDeg(double bearing, double heading);
-    double calcRecipBearingDeg(double bearing);
-
-    SGGeod _selectedpos;
-    SGGeod _tgtpos;
-
-    bool   _solid;           // if true ground is solid for FDMs
-    double _load_resistance; // ground load resistanc N/m^2
-    double _frictionFactor;  // dimensionless modifier for Coefficient of Friction
-    double _tgtrange, _tgtbrg;
-    double _ht_agl_ft;
-    double _relbrg, _truebrg;
-    double _parent_speed, _parent_hdg;
-    double _interval;
-
-    double _stn_relbrg, _stn_truebrg, _stn_brg, _stn_range, _stn_height;
-    double _stn_speed, _stn_angle_limit, _stn_limit;
-
-    double _max_speed;
-
-    const SGMaterial* _material;
-    SGPropertyNode_ptr _selected_ac;
-
-    bool _MPControl, _patrol, _stn_deg_true;
-
-    std::string _parent;
-
-};
-
-#endif  // FG_AIGROUNDVEHICLE_HXX
+// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
+// by adding a ground following utility
+//
+// Written by Vivian Meazza, started August 2009.
+// - vivian.meazza at lineone.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_AIESCORT_HXX
+#define _FG_AIESCORT_HXX
+
+#include <string>
+#include <list>
+
+#include <simgear/compiler.h>
+
+#include "AIBase.hxx"
+
+#include "AIShip.hxx"
+
+#include "AIManager.hxx"
+#include "AIBase.hxx"
+
+class FGAIEscort : public FGAIShip {
+public:
+    FGAIEscort();
+    virtual ~FGAIEscort();
+
+    virtual void readFromScenario(SGPropertyNode* scFileNode);
+    virtual void bind();
+    virtual void unbind();
+    virtual const char* getTypeString(void) const { return "escort"; }
+
+    bool init(bool search_in_AI_path=false);
+
+private:
+
+    virtual void reinit() { init(); }
+    virtual void update (double dt);
+
+    void setParentName(const std::string& p);
+    void setParentNode();
+    void setStnRange(double r);
+    void setStnBrg(double y);
+    void setStationSpeed();
+    void setStnLimit(double l);
+    void setStnAngleLimit(double l);
+    void setStnSpeed(double s);
+    void setStnHtFt(double h);
+    void setStnPatrol(bool p);
+    void setStnDegTrue(bool t);
+    void setParent();
+
+    void setMaxSpeed(double m);
+    void setUpdateInterval(double i);
+
+    void RunEscort(double dt);
+
+    bool getGroundElev(SGGeod inpos);
+
+    SGVec3d getCartHitchPosAt(const SGVec3d& off) const;
+
+    void calcRangeBearing(double lat, double lon, double lat2, double lon2,
+        double &range, double &bearing) const;
+    double calcRelBearingDeg(double bearing, double heading);
+    double calcTrueBearingDeg(double bearing, double heading);
+    double calcRecipBearingDeg(double bearing);
+
+    SGGeod _selectedpos;
+    SGGeod _tgtpos;
+
+    bool   _solid;           // if true ground is solid for FDMs
+    double _load_resistance; // ground load resistanc N/m^2
+    double _frictionFactor;  // dimensionless modifier for Coefficient of Friction
+    double _tgtrange, _tgtbrg;
+    double _ht_agl_ft;
+    double _relbrg, _truebrg;
+    double _parent_speed, _parent_hdg;
+    double _interval;
+
+    double _stn_relbrg, _stn_truebrg, _stn_brg, _stn_range, _stn_height;
+    double _stn_speed, _stn_angle_limit, _stn_limit;
+
+    double _max_speed;
+
+    const SGMaterial* _material;
+    SGPropertyNode_ptr _selected_ac;
+
+    bool _MPControl, _patrol, _stn_deg_true;
+
+    std::string _parent;
+
+};
+
+#endif  // FG_AIGROUNDVEHICLE_HXX
diff --git a/src/AIModel/AIGroundVehicle.cxx b/src/AIModel/AIGroundVehicle.cxx
index e65ea5b7e..10ea47e59 100644
--- a/src/AIModel/AIGroundVehicle.cxx
+++ b/src/AIModel/AIGroundVehicle.cxx
@@ -61,9 +61,9 @@ void FGAIGroundVehicle::readFromScenario(SGPropertyNode* scFileNode) {
 
     FGAIShip::readFromScenario(scFileNode);
 
-    setNoRoll(scFileNode->getBoolValue("no-roll", true));
     setName(scFileNode->getStringValue("name", "groundvehicle"));
-    setSMPath(scFileNode->getStringValue("submodel-path", ""));
+    setParentName(scFileNode->getStringValue("parent", ""));
+    setNoRoll(scFileNode->getBoolValue("no-roll", true));
     setContactX1offset(scFileNode->getDoubleValue("contact-x1-offset", 0.0));
     setContactX2offset(scFileNode->getDoubleValue("contact-x2-offset", 0.0));
     setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 35.0));
@@ -74,7 +74,6 @@ void FGAIGroundVehicle::readFromScenario(SGPropertyNode* scFileNode) {
     setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
     setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.1));
     setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.25));
-    setParentName(scFileNode->getStringValue("parent", ""));
     setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 1.0));
     setTowAngleLimit(scFileNode->getDoubleValue("tow-angle-limit-deg", 2.0));
     setInitialTunnel(scFileNode->getBoolValue("tunnel", false));
@@ -125,7 +124,7 @@ void FGAIGroundVehicle::unbind() {
     FGAIShip::unbind();
 
     props->untie("controls/constants/elevation-coeff");
-	props->untie("controls/constants/pitch-coeff");
+    props->untie("controls/constants/pitch-coeff");
     props->untie("position/ht-AGL-ft");
     props->untie("hitch/rel-bearing-deg");
     props->untie("hitch/tow-angle-deg");
@@ -149,6 +148,9 @@ bool FGAIGroundVehicle::init(bool search_in_AI_path) {
     invisible = false;
     _limit = 200;
     no_roll = true;
+
+    props->setStringValue("controls/parent-name", _parent.c_str());
+    setParentNode();
 
     return true;
 }
@@ -342,12 +344,15 @@ bool FGAIGroundVehicle::getPitch() {
 
     }
 
-    getGroundElev(pos);
+    //getGroundElev(pos);
 
     return true;
 }
 
-void FGAIGroundVehicle::setParent() {
+void FGAIGroundVehicle::setParentNode() {
+
+    if(_parent == "")
+        return;
 
     const SGPropertyNode_ptr ai = fgGetNode("/ai/models", true);
 
@@ -377,40 +382,16 @@ void FGAIGroundVehicle::setParent() {
 
     if (_selected_ac != 0){
         const string name = _selected_ac->getStringValue("name");
-        double lat = _selected_ac->getDoubleValue("position/latitude-deg");
-        double lon = _selected_ac->getDoubleValue("position/longitude-deg");
-        double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
-        double hitch_x_offset_m = _selected_ac->getDoubleValue("hitch/x-offset-ft")
-            * SG_FEET_TO_METER;
-        double hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
-            * SG_FEET_TO_METER;
-        double hitch_z_offset_m = _selected_ac->getDoubleValue("hitch/z-offset-ft")
-            * SG_FEET_TO_METER;
-        
-        _selectedpos.setLatitudeDeg(lat);
-        _selectedpos.setLongitudeDeg(lon);
-        _selectedpos.setElevationFt(elevation);
-
         _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");
-
-        _parent_speed    = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
-
-        SGVec3d rear_hitch(-hitch_x_offset_m, hitch_y_offset_m, 0);
-        SGVec3d RearHitch = getCartHitchPosAt(rear_hitch);
-
-        SGGeod rearpos = SGGeod::fromCart(RearHitch);
-
-        double user_lat = rearpos.getLatitudeDeg();
-        double user_lon = rearpos.getLongitudeDeg();
-
-        double range, bearing;
-
-        calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
-            user_lat, user_lon, range, bearing);
-        _range_ft = range * 6076.11549;
-        _relbrg = calcRelBearingDeg(bearing, hdg);
+        _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 ");
@@ -419,6 +400,34 @@ void FGAIGroundVehicle::setParent() {
 
 }
 
+void FGAIGroundVehicle::setParent(){
+
+    double lat = _selected_ac->getDoubleValue("position/latitude-deg");
+    double lon = _selected_ac->getDoubleValue("position/longitude-deg");
+    double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
+
+    _selectedpos.setLatitudeDeg(lat);
+    _selectedpos.setLongitudeDeg(lon);
+    _selectedpos.setElevationFt(elevation);
+
+    _parent_speed = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
+
+    SGVec3d rear_hitch(-_hitch_x_offset_m, _hitch_y_offset_m, 0);
+    SGVec3d RearHitch = getCartHitchPosAt(rear_hitch);
+
+    SGGeod rearpos = SGGeod::fromCart(RearHitch);
+
+    double user_lat = rearpos.getLatitudeDeg();
+    double user_lon = rearpos.getLongitudeDeg();
+
+    double range, bearing;
+
+    calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
+        user_lat, user_lon, range, bearing);
+    _range_ft = range * 6076.11549;
+    _relbrg = calcRelBearingDeg(bearing, hdg);
+}
+
 void FGAIGroundVehicle::calcRangeBearing(double lat, double lon, double lat2, double lon2,
                             double &range, double &bearing) const
 {
diff --git a/src/AIModel/AIGroundVehicle.hxx b/src/AIModel/AIGroundVehicle.hxx
index 721ebf303..8547e67d0 100644
--- a/src/AIModel/AIGroundVehicle.hxx
+++ b/src/AIModel/AIGroundVehicle.hxx
@@ -1,105 +1,107 @@
-// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
-// by adding a ground following utility
-//
-// Written by Vivian Meazza, started August 2009.
-// - vivian.meazza at lineone.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_AIGROUNDVEHICLE_HXX
-#define _FG_AIGROUNDVEHICLE_HXX
-
-#include <math.h>
-#include <vector>
-#include <simgear/structure/SGSharedPtr.hxx>
-#include <simgear/scene/material/mat.hxx>
-
-#include "AIShip.hxx"
-
-#include "AIManager.hxx"
-#include "AIBase.hxx"
-
-class FGAIGroundVehicle : public FGAIShip {
-public:
-    FGAIGroundVehicle();
-    virtual ~FGAIGroundVehicle();
-
-    virtual void readFromScenario(SGPropertyNode* scFileNode);
-    virtual void bind();
-    virtual void unbind();
-    virtual const char* getTypeString(void) const { return "groundvehicle"; }
-
-    bool init(bool search_in_AI_path=false);
-
-private:
-
-    virtual void reinit() { init(); }
-    virtual void update (double dt);
-
-    void setNoRoll(bool nr);
-    void setContactX1offset(double x1);
-    void setContactX2offset(double x2);
-    void setXOffset(double x);
-    void setYOffset(double y);
-    void setZOffset(double z);
-
-    void setPitchCoeff(double pc);
-    void setElevCoeff(double ec);
-    void setTowAngleGain(double g);
-    void setTowAngleLimit(double l);
-    void setElevation(double _elevation, double dt, double _elevation_coeff);
-    void setPitch(double _pitch, double dt, double _pitch_coeff);
-    void setTowAngle(double _relbrg, double dt, double _towangle_coeff);
-    void setParentName(const string& p);
-    void setTrainSpeed(double s, double dt, double coeff);
-    void setParent();
-    void AdvanceFP();
-    void setTowSpeed();
-    void RunGroundVehicle(double dt);
-
-    bool getGroundElev(SGGeod inpos);
-    bool getPitch();
-
-    SGVec3d getCartHitchPosAt(const SGVec3d& off) const;
-
-    void calcRangeBearing(double lat, double lon, double lat2, double lon2,
-        double &range, double &bearing) const;
-    double calcRelBearingDeg(double bearing, double heading);
-
-    SGGeod _selectedpos;
-
-    bool   _solid;           // if true ground is solid for FDMs
-    double _load_resistance; // ground load resistanc N/m^2
-    double _frictionFactor;  // dimensionless modifier for Coefficient of Friction
-    double _elevation, _elevation_coeff;
-    double _tow_angle_gain, _tow_angle_limit;
-    double _ht_agl_ft;
-    double _contact_x1_offset, _contact_x2_offset, _contact_z_offset;
-    double _pitch, _pitch_coeff, _pitch_deg;
-    double _speed_coeff, _speed_kt;
-    double _x_offset, _y_offset;
-    double _range_ft;
-    double _relbrg;
-    double _parent_speed, _parent_x_offset, _parent_y_offset, _parent_z_offset;
-    double _dt_count, _next_run, _break_count;
-
-    const SGMaterial* _material;
-    SGPropertyNode_ptr _selected_ac;
-
-    string _parent;
-
-};
-
-#endif  // FG_AIGROUNDVEHICLE_HXX
+// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
+// by adding a ground following utility
+//
+// Written by Vivian Meazza, started August 2009.
+// - vivian.meazza at lineone.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_AIGROUNDVEHICLE_HXX
+#define _FG_AIGROUNDVEHICLE_HXX
+
+#include <math.h>
+#include <vector>
+#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/scene/material/mat.hxx>
+
+#include "AIShip.hxx"
+
+#include "AIManager.hxx"
+#include "AIBase.hxx"
+
+class FGAIGroundVehicle : public FGAIShip {
+public:
+    FGAIGroundVehicle();
+    virtual ~FGAIGroundVehicle();
+
+    virtual void readFromScenario(SGPropertyNode* scFileNode);
+    virtual void bind();
+    virtual void unbind();
+    virtual const char* getTypeString(void) const { return "groundvehicle"; }
+
+    bool init(bool search_in_AI_path=false);
+
+private:
+
+    virtual void reinit() { init(); }
+    virtual void update (double dt);
+
+    void setNoRoll(bool nr);
+    void setContactX1offset(double x1);
+    void setContactX2offset(double x2);
+    void setXOffset(double x);
+    void setYOffset(double y);
+    void setZOffset(double z);
+
+    void setPitchCoeff(double pc);
+    void setElevCoeff(double ec);
+    void setTowAngleGain(double g);
+    void setTowAngleLimit(double l);
+    void setElevation(double _elevation, double dt, double _elevation_coeff);
+    void setPitch(double _pitch, double dt, double _pitch_coeff);
+    void setTowAngle(double _relbrg, double dt, double _towangle_coeff);
+    void setParentName(const string& p);
+    void setTrainSpeed(double s, double dt, double coeff);
+    void setParent();
+    void setParentNode();
+    void AdvanceFP();
+    void setTowSpeed();
+    void RunGroundVehicle(double dt);
+
+    bool getGroundElev(SGGeod inpos);
+    bool getPitch();
+
+    SGVec3d getCartHitchPosAt(const SGVec3d& off) const;
+
+    void calcRangeBearing(double lat, double lon, double lat2, double lon2,
+        double &range, double &bearing) const;
+    double calcRelBearingDeg(double bearing, double heading);
+
+    SGGeod _selectedpos;
+
+    bool   _solid;           // if true ground is solid for FDMs
+    double _load_resistance; // ground load resistanc N/m^2
+    double _frictionFactor;  // dimensionless modifier for Coefficient of Friction
+    double _elevation, _elevation_coeff;
+    double _tow_angle_gain, _tow_angle_limit;
+    double _ht_agl_ft;
+    double _contact_x1_offset, _contact_x2_offset, _contact_z_offset;
+    double _pitch, _pitch_coeff, _pitch_deg;
+    double _speed_coeff, _speed_kt;
+    double _x_offset, _y_offset;
+    double _range_ft;
+    double _relbrg;
+    double _parent_speed, _parent_x_offset, _parent_y_offset, _parent_z_offset;
+    double _hitch_x_offset_m, _hitch_y_offset_m, _hitch_z_offset_m;
+    double _dt_count, _next_run, _break_count;
+
+    const SGMaterial* _material;
+    SGPropertyNode_ptr _selected_ac;
+
+    string _parent;
+
+};
+
+#endif  // FG_AIGROUNDVEHICLE_HXX
diff --git a/src/AIModel/AIShip.cxx b/src/AIModel/AIShip.cxx
index 41f09550e..b27b21d96 100644
--- a/src/AIModel/AIShip.cxx
+++ b/src/AIModel/AIShip.cxx
@@ -99,6 +99,7 @@ void FGAIShip::readFromScenario(SGPropertyNode* scFileNode) {
     setRudderConstant(scFileNode->getDoubleValue("rudder-constant", 0.5));
     setFixedTurnRadius(scFileNode->getDoubleValue("fixed-turn-radius-ft", 500));
     setSpeedConstant(scFileNode->getDoubleValue("speed-constant", 0.5));
+    setSMPath(scFileNode->getStringValue("submodel-path", ""));
 
     if (!flightplan.empty()) {
         SG_LOG(SG_GENERAL, SG_ALERT, "getting flightplan: " << _name );
@@ -250,12 +251,12 @@ void FGAIShip::update(double dt) {
     // Update the velocity information stored in those nodes.
     // Transform that one to the horizontal local coordinate system.
     SGQuatd ec2hl = SGQuatd::fromLonLat(pos);
-    // The orientation of the carrier wrt the horizontal local frame
+    // The orientation of the ship wrt the horizontal local frame
     SGQuatd hl2body = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
     // and postrotate the orientation of the AIModel wrt the horizontal
     // local frame
     SGQuatd ec2body = ec2hl*hl2body;
-    // The cartesian position of the carrier in the wgs84 world
+    // The cartesian position of the ship in the wgs84 world
     SGVec3d cartPos = SGVec3d::fromGeod(pos);
 
     // The simulation time this transform is meant for
@@ -680,7 +681,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
         if (_next_name == "TUNNEL"){
             _tunnel = !_tunnel;
 
-            SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " " << sp_turn_radius_nm );
+            SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: " << _name << " " << sp_turn_radius_nm );
 
             fp->IncrementWaypoint(false);
             next = fp->getNextWaypoint();
@@ -697,7 +698,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
         }else if(_next_name == "END" || fp->getNextWaypoint() == 0) {
 
             if (_repeat) {
-                SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: "<< _name << " Flightplan repeating ");
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: "<< _name << " Flightplan repeating ");
                 fp->restart();
                 prev = curr;
                 curr = fp->getCurrentWaypoint();
@@ -711,7 +712,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
                 _lead_angle = 0;
                 AccelTo(prev->speed);
             } else if (_restart){
-                SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " Flightplan restarting ");
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " Flightplan restarting ");
                 _missed_count = 0;
                 initFlightPlan();
             } else {
@@ -755,7 +756,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
             _until_time = next->time;
             setUntilTime(next->time);
             if (until_time_sec > time_sec) {
-                SG_LOG(SG_GENERAL, SG_ALERT, "AIShip: " << _name << " "
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: " << _name << " "
                     << curr->name << " waiting until: "
                     << _until_time << " " << until_time_sec << " now " << time_sec );
                 setSpeed(0);
@@ -763,7 +764,7 @@ void FGAIShip::ProcessFlightPlan(double dt) {
                 _waiting = true;
                 return;
             } else {
-                SG_LOG(SG_GENERAL, SG_DEBUG, "AIShip: "
+                SG_LOG(SG_GENERAL, SG_INFO, "AIShip: "
                     << _name << " wait until done: getting new waypoints ");
                 setUntilTime("");
                 fp->IncrementWaypoint(false);
diff --git a/src/AIModel/AIWingman.cxx b/src/AIModel/AIWingman.cxx
index 39c20bbc6..2bc8e2c0f 100644
--- a/src/AIModel/AIWingman.cxx
+++ b/src/AIModel/AIWingman.cxx
@@ -75,6 +75,11 @@ void FGAIWingman::bind() {
         &FGAIBase::_getLongitude,
         &FGAIBase::_setLongitude));
 
+    props->tie("controls/formate-to-ac",
+        SGRawValueMethods<FGAIBallistic,bool>
+        (*this, &FGAIBallistic::getFormate, &FGAIBallistic::setFormate));
+
+
     props->tie("orientation/pitch-deg",   SGRawValuePointer<double>(&pitch));
     props->tie("orientation/roll-deg",    SGRawValuePointer<double>(&roll));
     props->tie("orientation/true-heading-deg", SGRawValuePointer<double>(&hdg));
@@ -122,6 +127,8 @@ void FGAIWingman::unbind() {
     props->untie("orientation/roll-deg");
     props->untie("orientation/true-heading-deg");
 
+    props->untie("controls/formate-to-ac");
+
     props->untie("submodels/serviceable");
 
     props->untie("velocities/true-airspeed-kt");

From 9018d65c5281f54b3cb562d61ed0bec32e809562 Mon Sep 17 00:00:00 2001
From: Vivian Meazza <vivian.meazza@lineone.net>
Date: Thu, 2 Sep 2010 09:25:53 +0100
Subject: [PATCH 2/8] Add contrail as a standard property

Signed-off-by: Vivian Meazza <vivian.meazza@lineone.net>
---
 src/MultiPlayer/multiplaymgr.cxx | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/MultiPlayer/multiplaymgr.cxx b/src/MultiPlayer/multiplaymgr.cxx
index 8d4783315..de2dacd22 100644
--- a/src/MultiPlayer/multiplaymgr.cxx
+++ b/src/MultiPlayer/multiplaymgr.cxx
@@ -159,6 +159,7 @@ FGMultiplayMgr::sIdPropertyList[] = {
   {1101, "sim/model/livery/file", simgear::props::STRING},
 
   {1200, "environment/wildfire/data", simgear::props::STRING},
+  {1201, "environment/contrail", simgear::props::INT},
 
   {1300, "tanker", simgear::props::INT},
 

From 8a97ed354d7d5fdccd0dce08e17d4a5512b288ca Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 6 Sep 2010 09:12:25 +0100
Subject: [PATCH 3/8] Fix submodel code to work with multiple aircraft dirs.

---
 src/AIModel/submodel.cxx | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/src/AIModel/submodel.cxx b/src/AIModel/submodel.cxx
index 471b45dd1..8963be719 100644
--- a/src/AIModel/submodel.cxx
+++ b/src/AIModel/submodel.cxx
@@ -515,9 +515,7 @@ void FGSubmodelMgr::setData(int id, string& path, bool serviceable)
 {
     SGPropertyNode root;
 
-    SGPath config(globals->get_fg_root());
-    config.append(path);
-    SG_LOG(SG_GENERAL, SG_DEBUG, "setData: path " << path);
+    SGPath config = globals->resolve_aircraft_path(path);
     try {
         SG_LOG(SG_GENERAL, SG_DEBUG,
                 "Submodels: Trying to read AI submodels file: " << config.str());
@@ -620,10 +618,7 @@ void FGSubmodelMgr::setData(int id, string& path, bool serviceable)
 void FGSubmodelMgr::setSubData(int id, string& path, bool serviceable)
 {
     SGPropertyNode root;
-
-    SGPath config(globals->get_fg_root());
-    config.append(path);
-    SG_LOG(SG_GENERAL, SG_DEBUG, "setSubData: path " << path);
+    SGPath config = globals->resolve_aircraft_path(path);
 
     try {
         SG_LOG(SG_GENERAL, SG_DEBUG,

From a7a2cb393a0259f4f16d905974fe25b25759a909 Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 6 Sep 2010 09:13:10 +0100
Subject: [PATCH 4/8] Use the new Simgear ResourceManager to resolve paths.

---
 src/Main/globals.cxx | 90 +++++++++++++++++++-------------------------
 src/Main/main.cxx    |  1 -
 2 files changed, 39 insertions(+), 52 deletions(-)

diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx
index bfa51f72f..031b91607 100644
--- a/src/Main/globals.cxx
+++ b/src/Main/globals.cxx
@@ -34,6 +34,7 @@
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/structure/event_mgr.hxx>
 #include <simgear/sound/soundmgr_openal.hxx>
+#include <simgear/misc/ResourceManager.hxx>
 
 #include <Aircraft/controls.hxx>
 #include <Airports/runways.hxx>
@@ -56,7 +57,36 @@
 #include "fg_props.hxx"
 #include "fg_io.hxx"
 
-
+class AircraftResourceProvider : public simgear::ResourceProvider
+{
+public:
+  AircraftResourceProvider() :
+    simgear::ResourceProvider(simgear::ResourceManager::PRIORITY_HIGH)
+  {
+  }
+  
+  virtual SGPath resolve(const std::string& aResource, SGPath&) const
+  {
+    string_list pieces(sgPathBranchSplit(aResource));
+    if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) {
+      return SGPath(); // not an Aircraft path
+    }
+    
+    const char* aircraftDir = fgGetString("/sim/aircraft-dir");
+    string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir));
+    if (aircraftDirPieces.empty() || (aircraftDirPieces.back() != pieces[1])) {
+      return SGPath(); // current aircraft-dir does not match resource aircraft
+    }
+    
+    SGPath r(aircraftDir);
+    for (unsigned int i=2; i<pieces.size(); ++i) {
+      r.append(pieces[i]);
+    }
+    
+    return r.exists() ? r : SGPath();
+  }
+};
+
 ////////////////////////////////////////////////////////////////////////
 // Implementation of FGGlobals.
 ////////////////////////////////////////////////////////////////////////
@@ -186,6 +216,9 @@ void FGGlobals::set_fg_root (const string &root) {
     n = n->getChild("fg-root", 0, true);
     n->setStringValue(fg_root.c_str());
     n->setAttribute(SGPropertyNode::WRITE, false);
+    
+    simgear::ResourceManager::instance()->addBasePath(fg_root, 
+      simgear::ResourceManager::PRIORITY_DEFAULT);
 }
 
 void FGGlobals::set_fg_scenery (const string &scenery)
@@ -243,6 +276,9 @@ void FGGlobals::append_aircraft_path(const std::string& path)
   unsigned int index = fg_aircraft_dirs.size();  
   fg_aircraft_dirs.push_back(path);
   
+  simgear::ResourceManager::instance()->addBasePath(path, 
+    simgear::ResourceManager::PRIORITY_NORMAL);
+  
 // make aircraft dirs available to Nasal
   SGPropertyNode* sim = fgGetNode("/sim", true);
   sim->removeChild("fg-aircraft", index, false);
@@ -261,60 +297,12 @@ void FGGlobals::append_aircraft_paths(const std::string& path)
 
 SGPath FGGlobals::resolve_aircraft_path(const std::string& branch) const
 {
-  string_list pieces(sgPathBranchSplit(branch));
-  if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) {
-    SG_LOG(SG_AIRCRAFT, SG_ALERT, "resolve_aircraft_path: bad path:" <<  branch);
-    return SGPath();
-  }
-  
-// check current aircraft dir first (takes precedence, allows Generics to be
-// over-riden
-  const char* aircraftDir = fgGetString("/sim/aircraft-dir");
-  string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir));
-  if (!aircraftDirPieces.empty() && (aircraftDirPieces.back() == pieces[1])) {
-    SGPath r(aircraftDir);
-    
-    for (unsigned int i=2; i<pieces.size(); ++i) {
-      r.append(pieces[i]);
-    }
-        
-    if (r.exists()) {
-      std::cout << "using aircraft-dir for:" << r.str() << std::endl;
-      return r;
-    }
-  } // of using aircraft-dir case
-  
-// try each fg_aircraft_dirs in turn
-  for (unsigned int p=0; p<fg_aircraft_dirs.size(); ++p) {
-    SGPath r(fg_aircraft_dirs[p]);
-    r.append(branch);
-    if (r.exists()) {
-      std::cout << "using aircraft directory for:" << r.str() << std::endl;
-      return r;
-    }
-  } // of fg_aircraft_dirs iteration
-
-// finally, try fg_root
-  SGPath r(fg_root);
-  r.append(branch);
-  if (r.exists()) {
-    std::cout << "using FG_ROOT for:" << r.str() << std::endl;
-    return r;
-  }
-
-  SG_LOG(SG_AIRCRAFT, SG_ALERT, "resolve_aircraft_path: failed to resolve:" << branch);
-  return SGPath();
+  return simgear::ResourceManager::instance()->findPath(branch);
 }
 
 SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const
 {
-  if (branch.find("Aircraft/") == 0) {
-    return resolve_aircraft_path(branch);
-  } else {
-    SGPath r(fg_root);
-    r.append(branch);
-    return r;
-  }
+  return simgear::ResourceManager::instance()->findPath(branch);
 }
 
 FGRenderer *
diff --git a/src/Main/main.cxx b/src/Main/main.cxx
index 7fbc9d7e4..894dd0010 100644
--- a/src/Main/main.cxx
+++ b/src/Main/main.cxx
@@ -391,7 +391,6 @@ static void fgIdleFunction ( void ) {
         globals->set_matlib( new SGMaterialLib );
         simgear::SGModelLib::init(globals->get_fg_root());
         simgear::SGModelLib::setPropRoot(globals->get_props());
-        simgear::SGModelLib::setResolveFunc(resolve_path);
         simgear::SGModelLib::setPanelFunc(load_panel);
         
         ////////////////////////////////////////////////////////////////////

From 8330449c5fba742526175ce3e4fc0f9b97903d5e Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 6 Sep 2010 09:28:28 +0100
Subject: [PATCH 5/8] Pass current-dir into XMLSound (and update to revised
 SGSoundSample ctor)

---
 src/Environment/fgclouds.cxx    | 2 +-
 src/Instrumentation/mk_viii.cxx | 7 ++-----
 src/Main/fg_commands.cxx        | 2 +-
 src/Sound/fg_fx.cxx             | 2 +-
 4 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/Environment/fgclouds.cxx b/src/Environment/fgclouds.cxx
index 208fa402b..57d7ba42e 100644
--- a/src/Environment/fgclouds.cxx
+++ b/src/Environment/fgclouds.cxx
@@ -66,7 +66,7 @@ void FGClouds::set_update_event(int count) {
 
 void FGClouds::init(void) {
 	if( snd_lightning == NULL ) {
-		snd_lightning = new SGSoundSample(globals->get_fg_root().c_str(), "Sounds/thunder.wav");
+		snd_lightning = new SGSoundSample("Sounds/thunder.wav", SGPath());
 		snd_lightning->set_max_dist(7000.0f);
 		snd_lightning->set_reference_dist(3000.0f);
 		SGSoundMgr *smgr = globals->get_soundmgr();
diff --git a/src/Instrumentation/mk_viii.cxx b/src/Instrumentation/mk_viii.cxx
index 12f3ef050..22cdb723b 100755
--- a/src/Instrumentation/mk_viii.cxx
+++ b/src/Instrumentation/mk_viii.cxx
@@ -2272,13 +2272,10 @@ MK_VIII::VoicePlayer::get_sample (const char *name)
   SGSoundSample *sample = _sgr->find(refname.str());
   if (! sample)
     {
-      SGPath sample_path(globals->get_fg_root());
-      sample_path.append("Sounds/mk-viii");
-
-      string filename = string(name) + ".wav";
+      string filename = "Sounds/mk-viii" + string(name) + ".wav";
       try
 	{
-	  sample = new SGSoundSample(sample_path.c_str(), filename.c_str());
+	  sample = new SGSoundSample(filename.c_str(), SGPath());
 	}
       catch (const sg_exception &e)
 	{
diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx
index ddeab463b..354a92bc0 100644
--- a/src/Main/fg_commands.cxx
+++ b/src/Main/fg_commands.cxx
@@ -1211,7 +1211,7 @@ do_play_audio_sample (const SGPropertyNode * arg)
            queue->tie_to_listener();
         }
 
-        SGSoundSample *msg = new SGSoundSample(path.c_str(), file.c_str());
+        SGSoundSample *msg = new SGSoundSample(file.c_str(), path);
         msg->set_volume( volume );
         queue->add( msg );
 
diff --git a/src/Sound/fg_fx.cxx b/src/Sound/fg_fx.cxx
index 950e0bdd0..ab0ace0a9 100644
--- a/src/Sound/fg_fx.cxx
+++ b/src/Sound/fg_fx.cxx
@@ -94,7 +94,7 @@ FGFX::init()
   
             try {
                 sound->init(globals->get_props(), node->getChild(i), this,
-                            _avionics, globals->get_fg_root());
+                            _avionics, path.dir());
   
                 _sound.push_back(sound);
             } catch ( sg_exception &e ) {

From 18a5a2a144c66ce8d81946174a015fcdb037ad72 Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 6 Sep 2010 16:10:58 +0100
Subject: [PATCH 6/8] Fix one more place to use path resolution (and hence work
 with multiple aircraft dirs) Thanks to Jentron for the catch.

---
 src/Systems/electrical.cxx | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/Systems/electrical.cxx b/src/Systems/electrical.cxx
index 18e80222f..d711b4dca 100644
--- a/src/Systems/electrical.cxx
+++ b/src/Systems/electrical.cxx
@@ -373,9 +373,8 @@ void FGElectricalSystem::init () {
     }
 
     if ( path.length() ) {
-        SGPath config( globals->get_fg_root() );
-        config.append( path );
-
+        SGPath config = globals->resolve_aircraft_path(path);
+        
         // load an obsolete xml configuration
         SG_LOG( SG_ALL, SG_WARN,
                 "Reading deprecated xml electrical system model from\n    "

From e8b0bb872abb49cfb25dbfcaecb84ab0f7d837db Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 6 Sep 2010 22:57:48 +0100
Subject: [PATCH 7/8] Register the aircraft resource provider.

---
 src/Main/globals.cxx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx
index 031b91607..c84870dde 100644
--- a/src/Main/globals.cxx
+++ b/src/Main/globals.cxx
@@ -135,7 +135,7 @@ FGGlobals::FGGlobals() :
     airwaynet( NULL ),
     multiplayer_mgr( NULL )
 {
-  
+  simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider());
 }
 
 

From 7227973e2fc493f82e1477ba82e3e8aa956b23ef Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Wed, 8 Sep 2010 11:01:26 +0100
Subject: [PATCH 8/8] Don't expect an 'Aircraft' sub-directory within each
 aircraft-dir.

---
 src/Main/globals.cxx | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/Main/globals.cxx b/src/Main/globals.cxx
index c84870dde..0bd14a3bc 100644
--- a/src/Main/globals.cxx
+++ b/src/Main/globals.cxx
@@ -72,6 +72,7 @@ public:
       return SGPath(); // not an Aircraft path
     }
     
+  // test against the aircraft-dir property
     const char* aircraftDir = fgGetString("/sim/aircraft-dir");
     string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir));
     if (aircraftDirPieces.empty() || (aircraftDirPieces.back() != pieces[1])) {
@@ -83,7 +84,24 @@ public:
       r.append(pieces[i]);
     }
     
-    return r.exists() ? r : SGPath();
+    if (r.exists()) {
+      SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " via /sim/aircraft-dir: " << r.str());
+      return r;
+    }
+  
+  // try each aircaft dir in turn
+    std::string res(aResource, 9); // resource path with 'Aircraft/' removed
+    const string_list& dirs(globals->get_aircraft_paths());
+    string_list::const_iterator it = dirs.begin();
+    for (; it != dirs.end(); ++it) {
+      SGPath p(*it, res);
+      if (p.exists()) {
+        SG_LOG(SG_IO, SG_INFO, "found path:" << aResource << " in aircraft dir: " << r.str());
+        return p;
+      }
+    } // of aircraft path iteration
+    
+    return SGPath(); // not found
   }
 };
 
@@ -276,9 +294,6 @@ void FGGlobals::append_aircraft_path(const std::string& path)
   unsigned int index = fg_aircraft_dirs.size();  
   fg_aircraft_dirs.push_back(path);
   
-  simgear::ResourceManager::instance()->addBasePath(path, 
-    simgear::ResourceManager::PRIORITY_NORMAL);
-  
 // make aircraft dirs available to Nasal
   SGPropertyNode* sim = fgGetNode("/sim", true);
   sim->removeChild("fg-aircraft", index, false);