39 static const double TIME_TO_DOCK = 30;
44 :
ShipAI(s), brakes(0), drop_state(0), jink_time(0), evading(false),
45 decoy_missile(0), missile_time(0), terrain_warning(false), inbound(0),
46 rtb_code(0), form_up(false), over_threshold(false), time_to_dock(0),
66 static double frame_time = 0;
106 double nr = sr + s*(lr-sr);
107 double np = sp + s*(lp-sp);
108 double nw = sw + s*(lw-sw)*0.5;
112 landing_cam.
Clone(work);
285 action = orders->
Action();
287 if (
navpt && !action) {
326 if (self_rgn && !rtb_rgn) {
330 if (self_rgn && rtb_rgn && self_rgn != rtb_rgn) {
359 bool use_farcaster = !qdrive ||
369 if (dest && dest->
GetRegion() == rtb_rgn) {
389 double r3 = (npt - apt).length();
391 if (r1+r2 < 1.2*r3) {
446 if (self_rgn && !nav_rgn) {
451 if (self_rgn && nav_rgn && self_rgn != nav_rgn) {
498 if (
target && wep_design) {
543 if (lead && lead !=
ship) {
585 for (
int i = 0; i < elem->
NumShips(); i++) {
598 ::Print(
"WARNING: FighterAI NAVPT RTB, but no controller or hangar found for ship '%s'\n",
ship->
Name());
607 for (
int i = 0; i < elem->
NumShips(); i++) {
622 ::Print(
"WARNING: FighterAI NAVPT DOCK, but no dock target found for ship '%s'\n",
ship->
Name());
687 double deflection = vrt.
y;
690 bool station_keeping =
distance < 0;
691 bool inverted = cam->
vup().
y < -0.5;
721 station_keeping =
true;
729 double desired_bank = -
PI/4;
730 double current_bank = asin(deflection);
731 double theta = desired_bank - current_bank;
734 double coord_pitch = compass_pitch - 0.2 * fabs(current_bank);
755 else if (fabs(deflection) > 0.1 || inverted) {
756 double theta = asin(deflection/vrt.
length()) * 0.5;
765 double pitch_deflection = heading.
y;
767 if (fabs(pitch_deflection) > 0.05) {
768 double rho = asin(pitch_deflection) * 3;
784 double desired = 1000;
786 bool station_keeping =
distance < 0;
787 bool augmenter =
false;
790 if (
inbound || station_keeping)
801 else if (station_keeping) {
818 if (ship_speed < 200)
825 desired = 250 + carrier_speed;
828 desired = 750 + carrier_speed;
834 desired = 75 + carrier_speed;
843 if (ship_speed > desired+5)
850 else if (ship_speed < 0.85 * desired) {
853 if (ship_speed < 0 && ship->GetFuelLevel() > 10)
857 else if (ship_speed < desired-5) {
875 if (ship_speed > desired+5)
882 else if (ship_speed < 0.85 * desired) {
885 if (ship_speed < 0 && ship->GetFuelLevel() > 10)
889 else if (ship_speed < desired-5) {
905 if (!elem || !formation) {
912 if (ship_speed > desired+5) {
917 else if (ship_speed < 0.85 * desired) {
920 if (ship_speed < 0 && ship->GetFuelLevel() > 10)
924 else if (ship_speed < desired-5)
954 if (
objective.
z > 10e3 && ship_speed < desired && ship->GetFuelLevel() > 25)
973 double sv = ship_speed;
977 if (dv > 0) dt = dv * 1e-5 * frame_time;
978 else if (dv < 0) dt = dv * 1e-2 * frame_time;
1010 if (
objective.
z > 20e3 && ship_speed < desired && ship->GetFuelLevel() > 35)
1031 if (ship_speed > speed) {
1035 else if (ship_speed < speed - 10) {
1057 else if (desired > 0) {
1058 if (ship_speed > desired) {
1063 else if (ship_speed < 0.85 * desired) {
1070 else if (ship_speed < desired - 10) {
1100 else if (ship_speed > 1 &&
brakes > 0)
1195 if (distance < 10 * self->Radius()) {
1217 if (distance < 20 * self->Radius())
1289 double basis =
self->Radius() + tgt->
Radius();
1338 else if (gap < 250) {
1372 if (self_rgn != lead_rgn) {
1374 bool use_farcaster = !qdrive ||
1378 if (use_farcaster) {
1392 if (distance < ship->Radius() * 10 && lead->
Velocity().
length() < 50) {
1406 s.
pitch =
el[0] - seek_damp * (
el[1] +
el[2] * 0.5);
1435 if (point.
z > 0.0f) {
1439 if (point.
x < 0)
az[0] = -
az[0];
1440 if (point.
y > 0)
el[0] = -
el[0];
1443 s.
pitch =
el[0] - seek_damp * (
el[1] +
el[2] * 0.5);
1454 if (point.
y > 5e3) {
1459 else if (point.
y < -5e3) {
1465 if (point.
x > 0) s.
yaw = 1.0f;
1473 if (point.
x > 0) s.
yaw = 1.0f;
1519 return Seek(evade_p);
1524 double threat_range = 20e3;
1533 if (threat_dist <= threat_range) {
1540 beam_line *= threat_range;
1545 return Seek(evade_p);
1551 if (
target == threat_ship && threat_dist < threat_range / 4) {
1570 rand() - 16384) * 15e3;
1576 return Seek(evade_p);
1600 return Seek(evade_p);
1618 else if (
target && threat_dist < threat_range / 2) {
1646 DWORD jink_rate = 400 + 200 * (3-
ai_level);
1652 rand() - 16384) * 2000;
1685 if (
objective.
z < 0 || distance < 4 * self->Radius())
1690 double gun_basket = cross_section * 2;
1696 bool use_primary =
true;
1707 dsgn_primary = primary->
Design();
1710 gun_basket = cross_section * 4;
1716 use_primary =
false;
1730 dx < gun_basket && dy < gun_basket &&
1741 dsgn_secondary = secondary->
Design();
1743 if (missile_time <= 0 && secondary->Ammo() && !secondary->
IsBlockedFriendly()) {
1750 double s_range = 0.5 + 0.2 * factor;
1751 double s_basket = 0.3 + 0.2 * factor;
1752 double extra_time = 10 * factor * factor + 5;
1764 extra_time = 0.5 * factor + 0.5;
1770 if (tgt_range < secondary->Design()->max_range * s_range) {
1771 double dx = fabs(tgt.
x);
1772 double dy = fabs(tgt.
y);
1774 if (dx < s_basket && dy < s_basket && tgt.z > 0) {
1804 double perimeter = 15e3;
1815 if (weapon->
Ammo() &&
1820 if (range > perimeter)