diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index 66360d8a5..40c790a16 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -51,7 +51,8 @@ const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = { FGAIAircraft *FGAIAircraft::_self = NULL; -FGAIAircraft::FGAIAircraft() { +FGAIAircraft::FGAIAircraft(FGAIManager* mgr) { + manager = mgr; _self = this; // set heading and altitude locks @@ -173,10 +174,10 @@ void FGAIAircraft::Run(double dt) { // adjust altitude (meters) based on current vertical speed (fpm) altitude += vs * 0.0166667 * dt * SG_FEET_TO_METER; + double altitude_ft = altitude * SG_METER_TO_FEET; // find target vertical speed if altitude lock engaged if (alt_lock) { - double altitude_ft = altitude * SG_METER_TO_FEET; if (altitude_ft < tgt_altitude) { tgt_vs = tgt_altitude - altitude_ft; if (tgt_vs > performance->climb_rate) @@ -203,6 +204,74 @@ void FGAIAircraft::Run(double dt) { // match pitch angle to vertical speed pitch = vs * 0.005; + //###########################// + // do calculations for radar // + //###########################// + + // copy values from the AIManager + double user_latitude = manager->get_user_latitude(); + double user_longitude = manager->get_user_longitude(); + double user_altitude = manager->get_user_altitude(); + double user_heading = manager->get_user_heading(); + double user_pitch = manager->get_user_pitch(); + double user_yaw = manager->get_user_yaw(); + double user_speed = manager->get_user_speed(); + + // calculate range to target in feet and nautical miles + double lat_range = fabs(pos.lat() - user_latitude) * ft_per_deg_lat; + double lon_range = fabs(pos.lon() - user_longitude) * ft_per_deg_lon; + double range_ft = sqrt( lat_range*lat_range + lon_range*lon_range ); + range = range_ft / 6076.11549; + + // calculate bearing to target + if (pos.lat() >= user_latitude) { + bearing = atan2(lat_range, lon_range) * SG_RADIANS_TO_DEGREES; + if (pos.lon() >= user_longitude) { + bearing = 90.0 - bearing; + } else { + bearing = 270.0 + bearing; + } + } else { + bearing = atan2(lon_range, lat_range) * SG_RADIANS_TO_DEGREES; + if (pos.lon() >= user_longitude) { + bearing = 180.0 - bearing; + } else { + bearing = 180.0 + bearing; + } + } + + // calculate look left/right to target, without yaw correction + horiz_offset = bearing - user_heading; + if (horiz_offset > 180.0) horiz_offset -= 360.0; + if (horiz_offset < -180.0) horiz_offset += 360.0; + + // calculate elevation to target + elevation = atan2( altitude_ft - user_altitude, range_ft ) + * SG_RADIANS_TO_DEGREES; + + // calculate look up/down to target + vert_offset = elevation + user_pitch; + +/* this calculation needs to be fixed + // calculate range rate + double recip_bearing = bearing + 180.0; + if (recip_bearing > 360.0) recip_bearing -= 360.0; + double my_horiz_offset = recip_bearing - hdg; + if (my_horiz_offset > 180.0) my_horiz_offset -= 360.0; + if (my_horiz_offset < -180.0) my_horiz_offset += 360.0; + rdot = (-user_speed * cos( horiz_offset * SG_DEGREES_TO_RADIANS )) + + (-speed * 1.686 * cos( my_horiz_offset * SG_DEGREES_TO_RADIANS )); +*/ + + // now correct look left/right for yaw + horiz_offset += user_yaw; + + // calculate values for radar display + y_shift = range * cos( horiz_offset * SG_DEGREES_TO_RADIANS); + x_shift = range * sin( horiz_offset * SG_DEGREES_TO_RADIANS); + rotation = hdg - user_heading; + if (rotation < 0.0) rotation += 360.0; + } diff --git a/src/AIModel/AIAircraft.hxx b/src/AIModel/AIAircraft.hxx index 8d16f381e..6ea34c092 100644 --- a/src/AIModel/AIAircraft.hxx +++ b/src/AIModel/AIAircraft.hxx @@ -49,7 +49,7 @@ public: enum aircraft_e {LIGHT=0, WW2_FIGHTER, JET_TRANSPORT, JET_FIGHTER}; static const PERF_STRUCT settings[]; - FGAIAircraft(); + FGAIAircraft(FGAIManager* mgr); ~FGAIAircraft(); bool init(); diff --git a/src/AIModel/AIBallistic.cxx b/src/AIModel/AIBallistic.cxx index 86703da9c..0e7249e4e 100644 --- a/src/AIModel/AIBallistic.cxx +++ b/src/AIModel/AIBallistic.cxx @@ -27,7 +27,8 @@ #include "AIBallistic.hxx" -FGAIBallistic::FGAIBallistic() { +FGAIBallistic::FGAIBallistic(FGAIManager* mgr) { + manager = mgr; _type_str = "ballistic"; } diff --git a/src/AIModel/AIBallistic.hxx b/src/AIModel/AIBallistic.hxx index 3878778b9..479dc44e5 100644 --- a/src/AIModel/AIBallistic.hxx +++ b/src/AIModel/AIBallistic.hxx @@ -28,7 +28,7 @@ class FGAIBallistic : public FGAIBase { public: - FGAIBallistic(); + FGAIBallistic(FGAIManager* mgr); ~FGAIBallistic(); bool init(); diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index 16f956ec6..baa13f865 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -48,9 +48,12 @@ FGAIBase::FGAIBase() { _self = this; _type_str = "model"; tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0; + bearing = elevation = range = rdot = 0.0; + x_shift = y_shift = rotation = 0.0; } FGAIBase::~FGAIBase() { + unbind(); _self = NULL; } @@ -91,7 +94,8 @@ bool FGAIBase::init() { } void FGAIBase::bind() { - props->tie("velocities/airspeed-kt", SGRawValuePointer(&speed)); + props->tie("id", SGRawValuePointer(&id)); + props->tie("velocities/true-airspeed-kt", SGRawValuePointer(&speed)); props->tie("velocities/vertical-speed-fps", SGRawValueFunctions(FGAIBase::_getVS_fps, FGAIBase::_setVS_fps)); @@ -108,7 +112,17 @@ void FGAIBase::bind() { props->tie("orientation/pitch-deg", SGRawValuePointer(&pitch)); props->tie("orientation/roll-deg", SGRawValuePointer(&roll)); - props->tie("orientation/heading-deg", SGRawValuePointer(&hdg)); + props->tie("orientation/true-heading-deg", SGRawValuePointer(&hdg)); + + props->tie("radar/bearing-deg", SGRawValueFunctions(FGAIBase::_getBearing)); + props->tie("radar/elevation-deg", SGRawValueFunctions(FGAIBase::_getElevation)); + props->tie("radar/range-nm", SGRawValueFunctions(FGAIBase::_getRange)); +// props->tie("radar/rdot-kts", SGRawValueFunctions(FGAIBase::_getRdot)); + props->tie("radar/h-offset", SGRawValueFunctions(FGAIBase::_getH_offset)); + props->tie("radar/v-offset", SGRawValueFunctions(FGAIBase::_getV_offset)); + props->tie("radar/x-shift", SGRawValueFunctions(FGAIBase::_getX_shift)); + props->tie("radar/y-shift", SGRawValueFunctions(FGAIBase::_getY_shift)); + props->tie("radar/rotation", SGRawValueFunctions(FGAIBase::_getRotation)); props->tie("controls/lighting/nav-lights", SGRawValueFunctions(FGAIBase::_isNight)); @@ -117,7 +131,8 @@ void FGAIBase::bind() { } void FGAIBase::unbind() { - props->untie("velocities/airspeed-kt"); + props->untie("id"); + props->untie("velocities/true-airspeed-kt"); props->untie("velocities/vertical-speed-fps"); props->untie("position/altitude-ft"); @@ -126,7 +141,17 @@ void FGAIBase::unbind() { props->untie("orientation/pitch-deg"); props->untie("orientation/roll-deg"); - props->untie("orientation/heading-deg"); + props->untie("orientation/true-heading-deg"); + + props->untie("radar/bearing-deg"); + props->untie("radar/elevation-deg"); + props->untie("radar/range-nm"); +// props->untie("radar/rdot-kts"); + props->untie("radar/h-offset"); + props->untie("radar/v-offset"); + props->untie("radar/x-shift"); + props->untie("radar/y-shift"); + props->untie("radar/rotation"); props->untie("controls/controls/lighting/nav-lights"); } diff --git a/src/AIModel/AIBase.hxx b/src/AIModel/AIBase.hxx index 568469542..63e0128fe 100644 --- a/src/AIModel/AIBase.hxx +++ b/src/AIModel/AIBase.hxx @@ -30,6 +30,8 @@ SG_USING_STD(string); +class FGAIManager; + class FGAIBase { public: @@ -51,21 +53,26 @@ public: void setLongitude( double longitude ); void setBank( double bank ); + void setID( int ID ); + int getID(); void setDie( bool die ); bool getDie(); protected: SGPropertyNode *props; + FGAIManager* manager; + // these describe the model's actual state Point3D pos; // WGS84 lat & lon in degrees, elev above sea-level in meters double hdg; // True heading in degrees double roll; // degrees, left is negative double pitch; // degrees, nose-down is negative double speed; // knots true airspeed double altitude; // meters above sea level - double vs; // vertical speed, feet per minute + double vs; // vertical speed, feet per minute + // these describe the model's desired state double tgt_heading; // target heading, degrees true double tgt_altitude; // target altitude, *feet* above sea level double tgt_speed; // target speed, KTAS @@ -74,10 +81,22 @@ protected: double tgt_yaw; double tgt_vs; + // these describe radar information for the user + double bearing; // true bearing from user to this model + double elevation; // elevation in degrees from user to this model + double range; // range from user to this model, nm + double rdot; // range rate, in knots + double horiz_offset; // look left/right from user to me, deg + double vert_offset; // look up/down from user to me, deg + double x_shift; // value used by radar display instrument + double y_shift; // value used by radar display instrument + double rotation; // value used by radar display instrument + string model_path; //Path to the 3D model SGModelPlacement aip; bool delete_me; + int id; void Transform(); @@ -98,6 +117,16 @@ public: static double _getLongitude(); static double _getLatitude (); + static double _getBearing(); + static double _getElevation(); + static double _getRange(); + static double _getRdot(); + static double _getH_offset(); + static double _getV_offset(); + static double _getX_shift(); + static double _getY_shift(); + static double _getRotation(); + static bool _isNight(); }; @@ -143,6 +172,16 @@ inline void FGAIBase::_setLatitude ( double latitude ) { inline double FGAIBase::_getLongitude() { return _self->pos.lon(); } inline double FGAIBase::_getLatitude () { return _self->pos.lat(); } +inline double FGAIBase::_getBearing() { return _self->bearing; } +inline double FGAIBase::_getElevation() { return _self->elevation; } +inline double FGAIBase::_getRange() { return _self->range; } +inline double FGAIBase::_getRdot() { return _self->rdot; } +inline double FGAIBase::_getH_offset() { return _self->horiz_offset; } +inline double FGAIBase::_getV_offset() { return _self->vert_offset; } +inline double FGAIBase::_getX_shift() { return _self->x_shift; } +inline double FGAIBase::_getY_shift() { return _self->y_shift; } +inline double FGAIBase::_getRotation() { return _self->rotation; } + inline double FGAIBase::_getVS_fps() { return _self->vs*60.0; } inline void FGAIBase::_setVS_fps( double _vs ) { _self->vs = _vs/60.0; } @@ -157,5 +196,8 @@ inline bool FGAIBase::_isNight() { return (fgGetFloat("/sim/time/sun-angle-rad") > 1.57); } +inline void FGAIBase::setID( int ID ) { id = ID; } +inline int FGAIBase::getID() { return id; } + #endif // _FG_AIBASE_HXX diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx index 52a1c0fd1..b3d3060da 100644 --- a/src/AIModel/AIManager.cxx +++ b/src/AIModel/AIManager.cxx @@ -34,72 +34,61 @@ SG_USING_STD(list); FGAIManager::FGAIManager() { initDone = false; + numObjects = 0; + dt_count = 9; } FGAIManager::~FGAIManager() { + ai_list_itr = ai_list.begin(); + while(ai_list_itr != ai_list.end()) { + delete (*ai_list_itr); + ++ai_list_itr; + } ai_list.clear(); + ids.clear(); } -void FGAIManager::init() { - SGPropertyNode * node = fgGetNode("sim/ai", true); - for (int i = 0; i < node->nChildren(); i++) { - const SGPropertyNode * entry = node->getChild(i); +void FGAIManager::init() { + int rval; + root = fgGetNode("sim/ai", true); + + for (int i = 0; i < root->nChildren(); i++) { + const SGPropertyNode * entry = root->getChild(i); if (!strcmp(entry->getName(), "entry")) { if (!strcmp(entry->getStringValue("type", ""), "aircraft")) { - FGAIAircraft* ai_plane = new FGAIAircraft; - ai_list.push_back(ai_plane); - string model_class = entry->getStringValue("class", ""); - if (model_class == "light") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]); - - } else if (model_class == "ww2_fighter") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]); - - } else if (model_class == "jet_transport") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); - - } else if (model_class == "jet_fighter") { - ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]); - } - - ai_plane->setHeading(entry->getDoubleValue("heading")); - ai_plane->setSpeed(entry->getDoubleValue("speed-KTAS")); - ai_plane->setPath(entry->getStringValue("path")); - ai_plane->setAltitude(entry->getDoubleValue("altitude-ft")); - ai_plane->setLongitude(entry->getDoubleValue("longitude")); - ai_plane->setLatitude(entry->getDoubleValue("latitude")); - ai_plane->setBank(entry->getDoubleValue("bank")); - ai_plane->init(); - ai_plane->bind(); + rval = createAircraft( entry->getStringValue("class", ""), + entry->getStringValue("path"), + entry->getDoubleValue("latitude"), + entry->getDoubleValue("longitude"), + entry->getDoubleValue("altitude-ft"), + entry->getDoubleValue("heading"), + entry->getDoubleValue("speed-KTAS"), + 0.0, + entry->getDoubleValue("bank") ); } else if (!strcmp(entry->getStringValue("type", ""), "ship")) { - FGAIShip* ai_ship = new FGAIShip; - ai_list.push_back(ai_ship); - ai_ship->setHeading(entry->getDoubleValue("heading")); - ai_ship->setSpeed(entry->getDoubleValue("speed-KTAS")); - ai_ship->setPath(entry->getStringValue("path")); - ai_ship->setAltitude(entry->getDoubleValue("altitude-ft")); - ai_ship->setLongitude(entry->getDoubleValue("longitude")); - ai_ship->setLatitude(entry->getDoubleValue("latitude")); - ai_ship->setBank(entry->getDoubleValue("rudder")); - ai_ship->init(); - ai_ship->bind(); + + rval = createShip( entry->getStringValue("path"), + entry->getDoubleValue("latitude"), + entry->getDoubleValue("longitude"), + entry->getDoubleValue("altitude-ft"), + entry->getDoubleValue("heading"), + entry->getDoubleValue("speed-KTAS"), + entry->getDoubleValue("rudder") ); } else if (!strcmp(entry->getStringValue("type", ""), "ballistic")) { - FGAIBallistic* ai_ballistic = new FGAIBallistic; - ai_list.push_back(ai_ballistic); - ai_ballistic->setAzimuth(entry->getDoubleValue("azimuth")); - ai_ballistic->setElevation(entry->getDoubleValue("elevation")); - ai_ballistic->setSpeed(entry->getDoubleValue("speed-fps")); - ai_ballistic->setPath(entry->getStringValue("path")); - ai_ballistic->setAltitude(entry->getDoubleValue("altitude-ft")); - ai_ballistic->setLongitude(entry->getDoubleValue("longitude")); - ai_ballistic->setLatitude(entry->getDoubleValue("latitude")); - ai_ballistic->init(); - ai_ballistic->bind(); + + rval = createBallistic( entry->getStringValue("path"), + entry->getDoubleValue("latitude"), + entry->getDoubleValue("longitude"), + entry->getDoubleValue("altitude-ft"), + entry->getDoubleValue("azimuth"), + entry->getDoubleValue("elevation"), + entry->getDoubleValue("speed") ); + } } } @@ -109,33 +98,166 @@ void FGAIManager::init() { void FGAIManager::bind() { + root = globals->get_props()->getNode("ai/models", true); + root->tie("count", SGRawValuePointer(&numObjects)); } void FGAIManager::unbind() { - ai_list_itr = ai_list.begin(); - while(ai_list_itr != ai_list.end()) { - (*ai_list_itr)->unbind(); - ++ai_list_itr; - } + root->untie("count"); } void FGAIManager::update(double dt) { -#if 0 - if(!initDone) { - init(); - SG_LOG(SG_ATC, SG_WARN, "Warning - AIManager::update(...) called before AIManager::init()"); - } -#endif ai_list_itr = ai_list.begin(); while(ai_list_itr != ai_list.end()) { if ((*ai_list_itr)->getDie()) { - ai_list.erase(ai_list_itr, ai_list_itr); + freeID((*ai_list_itr)->getID()); + delete (*ai_list_itr); + ai_list.erase(ai_list_itr); + --ai_list_itr; + --numObjects; } else { + fetchUserState(); (*ai_list_itr)->update(dt); } ++ai_list_itr; } } + + +// This function returns the next available ID +int FGAIManager::assignID() { + int maxint = 30000; + int x; + bool used; + for (x=0; xsetID( assignID() ); + ++numObjects; + if (model_class == "light") { + ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::LIGHT]); + } else if (model_class == "ww2_fighter") { + ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::WW2_FIGHTER]); + } else if (model_class == "jet_transport") { + ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]); + } else if (model_class == "jet_fighter") { + ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_FIGHTER]); + } + ai_plane->setHeading(heading); + ai_plane->setSpeed(speed); + ai_plane->setPath(path.c_str()); + ai_plane->setAltitude(altitude); + ai_plane->setLongitude(longitude); + ai_plane->setLatitude(latitude); + ai_plane->setBank(roll); + ai_plane->init(); + ai_plane->bind(); + return ai_plane->getID(); +} + + +int FGAIManager::createShip( string path, double latitude, double longitude, + double altitude, double heading, double speed, + double rudder ) { + + FGAIShip* ai_ship = new FGAIShip(this); + ai_list.push_back(ai_ship); + ai_ship->setID( assignID() ); + ++numObjects; + ai_ship->setHeading(heading); + ai_ship->setSpeed(speed); + ai_ship->setPath(path.c_str()); + ai_ship->setAltitude(altitude); + ai_ship->setLongitude(longitude); + ai_ship->setLatitude(latitude); + ai_ship->setBank(rudder); + ai_ship->init(); + ai_ship->bind(); + return ai_ship->getID(); +} + + +int FGAIManager::createBallistic( string path, double latitude, double longitude, + double altitude, double azimuth, double elevation, + double speed ) { + + FGAIBallistic* ai_ballistic = new FGAIBallistic(this); + ai_list.push_back(ai_ballistic); + ai_ballistic->setID( assignID() ); + ++numObjects; + ai_ballistic->setAzimuth(azimuth); + ai_ballistic->setElevation(elevation); + ai_ballistic->setSpeed(speed); + ai_ballistic->setPath(path.c_str()); + ai_ballistic->setAltitude(altitude); + ai_ballistic->setLongitude(longitude); + ai_ballistic->setLatitude(latitude); + ai_ballistic->init(); + ai_ballistic->bind(); + return ai_ballistic->getID(); +} + +void FGAIManager::destroyObject( int ID ) { + ai_list_itr = ai_list.begin(); + while(ai_list_itr != ai_list.end()) { + if ((*ai_list_itr)->getID() == ID) { + freeID( ID ); + delete (*ai_list_itr); + ai_list.erase(ai_list_itr); + --ai_list_itr; + --numObjects; + return; + } + ++ai_list_itr; + } +} + +// fetch the user's state every 10 sim cycles +void FGAIManager::fetchUserState( void ) { + ++dt_count; + if (dt_count == 10) { + user_latitude = fgGetDouble("/position/latitude-deg"); + user_longitude = fgGetDouble("/position/longitude-deg"); + user_altitude = fgGetDouble("/position/altitude-ft"); + user_heading = fgGetDouble("/orientation/heading-deg"); + user_pitch = fgGetDouble("/orientation/pitch-deg"); + user_yaw = fgGetDouble("/orientation/side-slip-deg"); + user_speed = fgGetDouble("/velocities/uBody-fps") * 0.592484; + dt_count = 0; + } +} diff --git a/src/AIModel/AIManager.hxx b/src/AIModel/AIManager.hxx index 32098fcd7..9b668f4cc 100644 --- a/src/AIModel/AIManager.hxx +++ b/src/AIModel/AIManager.hxx @@ -47,6 +47,11 @@ private: ai_list_type ai_list; ai_list_iterator ai_list_itr; + // array of already-assigned ID's + typedef vector id_vector_type; + id_vector_type ids; + id_vector_type::iterator id_itr; + public: enum object_type { otAircraft, otShip, otBallistic, otRocket }; @@ -59,10 +64,61 @@ public: void unbind(); void update(double dt); + int assignID(); + void freeID(int ID); + + int createAircraft( string model_class, // see FGAIAircraft.hxx for possible classes + string path, // path to exterior model + double latitude, // in degrees -90 to 90 + double longitude, // in degrees -180 to 180 + double altitude, // in feet + double heading, // true heading in degrees + double speed, // in knots true airspeed (KTAS) + double pitch = 0, // in degrees + double roll = 0 ); // in degrees + + int createShip( string path, // path to exterior model + double latitude, // in degrees -90 to 90 + double longitude, // in degrees -180 to 180 + double altitude, // in feet (ex. for a lake!) + double heading, // true heading in degrees + double speed, // in knots true + double rudder ); // in degrees (between 0 and 5 works best) + + + int createBallistic( string path, // path to exterior model + double latitude, // in degrees -90 to 90 + double longitude, // in degrees -180 to 180 + double altitude, // in feet + double azimuth, // in degrees (same as heading) + double elevation, // in degrees (same as pitch) + double speed ); // in feet per second + + void destroyObject( int ID ); + + inline double get_user_latitude() { return user_latitude; } + inline double get_user_longitude() { return user_longitude; } + inline double get_user_altitude() { return user_altitude; } + inline double get_user_heading() { return user_heading; } + inline double get_user_pitch() { return user_pitch; } + inline double get_user_yaw() { return user_yaw; } + inline double get_user_speed() {return user_speed; } private: bool initDone; + int numObjects; + SGPropertyNode* root; + + double user_latitude; + double user_longitude; + double user_altitude; + double user_heading; + double user_pitch; + double user_yaw; + double user_speed; + int dt_count; + void fetchUserState( void ); }; diff --git a/src/AIModel/AIShip.cxx b/src/AIModel/AIShip.cxx index bd9ebb09f..d9fc379fe 100644 --- a/src/AIModel/AIShip.cxx +++ b/src/AIModel/AIShip.cxx @@ -27,7 +27,8 @@ #include "AIShip.hxx" -FGAIShip::FGAIShip() { +FGAIShip::FGAIShip(FGAIManager* mgr) { + manager = mgr; hdg_lock = false; rudder = 0.0; _type_str = "ship"; diff --git a/src/AIModel/AIShip.hxx b/src/AIModel/AIShip.hxx index d4d29f022..1fc583ca0 100644 --- a/src/AIModel/AIShip.hxx +++ b/src/AIModel/AIShip.hxx @@ -21,15 +21,14 @@ #ifndef _FG_AISHIP_HXX #define _FG_AISHIP_HXX -#include "AIManager.hxx" #include "AIBase.hxx" - +class FGAIManager; class FGAIShip : public FGAIBase { public: - FGAIShip(); + FGAIShip(FGAIManager* mgr); ~FGAIShip(); bool init();