Author Topic: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes  (Read 11479 times)

0 Members and 1 Guest are viewing this topic.

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
[Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
EDIT: Fixed bug with the way that waypoints are marked done (for both the log and the directives) and when the ai goals are cleared.  This post has been updated with both a new build and corrected patch.
EDIT2: Fixed bug with autopilot linking.
EDIT July 11th, 2010: Added a couple of items to the autopilot table.

In fixing Mantis 1888 I have run into few things that cannot be fixed without affecting how the AI works in a very limited fashion.  Because changes to the AI result in subtle bugs I am putting this build out the community to take a look at.

The changes in this patch include (not including the primary fix for 1888 which is already in trunk and 3.6.12):
  • Collapsed the code for the AI goals AIM_FLY_TO_SHIP and AIM_WAYPOINTS into one sub-function (removing the redundant code).
  • Autopilot can handle multiple wings of fighters as *originally* advertised.  The player's wing will always be the leader wing.
  • The cinematic mode for autopilot (ie. Wing Commander or Twist of Fate (a FSPort mod)) will always point the camera at the player regardless of his position in the wing.
  • Two new failure modes for the Autopilot:
    • $Support Present: - Used to indicate that the support ship is present but the code does not have a specific reason why it cannot be dismissed.  Normally the autopilot code will have the support ship depart automatically, when it it not rearm/repairing.
    • $Support Working: - Used to indicate that the support ship is present but has active orders to rearm/repair one or more ships.  This order can be circumvented by the player ordering the support ship to depart.
  • Obviously the above requires two new entries in the autopilot.tbl (which have been added to the autopilot.tbl built into the engine.
  • Setting nav-status-carry on an object that can never move (ie. a cargo container) now causes a warning to appear when the autopliot starts up.  The warning code also fixes the issue that results from the condition by making sure that the speed cap is no smaller than 1.
  • Three new optional autopilot.tbl settings:
    • $Interrupt autopilot if enemy within distance: NUMBER - defaults to 5000 meters.  A number less than zero disables the enemy check all together.   Is the minimum distance that any enemy has to be from the player for the autopilot to engage and the minimum distance that any enemy has to be from the Flight leader during the autopilot (that is, you will drop out of autopilot if your AP path takes you closer than NUMBER meters to any enemy).
    • $Interrupt autopilot if asteroid within distance: NUMBER - defaults to 1000 meters. A number less than zero disables the enemy check all together.  Is the minimum distance that an asteroid has to be from the player for the autopilot to engage and is the minimum distance that an asteroid has to be from the Flight leader during through the autopilot (that is, you will drop out of autopilot if your AP path takes you closer than NUMBER meters to an asteroid).
    • $Lock weapons during autopilot: BOOLEAN - defaults to NO. Disables all weapons of all ships involved in the cinematic autopilot sequence, does not affect the time acceleration autopilot.

Debug and release windows build (no pdbs). MD5 = 014AE02F8619704885B3D2ACC30654A5

Code: (The Patch (should work against both 3.6.12 and trunk)) [Select]
Index: code/ai/ai.h
===================================================================
--- code/ai/ai.h (revision 6288)
+++ code/ai/ai.h (working copy)
@@ -639,6 +639,7 @@
 extern void ai_rearm_repair( object *objp, int docker_index, object *goal_objp, int dockee_index );
 extern void ai_add_rearm_goal( object *requester_objp, object *support_objp );
 extern void create_model_path(object *pl_objp, object *mobjp, int path_num, int subsys_path=0);
+extern int ai_find_goal_index( ai_goal* aigp, int mode, int submode = -1, int priority = -1 );
 
 // Goober5000
 extern void ai_do_safety(object *objp);
Index: code/ai/aicode.cpp
===================================================================
--- code/ai/aicode.cpp (revision 6288)
+++ code/ai/aicode.cpp (working copy)
@@ -4177,13 +4177,13 @@
 
 
 // --------------------------------------------------------------------------
-// make Pl_objp fly tword a ship
-//  Goal created by Kazan
-//  code adapted from waypoints
-void ai_fly_to_ship()
+// make Pl_objp fly to its target's position
+// optionally returns true if Pl_objp (pl_done_p) has reached the target position (can be NULL)
+// optionally returns true if Pl_objp's (pl_treat_as_ship_p) fly to order was issued to him directly,
+// or if the order was issued to his wing (returns false) (can be NULL, and result is only
+// valid if Pl_done_p was not NULL and was set true by function.
+void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl_treat_as_ship_p=NULL)
 {
-
- vec3d *target_pos;
  float dot, dist_to_goal, speed;
  ship *shipp = &Ships[Pl_objp->instance];
  ship_info *sip = &Ship_info[shipp->ship_info_index];
@@ -4193,30 +4193,25 @@
  float prev_dot_to_goal;
  vec3d temp_vec;
  vec3d *slop_vec;
- int target_object=-1;
+ int j;
 
- aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
+ Assert( target_pos != NULL );
 
- int i,j ;
- for (i = 0; i < MAX_AI_GOALS && target_object == -1; i++)
- {
- if (aip->goals[i].ai_mode == AIM_FLY_TO_SHIP || aip->goals[i].ai_mode == AI_GOAL_FLY_TO_SHIP)
- {
- for (j = 0; j < MAX_SHIPS; j++)
- {
- if (Ships[j].objnum != -1 && !stricmp(aip->goals[i].ship_name, Ships[j].ship_name))
- {
- target_object = Ships[j].objnum;
- break;
- }
- }
- }
+ if ( pl_done_p != NULL ) {
+ // initialize this to false now incase we leave early so that that
+ // the caller of this function doesn't get any funny ideas about
+ // the status of the waypoint
+ *pl_done_p = false;
  }
-
 
+ aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
 
+ /* I shouldn't be flying to position for what ever called me any more.
+ Set mode to none so that default dynamic behaviour gets started up again. */
+ if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) ) {
+ aip->mode = AIM_NONE;
+ }
 
- target_pos = &Objects[target_object].pos;
  speed = Pl_objp->phys_info.speed;
 
  dist_to_goal = vm_vec_dist_quick(&Pl_objp->pos, target_pos);
@@ -4250,15 +4245,13 @@
  // If a wing leader, take turns more slowly, based on size of wing.
  int scale;
 
- if (Ai_info[Ships[Pl_objp->instance].ai_index].wing >= 0) {
- scale = Wings[Ai_info[Ships[Pl_objp->instance].ai_index].wing].current_count;
+ if (aip->wing >= 0) {
+ scale = Wings[aip->wing].current_count;
  scale = (int) ((scale+1)/2);
  } else {
  scale = 1;
  }
 
-
-
  // ----------------------------------------------
  // if in autopilot mode make sure to not collide
  // and "keep reasonable distance"
@@ -4269,7 +4262,9 @@
 
  bool carry_flag = ((shipp->flags2 & SF2_NAVPOINT_CARRY) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags & WF_NAV_CARRY)));
 
- if (AutoPilotEngaged && timestamp_elapsed(LockAPConv) && carry_flag
+ if (AutoPilotEngaged
+ && timestamp_elapsed(LockAPConv)
+ && carry_flag
  && ((The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) || (Pl_objp != Autopilot_flight_leader)) )
  {
  Assertion( Autopilot_flight_leader != NULL, "When under autopliot there must be a flight leader", Autopilot_flight_leader );
@@ -4277,11 +4272,13 @@
  if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) {
  if (aip->wing != -1) {
  int wing_index = get_wing_index(Pl_objp, aip->wing);
+ object *wing_leader = get_wing_leader(aip->wing);
 
- if (Autopilot_flight_leader != Pl_objp) {
- // not leader.. get our position relative to leader
- get_absolute_wing_pos_autopilot(&goal_point, Autopilot_flight_leader, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
+ if (wing_leader != Pl_objp) {
+ // not wing leader.. get my position relative to wing leader
+ get_absolute_wing_pos_autopilot(&goal_point, wing_leader, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
  } else {
+ // Am wing leader.. get the wings position relative to the flight leader
  j = 1+int( (float)floor(double(autopilot_wings[aip->wing]-1)/2.0) );
 
  switch (autopilot_wings[aip->wing] % 2) {
@@ -4304,7 +4301,7 @@
  Pl_objp->pos = goal_point;
  }
 
- vm_vec_sub(&perp, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
+ vm_vec_sub(&perp, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
  vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
  } else {
  vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
@@ -4322,8 +4319,6 @@
  dot = vm_vec_dot_to_point(&nvel_vec, &Pl_objp->pos, target_pos);
  aip->prev_dot_to_goal = dot;
 
- // nprintf(("AI", "Wp #%i, dot = %6.3f, next dot = %6.3f, dist = %7.2f\n", wp_index, dot, dot_to_next, dist_to_goal));
-
  if (Pl_objp->phys_info.speed < 0.0f) {
  accelerate_ship(aip, 1.0f/32);
  } else if (prev_dot_to_goal > dot+0.01f) {
@@ -4385,13 +4380,11 @@
 
  r = find_nearest_point_on_line(&nearest_point, &Pl_objp->last_pos, &Pl_objp->pos, target_pos);
 
- if ( (vm_vec_dist_quick(&Pl_objp->pos, target_pos) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius) + vm_vec_dist_quick(&Pl_objp->pos, &Pl_objp->last_pos))) ||
- ((r >= 0.0f) && (r <= 1.0f)) && (vm_vec_dist_quick(&nearest_point, target_pos) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius)))) {
-
-
+ if ( (vm_vec_dist_quick(&Pl_objp->pos, target_pos) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius) + vm_vec_dist_quick(&Pl_objp->pos, &Pl_objp->last_pos)))
+ || (((r >= 0.0f) && (r <= 1.0f)) && (vm_vec_dist_quick(&nearest_point, target_pos) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius)))))
+ {
  int treat_as_ship;
 
- // when not repeating waypoints -- mark the goal as done and put and entry into the mission log
  // we must be careful when dealing with wings.  A ship in a wing might be completing
  // a waypoint for for the entire wing, or it might be completing a goal for itself.  If
  // for itself and in a wing, treat the completion as we would a ship
@@ -4399,15 +4392,6 @@
  if ( Ships[Pl_objp->instance].wingnum != -1 ) {
  int type;
 
- // I don't think that you can fly waypoints as dynamic goals!!!
- // -- This is legal, just stupid. -- Assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
-
- // Clean up from above Assert, just in case we ship without fixing it.  (Encountered by JimB on 2/9/98)
- if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) ) {
- aip->mode = AIM_NONE;
- Int3(); // Look at the ship, find out of it's supposed to be flying waypoints. -- MK.
- }
-
  type = aip->goals[aip->active_goal].type;
  if ( (type == AIG_TYPE_EVENT_WING) || (type == AIG_TYPE_PLAYER_WING) ) {
  treat_as_ship = 0;
@@ -4415,20 +4399,20 @@
  treat_as_ship = 1;
  }
  }
-
- // if the ship is not in a wing, remove the goal and continue on
- if ( treat_as_ship ) {
- ai_mission_goal_complete( aip ); // this call should reset the AI mode
- //mission_log_add_entry(LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, wpl->name, -1 );
+ // setup out parameters
+ if ( pl_done_p != NULL ) {
+ *pl_done_p = true;
+ if ( pl_treat_as_ship_p != NULL ) {
+ if ( treat_as_ship ) {
+ *pl_treat_as_ship_p = true;
+ } else {
+ *pl_treat_as_ship_p = false;
+ }
+ }
  } else {
- // this ship is in a wing.  We must mark the goal as being completed for all ships
- // in the wing.  We will also mark an entry in the log that the wing completed the goal
- // not the individual ship.
- ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
- //mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, wpl->name, -1 );
+ Assertion( pl_treat_as_ship_p != NULL,
+ "pl_done_p cannot be NULL while pl_treat_as_ship_p is not NULL" );
  }
- //wp_index = wpl->count-1;
-
  }
  }
 }
@@ -4438,18 +4422,8 @@
 void ai_waypoints()
 {
  int wp_index;
- vec3d *wp_cur, *wp_next;
- float dot, dist_to_goal, dist_to_next, speed, dot_to_next;
- ship *shipp = &Ships[Pl_objp->instance];
- ship_info *sip = &Ship_info[shipp->ship_info_index];
- waypoint_list *wpl;
  ai_info *aip;
- vec3d nvel_vec;
- float mag;
- float prev_dot_to_goal;
- vec3d temp_vec;
- vec3d *slop_vec;
- int j;
+ waypoint_list *wpl;
 
  aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
 
@@ -4463,234 +4437,113 @@
 
  wpl = &Waypoint_lists[aip->wp_list];
 
- Assert(wpl->count); // What? Is this zero? Probably wp_index never got initialized!
+ Assert(wpl->count > 0); // What? Is this zero? Probably wp_index never got initialized!
 
- wp_cur = &wpl->waypoints[wp_index];
- wp_next = &wpl->waypoints[(wp_index+1) % wpl->count];
- speed = Pl_objp->phys_info.speed;
+ bool done, treat_as_ship;
+ ai_fly_to_target_position(&(wpl->waypoints[wp_index]), &done, &treat_as_ship);
 
- dist_to_goal = vm_vec_dist_quick(&Pl_objp->pos, wp_cur);
- dist_to_next = vm_vec_dist_quick(&Pl_objp->pos, wp_next);
-
- // Can't use fvec, need to use velocity vector because we aren't necessarily
- // moving in the direction we're facing.
- // AL 23-3-98: Account for very small velocities by checking result of vm_vec_mag().
- // If we don't vm_vec_copy_normalize() will think it is normalizing a null vector.
-// if (IS_VEC_NULL(&Pl_objp->phys_info.vel)) {
- if ( vm_vec_mag_quick(&Pl_objp->phys_info.vel) < AICODE_SMALL_MAGNITUDE ) {
- mag = 0.0f;
- vm_vec_zero(&nvel_vec);
- } else {
- mag = vm_vec_copy_normalize(&nvel_vec, &Pl_objp->phys_info.vel);
- }
-
- // If moving not-very-slowly and sliding, then try to slide at goal, rather than
- // point at goal.
- slop_vec = NULL;
- if (mag < 1.0f) {
- nvel_vec = Pl_objp->orient.vec.fvec;
- } else if (mag > 5.0f) {
- float nv_dot;
- nv_dot = vm_vec_dot(&Pl_objp->orient.vec.fvec, &nvel_vec);
- if ((nv_dot > 0.5f) && (nv_dot < 0.97f)) {
- slop_vec = &temp_vec;
- vm_vec_sub(slop_vec, &nvel_vec, &Pl_objp->orient.vec.fvec);
+ if ( done ) {
+ aip->wp_index++; // go on to next waypoint in path
+ if ( (aip->wp_index >= wpl->count) ) {
+ // have reached the last waypoint.  Do I?
+ if ( ((aip->wp_flags & WPF_REPEAT) > 0) ) {
+ aip->wp_index = 0; // go back to the start.
+ } else {
+ aip->wp_index = (wpl->count - 1); // stay on the last waypoint
+ }
+ // Log a message that the wing or ship reached his waypoint and
+ // remove the goal from the AI goals of the ship pr wing, respectively.
+ // Wether or not we should treat this as a ship or a wing is determined by
+ // ai_fly_to_target_position when it marks the AI directive as complete
+ if ( treat_as_ship ) {
+ ai_mission_goal_complete( aip ); // this call should reset the AI mode
+ mission_log_add_entry( LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, wpl->name, -1 );
+ } else {
+ ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
+ mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, wpl->name, -1 );
+ }
  }
  }
+}
 
- // If a wing leader, take turns more slowly, based on size of wing.
- int scale;
+// --------------------------------------------------------------------------
+// make Pl_objp fly toward a ship
+void ai_fly_to_ship()
+{
+ ai_info *aip;
+ object* target_p = NULL;
 
- if (aip->wing >= 0) {
- scale = Wings[aip->wing].current_count;
- scale = (int) ((scale+1)/2);
- } else {
- scale = 1;
+ aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
+
+ if ( aip->mode != AIM_FLY_TO_SHIP ) {
+ Warning(LOCATION,
+ "ai_fly_to_ship called for '%s' when ai_info.mode not equal to AIM_FLY_TO_SHIP. Is actually '%d'",
+ Ships[Pl_objp->instance].ship_name,
+ aip->mode);
+ aip->mode = AIM_NONE;
+ return;
  }
+ if ( aip->active_goal < 0 || aip->active_goal >= MAX_AI_GOALS ) {
+ Warning(LOCATION,
+ "'%s' is trying to fly-to a ship without an active AI_GOAL\n\n"
+ "Active ai mode is '%d'",
+ Ships[Pl_objp->instance].ship_name,
+ aip->active_goal);
+ aip->mode = AIM_NONE;
+ return;
+ }
+ Assert( aip->goals[aip->active_goal].ship_name != NULL );
+ if ( strlen(aip->goals[aip->active_goal].ship_name) == 0 ) {
+ Warning(LOCATION,
+ "'%s' is trying to fly-to a ship without a name for the ship",
+ Ships[Pl_objp->instance].ship_name);
+ aip->mode = AIM_NONE;
+ ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
+ return;
+ }
 
- // ----------------------------------------------
- // if in autopilot mode make sure to not collide
- // and "keep reasonable distance"
- // this needs to be done for ALL SHIPS not just capships STOP CHANGING THIS
- // ----------------------------------------------
-
- vec3d perp, goal_point;
-
- bool carry_flag = ((shipp->flags2 & SF2_NAVPOINT_CARRY) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags & WF_NAV_CARRY)));
-
- if (AutoPilotEngaged && timestamp_elapsed(LockAPConv) && carry_flag
- && ((The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) || (Pl_objp != Autopilot_flight_leader)) )
+ for (int j = 0; j < MAX_SHIPS; j++)
  {
- // snap wings into formation them into formation
- if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS) {
- if (aip->wing != -1) {
- int wing_index = get_wing_index(Pl_objp, aip->wing);
-
- if (Autopilot_flight_leader != Pl_objp) {
- // not leader.. get our position relative to leader
- get_absolute_wing_pos_autopilot(&goal_point, Autopilot_flight_leader, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
- } else {
- j = 1+int( (float)floor(double(autopilot_wings[aip->wing]-1)/2.0) );
-
- switch (autopilot_wings[aip->wing] % 2) {
- case 1: // back-left
- vm_vec_copy_normalize(&perp, &Autopilot_flight_leader->orient.vec.rvec);
- vm_vec_scale(&perp, -166.0f*j); // 166m is supposedly the optimal range according to tolwyn
- vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
- break;
-
- default: //back-right
- case 0:
- vm_vec_copy_normalize(&perp, &Autopilot_flight_leader->orient.vec.rvec);
- vm_vec_scale(&perp, 166.0f*j);
- vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
- break;
- }
-
- }
-
- Pl_objp->pos = goal_point;
- }
-
- vm_vec_sub(&perp, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
- vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
- } else {
- vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
- ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
+ if (Ships[j].objnum != -1 && !stricmp(aip->goals[aip->active_goal].ship_name, Ships[j].ship_name))
+ {
+ target_p = &Objects[Ships[j].objnum];
+ break;
  }
- } else {
- if (dist_to_goal > 0.1f) {
- ai_turn_towards_vector(wp_cur, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
- }
  }
 
-
- // ----------------------------------------------
-
- prev_dot_to_goal = aip->prev_dot_to_goal;
- dot = vm_vec_dot_to_point(&nvel_vec, &Pl_objp->pos, wp_cur);
- dot_to_next = vm_vec_dot_to_point(&nvel_vec, &Pl_objp->pos, wp_next);
- aip->prev_dot_to_goal = dot;
-
- // If there is no next point on the path, don't care about dot to next.
- if (wp_index + 1 >= wpl->count) {
- dot_to_next = dot;
- }
-
- // nprintf(("AI", "Wp #%i, dot = %6.3f, next dot = %6.3f, dist = %7.2f\n", wp_index, dot, dot_to_next, dist_to_goal));
-
- if (Pl_objp->phys_info.speed < 0.0f) {
- accelerate_ship(aip, 1.0f/32);
- } else if (prev_dot_to_goal > dot+0.01f) {
- // We are further from pointing at our goal this frame than last frame, so slow down.
- set_accel_for_target_speed(Pl_objp, Pl_objp->phys_info.speed * 0.95f);
- } else if (dist_to_goal < 100.0f) {
- float slew_dot = vm_vec_dot(&Pl_objp->orient.vec.fvec, &nvel_vec);
- if (fl_abs(slew_dot) < 0.9f) {
- accelerate_ship(aip, 0.0f);
- } else if (dot < 0.88f + 0.1f*(100.0f - dist_to_goal)/100.0f) {
- accelerate_ship(aip, 0.0f);
- } else {
- accelerate_ship(aip, 0.5f * dot * dot);
+ if ( target_p == NULL ) {
+ #ifndef NDEBUG
+ for (int i = 0; i < MAX_AI_GOALS; i++)
+ {
+ if (aip->mode == AIM_FLY_TO_SHIP || aip->goals[i].ai_mode == AI_GOAL_FLY_TO_SHIP)
+ {
+ mprintf(("Ship '%s' told to fly to target ship '%s'",
+ Ships[Pl_objp->instance].ship_name,
+ aip->goals[i].ship_name));
+ }
  }
+ #endif
+ Warning(LOCATION, "Ship '%s' told to fly to a ship but none of the ships it was told to fly to exist.\n"
+ "See log before this message for list of ships set as fly-to tagets",
+ Ships[Pl_objp->instance].ship_name);
+ aip->mode = AIM_NONE;
+ ai_remove_ship_goal( aip, aip->active_goal ); // function sets aip->active_goal to NONE for me
+ return;
  } else {
- float dot1;
- if (dist_to_goal < 250.0f) {
- dot1 = dot*dot*dot; // Very important to be pointing towards goal when nearby.  Note, cubing preserves sign.
- } else {
- if (dot > 0.0f) {
- dot1 = dot*dot;
+ bool done, treat_as_ship;
+ ai_fly_to_target_position(&(target_p->pos), &done, &treat_as_ship);
+
+ if ( done ) {
+ // remove the goal from the AI goals of the ship pr wing, respectively.
+ // Wether or not we should treat this as a ship or a wing is determined by
+ // ai_fly_to_target when it marks the AI directive as complete
+ if ( treat_as_ship ) {
+ ai_mission_goal_complete( aip ); // this call should reset the AI mode
  } else {
- dot1 = dot;
+ ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
  }
  }
-
- if (dist_to_goal > 100.0f + Pl_objp->radius * 2) {
- if (dot < 0.2f) {
- dot1 = 0.2f;
- }
- }
-
- if (sip->flags & SIF_SMALL_SHIP) {
- set_accel_for_target_speed(Pl_objp, dot1 * dist_to_goal/5.0f);
- } else {
- set_accel_for_target_speed(Pl_objp, dot1 * dist_to_goal/10.0f);
- }
  }
-
- // Make sure not travelling too fast for someone to keep up.
- float max_allowed_speed = 9999.9f;
-
- if (shipp->wingnum != -1) {
- max_allowed_speed = 0.9f * get_wing_lowest_max_speed(Pl_objp);
- }
-
- // check if waypoint speed cap is set and adjust max speed
- if (aip->waypoint_speed_cap > 0) {
- max_allowed_speed = (float) aip->waypoint_speed_cap;
- }
-
- if (aip->prev_accel * shipp->current_max_speed > max_allowed_speed) {
- accelerate_ship(aip, max_allowed_speed / shipp->current_max_speed);
- }
-
- if ( (dist_to_goal < MIN_DIST_TO_WAYPOINT_GOAL) || (vm_vec_dist_quick(&Pl_objp->last_pos, &Pl_objp->pos) > 0.1f) ) {
- vec3d nearest_point;
- float r;
-
- r = find_nearest_point_on_line(&nearest_point, &Pl_objp->last_pos, &Pl_objp->pos, wp_cur);
-
- if ( (vm_vec_dist_quick(&Pl_objp->pos, wp_cur) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius) + vm_vec_dist_quick(&Pl_objp->pos, &Pl_objp->last_pos))) ||
- ((r >= 0.0f) && (r <= 1.0f)) && (vm_vec_dist_quick(&nearest_point, wp_cur) < (MIN_DIST_TO_WAYPOINT_GOAL + fl_sqrt(Pl_objp->radius)))) {
- wp_index++;
- if (wp_index >= wpl->count)
- if (aip->wp_flags & WPF_REPEAT) {
- wp_index = 0;
- } else {
- int treat_as_ship;
-
- // when not repeating waypoints -- mark the goal as done and put and entry into the mission log
- // we must be careful when dealing with wings.  A ship in a wing might be completing
- // a waypoint for for the entire wing, or it might be completing a goal for itself.  If
- // for itself and in a wing, treat the completion as we would a ship
- treat_as_ship = 1;
- if ( Ships[Pl_objp->instance].wingnum != -1 ) {
- int type;
-
- // I don't think that you can fly waypoints as dynamic goals!!!
- // -- This is legal, just stupid. -- Assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
-
- // Clean up from above Assert, just in case we ship without fixing it.  (Encountered by JimB on 2/9/98)
- if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) ) {
- aip->mode = AIM_NONE;
- //Int3(); // Look at the ship, find out of it's supposed to be flying waypoints. -- MK.
- }
-
- type = aip->goals[aip->active_goal].type;
- if ( (type == AIG_TYPE_EVENT_WING) || (type == AIG_TYPE_PLAYER_WING) ) {
- treat_as_ship = 0;
- } else {
- treat_as_ship = 1;
- }
- }
-
- // if the ship is not in a wing, remove the goal and continue on
- if ( treat_as_ship ) {
- ai_mission_goal_complete( aip ); // this call should reset the AI mode
- mission_log_add_entry(LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, wpl->name, -1 );
- } else {
- // this ship is in a wing.  We must mark the goal as being completed for all ships
- // in the wing.  We will also mark an entry in the log that the wing completed the goal
- // not the individual ship.
- ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
- mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, wpl->name, -1 );
- }
- //wp_index = wpl->count-1;
- }
-
- aip->wp_index = wp_index;
- }
- }
 }
 
 // Make Pl_objp avoid En_objp
Index: code/ai/aigoals.cpp
===================================================================
--- code/ai/aigoals.cpp (revision 6288)
+++ code/ai/aigoals.cpp (working copy)
@@ -990,7 +990,7 @@
  * Pass -1 in priority to ignore priority when searching
  * Returns -1 if not found, or [0, MAX_AI_GOALS)
  */
-int ai_find_goal_index( ai_goal* aigp, int mode, int submode = -1, int priority = -1 )
+int ai_find_goal_index( ai_goal* aigp, int mode, int submode, int priority )
 {
  Assert( aigp != NULL );
  for ( int i = 0; i < MAX_AI_GOALS; i++ )
Index: code/ai/aigoals.h
===================================================================
--- code/ai/aigoals.h (revision 6288)
+++ code/ai/aigoals.h (working copy)
@@ -26,35 +26,35 @@
 // Fred.  If the goal you add doesn't have a target (such as chase_any), then you don't have
 // to worry about doing this.  Also add it to list in Fred\Management.cpp, and let Hoffoss know!
 // WMC - Oh and add them to Ai_goal_names plz. TY! :)
-#define AI_GOAL_CHASE (1<<1)
-#define AI_GOAL_DOCK (1<<2) // used for undocking as well
-#define AI_GOAL_WAYPOINTS (1<<3)
-#define AI_GOAL_WAYPOINTS_ONCE (1<<4)
-#define AI_GOAL_WARP (1<<5)
-#define AI_GOAL_DESTROY_SUBSYSTEM (1<<6)
-#define AI_GOAL_FORM_ON_WING (1<<7)
-#define AI_GOAL_UNDOCK (1<<8)
-#define AI_GOAL_CHASE_WING (1<<9)
-#define AI_GOAL_GUARD (1<<10)
-#define AI_GOAL_DISABLE_SHIP (1<<11)
-#define AI_GOAL_DISARM_SHIP (1<<12)
-#define AI_GOAL_CHASE_ANY (1<<13)
-#define AI_GOAL_IGNORE (1<<14)
-#define AI_GOAL_GUARD_WING (1<<15)
-#define AI_GOAL_EVADE_SHIP (1<<16)
+#define AI_GOAL_CHASE (1<<1) // 0x00000002
+#define AI_GOAL_DOCK (1<<2) // 0x00000004 // used for undocking as well
+#define AI_GOAL_WAYPOINTS (1<<3) // 0x00000008
+#define AI_GOAL_WAYPOINTS_ONCE (1<<4) // 0x00000010
+#define AI_GOAL_WARP (1<<5) // 0x00000020
+#define AI_GOAL_DESTROY_SUBSYSTEM (1<<6) // 0x00000040
+#define AI_GOAL_FORM_ON_WING (1<<7) // 0x00000080
+#define AI_GOAL_UNDOCK (1<<8) // 0x00000100
+#define AI_GOAL_CHASE_WING (1<<9) // 0x00000200
+#define AI_GOAL_GUARD (1<<10) // 0x00000400
+#define AI_GOAL_DISABLE_SHIP (1<<11) // 0x00000800
+#define AI_GOAL_DISARM_SHIP (1<<12) // 0x00001000
+#define AI_GOAL_CHASE_ANY (1<<13) // 0x00002000
+#define AI_GOAL_IGNORE (1<<14) // 0x00004000
+#define AI_GOAL_GUARD_WING (1<<15) // 0x00008000
+#define AI_GOAL_EVADE_SHIP (1<<16) // 0x00010000
 
 // the next goals are for support ships only
-#define AI_GOAL_STAY_NEAR_SHIP (1<<17)
-#define AI_GOAL_KEEP_SAFE_DISTANCE (1<<18)
-#define AI_GOAL_REARM_REPAIR (1<<19)
+#define AI_GOAL_STAY_NEAR_SHIP (1<<17) // 0x00020000
+#define AI_GOAL_KEEP_SAFE_DISTANCE (1<<18) // 0x00040000
+#define AI_GOAL_REARM_REPAIR (1<<19) // 0x00080000
 
 // resume regular goals
-#define AI_GOAL_STAY_STILL (1<<20)
-#define AI_GOAL_PLAY_DEAD (1<<21)
-#define AI_GOAL_CHASE_WEAPON (1<<22)
+#define AI_GOAL_STAY_STILL (1<<20) // 0x00100000
+#define AI_GOAL_PLAY_DEAD (1<<21) // 0x00200000
+#define AI_GOAL_CHASE_WEAPON (1<<22) // 0x00400000
 
-#define AI_GOAL_FLY_TO_SHIP (1<<23) // kazan
-#define AI_GOAL_IGNORE_NEW (1<<24) // Goober5000
+#define AI_GOAL_FLY_TO_SHIP (1<<23) // 0x00800000
+#define AI_GOAL_IGNORE_NEW (1<<24) // 0x01000000
 
 // now the masks for ship types
 
Index: code/autopilot/autopilot.cpp
===================================================================
--- code/autopilot/autopilot.cpp (revision 6288)
+++ code/autopilot/autopilot.cpp (working copy)
@@ -39,6 +39,7 @@
 // Module variables
 bool AutoPilotEngaged;
 bool UseCutsceneBars;
+bool LockWeaponsDuringAutopilot;
 int CurrentNav;
 float ramp_bias;
 NavPoint Navs[MAX_NAVPOINTS];
@@ -55,6 +56,9 @@
 vec3d cameraPos, cameraTarget;
 std::map<int,int> autopilot_wings;
 
+int AutopilotMinEnemyDistance;
+int AutopilotMinAsteroidDistance;
+
 // used for ramping time compression;
 int start_dist;
 
@@ -149,12 +153,7 @@
 }
 
 // ********************************************************************************************
-// Tell us if autopilot is allowed
-// This needs:
-//        * Nav point selected
-//        * No enemies within X distance
-//        * Destination > 1,000 meters away
-bool CanAutopilot(bool send_msg)
+bool CanAutopilot(vec3d targetPos, bool send_msg)
 {
  if (CurrentNav == -1)
  {
@@ -162,95 +161,64 @@
  send_autopilot_msgID(NP_MSG_FAIL_NOSEL);
  return false;
  }
-
+
  if (object_get_gliding(Player_obj))
  {
  if (send_msg)
  send_autopilot_msgID(NP_MSG_FAIL_GLIDING);
  return false;
  }
+
  // You cannot autopilot if you're within 1000 meters of your destination nav point
- if (vm_vec_dist_quick(&Player_obj->pos, Navs[CurrentNav].GetPosition()) < 1000)
- {
+ if (vm_vec_dist_quick(&targetPos, Navs[CurrentNav].GetPosition()) < 1000) {
  if (send_msg)
  send_autopilot_msgID(NP_MSG_FAIL_TOCLOSE);
  return false;
  }
 
- // see if any hostiles are nearby
- for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
- {
- object *other_objp = &Objects[so->objnum];
-
- // attacks player?
- if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
- && !(Ship_info[Ships[other_objp->instance].ship_info_index].flags & SIF_CARGO))
+ if ( AutopilotMinEnemyDistance > 0 ) {
+ // see if any hostiles are nearby
+ for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
  {
- // Cannot autopilot if enemy within 5,000 meters
- if (vm_vec_dist_quick(&Player_obj->pos, &other_objp->pos) < 5000)
+ object *other_objp = &Objects[so->objnum];
+ // attacks player?
+ if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
+ && !(Ship_info[Ships[other_objp->instance].ship_info_index].flags & SIF_CARGO)) // ignore cargo
  {
- if (send_msg)
- send_autopilot_msgID(NP_MSG_FAIL_HOSTILES);
- return false;
+ // Cannot autopilot if enemy within AutopilotMinEnemyDistance meters
+ if (vm_vec_dist_quick(&targetPos, &other_objp->pos) < AutopilotMinEnemyDistance) {
+ if (send_msg)
+ send_autopilot_msgID(NP_MSG_FAIL_HOSTILES);
+ return false;
+ }
  }
  }
  }
-
- //check for asteroids
- for (int n=0; n<MAX_ASTEROIDS; n++)
- {
- // asteroid
- if (Asteroids[n].flags & AF_USED)
+
+ if ( AutopilotMinAsteroidDistance > 0 ) {
+ //check for asteroids
+ for (int n=0; n<MAX_ASTEROIDS; n++)
  {
- // Cannot autopilot if asteroid within 1,000 meters
- if (vm_vec_dist_quick(&Player_obj->pos, &Objects[Asteroids[n].objnum].pos) < 1000)
+ // asteroid
+ if (Asteroids[n].flags & AF_USED)
  {
- if (send_msg)
- send_autopilot_msgID(NP_MSG_FAIL_HAZARD);
- return false;
+ // Cannot autopilot if asteroid within AutopilotMinAsteroidDistance meters
+ if (vm_vec_dist_quick(&targetPos, &Objects[Asteroids[n].objnum].pos) < AutopilotMinAsteroidDistance) {
+ if (send_msg)
+ send_autopilot_msgID(NP_MSG_FAIL_HAZARD);
+ return false;
+ }
  }
  }
  }
 
- return true;
-}
-
-// ********************************************************************************************
-// Tell us if autopilot is allowed at a certain position (only performs checks based on that position)
-// This needs:
-//        * Nav point selected
-//        * No enemies within X distance
-//        * Destination > 1,000 meters away
-bool CanAutopilotPos(vec3d targetPos)
-{
- // You cannot autopilot if you're within 1000 meters of your destination nav point
- if (vm_vec_dist_quick(&targetPos, Navs[CurrentNav].GetPosition()) < 1000)
+ // check for support ships
+ // cannot autopilot if support ship present
+ if ( ship_find_repair_ship(Player_obj) != NULL ) {
+ if (send_msg)
+ send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_PRESENT);
  return false;
- // see if any hostiles are nearby
- for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
- {
- object *other_objp = &Objects[so->objnum];
- // attacks player?
- if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
- && !(Ship_info[Ships[other_objp->instance].ship_info_index].flags & SIF_CARGO)) // ignore cargo
- {
- // Cannot autopilot if enemy within 5,000 meters
- if (vm_vec_dist_quick(&targetPos, &other_objp->pos) < 5000)
- return false;
- }
  }
-
- //check for asteroids
- for (int n=0; n<MAX_ASTEROIDS; n++)
- {
- // asteroid
- if (Asteroids[n].flags & AF_USED)
- {
- // Cannot autopilot if asteroid within 1,000 meters
- if (vm_vec_dist_quick(&targetPos, &Objects[Asteroids[n].objnum].pos) < 1000)
- return false;
- }
- }
 
  return true;
 }
@@ -264,10 +232,39 @@
 //        * Lock time compression -WMC
 //        * Tell AI to fly to targetted Nav Point (for all nav-status wings/ships)
 //  * Sets max waypoint speed to the best-speed of the slowest ship tagged
-void StartAutopilot()
+bool StartAutopilot()
 {
+ // Check for support ship and dismiss it if it is not doing anything.
+ // If the support ship is doing something then tell the user such.
+ bool done = false;
+ while (!done) {
+ object* support_ship_op = ship_find_repair_ship(Player_obj);
+ if ( support_ship_op == NULL ) {
+ // no more
+ done = true;
+ break;
+ }
+
+ Assert( support_ship_op->type == OBJ_SHIP );
+ Assert( support_ship_op->instance >= 0 );
+ Assert( support_ship_op->instance < MAX_SHIPS );
+ Assert( Ships[support_ship_op->instance].ai_index != -1 );
+
+ ai_info* support_ship_aip = &(Ai_info[Ships[support_ship_op->instance].ai_index]);
+
+ // is support ship trying to rearm-repair
+ if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
+ // no, so tell it to depart
+ ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
+ } else {
+ // yes
+ send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING);
+ return false;
+ }
+
+ }
  if (!CanAutopilot())
- return;
+ return false;
 
  AutoPilotEngaged = true;
 
@@ -341,10 +338,20 @@
  }
  }
 
-
  // damp speed_cap to 90% of actual -- to make sure ships stay in formation
  if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
  speed_cap = 0.90f * speed_cap;
+
+ if ( speed_cap < 1.0f ) {
+ /* We need to deal with this so that incorrectly flagged ships will not
+ cause the engine to fail to limit all the ships speeds correctly. */
+ Warning(LOCATION, "Ship speed cap is way too small (%f)!\n"
+ "This is normally caused by a ship that has nav-carry-status set, but cannot move itself (like a Cargo container).\n"
+ "Speed cap has been set to 1.0 m/s.",
+ speed_cap);
+ speed_cap = 1.0f;
+ }
+
  ramp_bias = speed_cap/50.0f;
 
  // assign ship goals
@@ -410,7 +417,7 @@
  vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
  }
 
- // snap wings into formation them into formation
+ // snap wings into formation
  if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS &&  // only if using cinematics
  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
  && Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
@@ -458,7 +465,8 @@
  }
  }
  // lock primary and secondary weapons
- //Ships[i].flags2 |= (SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);
+ if ( LockWeaponsDuringAutopilot )
+ Ships[i].flags2 |= (SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);
 
  // clear the ship goals and cap the waypoint speed
  ai_clear_ship_goals(&Ai_info[Ships[i].ai_index]);
@@ -843,16 +851,8 @@
  camMovingTime = int(4.5*float(tc_factor));
  set_time_compression((float)tc_factor);
  }
-}
 
-// ********************************************************************************************
-// Checks if autopilot should automatically die
-// Returns true if:
-//         * Targetted waypoint < 10,000 meters away
-//         * Enemy < 10,000 meters
-bool Autopilot_AutoDiable()
-{
- return !CanAutopilot();
+ return true;
 }
 
 // ********************************************************************************************
@@ -914,8 +914,10 @@
    )
  {
  //unlock their weaponry
- //Ships[i].flags2 &= ~(SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);
+ if ( LockWeaponsDuringAutopilot )
+ Ships[i].flags2 &= ~(SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);
  Ai_info[Ships[i].ai_index].waypoint_speed_cap = -1; // uncap their speed
+ Ai_info[Ships[i].ai_index].mode = AIM_NONE; // make AI re-evaluate current ship mode
 
  for (j = 0; j < MAX_AI_GOALS; j++)
  {
@@ -992,18 +994,19 @@
 {
  /* ok... find our end distance - norm1 is still a unit vector in the
  direction from the flight leader to the navpoint */
- vec3d targetPos, tpos=Autopilot_flight_leader->pos, pos;
+ vec3d targetPos, tpos=Autopilot_flight_leader->pos, pos, velocity;
 
  /* calculate a vector that we can use to make a path from the flight
  leader's location to the nav point */
  vm_vec_sub(&pos, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
  vm_vec_normalize(&pos);
+ velocity = pos; // make a copy for later when we do setup veleocity vector
  vm_vec_scale(&pos, 250.0f); // we move by increments of 250
 
  /* using the vector of the flight leaders's path, simulate moving the
  flight along this path by checking the autopilot conditions as specific
  intervals along the path*/
- while (CanAutopilotPos(tpos))
+ while (CanAutopilot(tpos))
  {
  vm_vec_add(&tpos, &tpos, &pos);
  }
@@ -1021,17 +1024,21 @@
  vm_vec_add(&cameraPos, &cameraPos, &targetPos);
  }
 
+ /* calcuate the speed that everyone is supposed to be going so that there
+ is no need for anyone to accelerate or decelerate (most obvious with
+ the player's fighter slowing down as it changes the camera pan speed). */
+ vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap);
+
  // Find all ships that are supposed to autopilot with the player and move them
  // to the cinimatic location or the final destination
  for (int i = 0; i < MAX_SHIPS; i++)
  {
- if (Ships[i].objnum != -1 &&
- (Ships[i].flags2 & SF2_NAVPOINT_CARRY ||
- (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
- )
- )
+ if (Ships[i].objnum != -1
+ && (Ships[i].flags2 & SF2_NAVPOINT_CARRY
+ || (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)))
  {
  vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
+ Objects[Ships[i].objnum].phys_info.vel = velocity;
  }
  }
 
@@ -1070,7 +1077,7 @@
  }
 
 
- if (timestamp() >= EndAPCinematic || Autopilot_AutoDiable())
+ if (timestamp() >= EndAPCinematic || !CanAutopilot())
  {
  nav_warp();
  EndAutoPilot();
@@ -1097,7 +1104,7 @@
  }
  else
  {
- if (Autopilot_AutoDiable())
+ if (!CanAutopilot())
  EndAutoPilot();
 
  }
@@ -1170,14 +1177,17 @@
  }
  }
 
- // autopilot linking
+ /* Link in any ships that need to be linked in when the player gets close
+ enough.  Always done by the player because: "making sure the AI fighters
+ are where they're supposed to be at all times is like herding cats" -Woolie Wool
+ */
  for (int i = 0; i < MAX_SHIPS; i++)
  {
  if (Ships[i].objnum != -1 && Ships[i].flags2 & SF2_NAVPOINT_NEEDSLINK)
  {
  object *other_objp = &Objects[Ships[i].objnum];
 
- if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &other_objp->pos) < (NavLinkDistance + other_objp->radius))
+ if (vm_vec_dist_quick(&Player_obj->pos, &other_objp->pos) < (NavLinkDistance + other_objp->radius))
  {
  Ships[i].flags2 &= ~SF2_NAVPOINT_NEEDSLINK;
  Ships[i].flags2 |= SF2_NAVPOINT_CARRY;
@@ -1276,6 +1286,21 @@
  required_string("$Link Distance:");
  stuff_int(&NavLinkDistance);
 
+ if (optional_string("$Interrupt autopilot if enemy within distance:"))
+ stuff_int(&AutopilotMinEnemyDistance);
+ else
+ AutopilotMinEnemyDistance = 5000;
+
+ if (optional_string("$Interrupt autopilot if asteroid within distance:"))
+ stuff_int(&AutopilotMinAsteroidDistance);
+ else
+ AutopilotMinAsteroidDistance = 1000;
+
+ if (optional_string("$Lock Weapons During Autopilot:"))
+ stuff_boolean(&LockWeaponsDuringAutopilot);
+ else
+ LockWeaponsDuringAutopilot = false;
+
  // optional no cutscene bars
  if (optional_string("+No_Cutscene_Bars"))
  UseCutsceneBars = false;
@@ -1284,7 +1309,9 @@
  Cmdline_autopilot_interruptable = 0;
 
  // No Nav selected message
- char *msg_tags[] = { "$No Nav Selected:", "$Gliding:", "$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:" };
+ char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
+ "$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
+ "$Support Present:", "$Support Working:" };
  for (int i = 0; i < NP_NUM_MESSAGES; i++)
  {
  required_string(msg_tags[i]);
Index: code/autopilot/autopilot.h
===================================================================
--- code/autopilot/autopilot.h (revision 6288)
+++ code/autopilot/autopilot.h (working copy)
@@ -8,6 +8,7 @@
 #define _AUTOPILOT_H_
 
 #include "globalincs/pstypes.h"
+#include "object/object.h"
 #include <map>
 
 // milliseconds between updates
@@ -37,13 +38,15 @@
 };
 
 
-#define NP_NUM_MESSAGES 6
 #define NP_MSG_FAIL_NOSEL 0
 #define NP_MSG_FAIL_GLIDING 1
 #define NP_MSG_FAIL_TOCLOSE 2
 #define NP_MSG_FAIL_HOSTILES 3
 #define NP_MSG_MISC_LINKED 4
 #define NP_MSG_FAIL_HAZARD 5
+#define NP_MSG_FAIL_SUPPORT_PRESENT 6
+#define NP_MSG_FAIL_SUPPORT_WORKING 7
+#define NP_NUM_MESSAGES 8
 
 struct NavMessage
 {
@@ -62,28 +65,29 @@
 bool Sel_NextNav();
 
 
-// Tell us is autopilot is allow
+// Tell us if autopilot is allowed
 // This needs:
 //        * Nav point selected
-//        * No enemies within 5,000 meters
+//        * No enemies within AutopilotMinEnemyDistance meters
+//        * No asteroids within AutopilotMinAsteroidDistance meters
 //        * Destination > 1,000 meters away
-bool CanAutopilot(bool send_msg=false);
-bool CanAutopilotPos(vec3d targetPos);
+//        * Support ship not present or is actively leaving
+bool CanAutopilot(vec3d targetPos, bool send_msg=false);
 
+// Check if autopilot is allowed at player's current position
+// See CanAutopilot(vec3d, bool) for more information
+inline bool CanAutopilot(bool send_msg=false) { return CanAutopilot(Player_obj->pos, send_msg); }
+
 // Engages autopilot
 // This does:
+//        * Checks if Autopilot is allowed.  See CanAutopilot() for conditions.
 //        * Control switched from player to AI
 //        * Time compression to 32x
 //        * Tell AI to fly to targetted Nav Point (for all nav-status wings/ships)
-//  * Sets max waypoint speed to the best-speed of the slowest ship tagged
-void StartAutopilot();
+//        * Sets max waypoint speed to the best-speed of the slowest ship tagged
+// Returns false if autopilot cannot be started. True otherwise.
+bool StartAutopilot();
 
-// Checks if autopilot should automatically die
-// Returns true if:
-//         * Targetted waypoint < 1,000 meters away
-//         * Enemy < 5,000 meters
-bool Autopilot_AutoDiable();
-
 // Disengages autopilot
 // this does:
 //         * Time compression to 1x
Index: code/globalincs/def_files.cpp
===================================================================
--- code/globalincs/def_files.cpp (revision 6288)
+++ code/globalincs/def_files.cpp (working copy)
@@ -986,6 +986,12 @@
 $Hazard: \n\
  +Msg: Cannot engage autopilot: Hazard Near \n\
  +Snd File: none \n\
+$Support Present: \n\
+ +Msg: Cannot engage autopilot: Support Ship Present \n\
+ +Snd File: none \n\
+$Support Working: \n\
+ +Msg: Cannot engage autopilot: Support Ship is rearming or repairing a ship \n\
+ +Snd File: none \n\
  \n\
 #END \n\
 ";
Index: code/io/keycontrol.cpp
===================================================================
--- code/io/keycontrol.cpp (revision 6288)
+++ code/io/keycontrol.cpp (working copy)
@@ -2846,11 +2846,7 @@
  }
  else
  {
- if (CanAutopilot(true))
- {
- StartAutopilot();
- }
- else
+ if (!StartAutopilot())
  gamesnd_play_iface(SND_GENERAL_FAIL);
  }
  }
Index: code/ship/ship.cpp
===================================================================
--- code/ship/ship.cpp (revision 6288)
+++ code/ship/ship.cpp (working copy)
@@ -72,6 +72,7 @@
 #include "iff_defs/iff_defs.h"
 #include "network/multiutil.h"
 #include "network/multimsgs.h"
+#include "autopilot/autopilot.h"
 
 
 
@@ -11814,6 +11815,7 @@
 
 // function which is used to find a repair ship to repair requester_obj.  the way repair ships will work
 // is:
+// if repair ship present and ordered to depart, return NULL.
 // if repair ship present and available, return pointer to that object.
 // If repair ship present and busy, possibly return that object if he can satisfy the request soon enough.
 // If repair ship present and busy and cannot satisfy request, return NULL to warp a new one in if below max number
@@ -11862,6 +11864,14 @@
  continue;
  }
 
+ /* Ship has been ordered to warpout but has not had a chance to
+ process the order.*/
+ Assert( Ships[objp->instance].ai_index != -1 );
+ ai_info* aip = &(Ai_info[Ships[objp->instance].ai_index]);
+ if ( ai_find_goal_index( aip->goals, AI_GOAL_WARP ) != -1 ) {
+ continue;
+ }
+
  dist = vm_vec_dist_quick(&objp->pos, &requester_obj->pos);
 
  if (!(Ai_info[shipp->ai_index].ai_flags & AIF_REPAIRING))
@@ -14678,6 +14688,10 @@
 {
  // check updated mission conditions to allow support
 
+ // If running under autopilot support is not allowed
+ if ( AutoPilotEngaged )
+ return 0;
+
  // none allowed
  if (The_mission.support_ships.max_support_ships == 0)
  return 0;
« Last Edit: July 11, 2010, 01:56:55 am by Iss Mneur »
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline chief1983

  • Still lacks a custom title
  • Moderator
  • 212
  • ⬇️⬆️⬅️⬅️🅰➡️⬇️
    • Minecraft
    • Skype
    • Steam
    • Twitter
    • Fate of the Galaxy
Re: (AI changes) Autopilot and Waypoint Fixes
I'd just like to give a big thanks to IssMneur for looking into this bug.  Once he dug it, it quickly grew from a single Mantis issue into a whole pile of problems related to the autopilot and AI code.  He's been working with Woolie and Talon for the last several weeks to get these straightened out.  These issues have been around since well before 3.6.10 was released, which will tell you a bit about how long some people have been waiting on a fix for these issues (around 2 years).  So thanks again Iss.
Fate of the Galaxy - Now Hiring!  Apply within | Diaspora | SCP Home | Collada Importer for PCS2
Karajorma's 'How to report bugs' | Mantis
#freespace | #scp-swc | #diaspora | #SCP | #hard-light on EsperNet

"You may not sell or otherwise commercially exploit the source or things you created based on the source." -- Excerpt from FSO license, for reference

Nuclear1:  Jesus Christ zack you're a little too hamyurger for HLP right now...
iamzack:  i dont have hamynerge i just want ptatoc hips D:
redsniper:  Platonic hips?!
iamzack:  lays

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: (AI changes) Autopilot and Waypoint Fixes
That first bullet point
Quote
Collapsed the code for the AI goals AIM_FLY_TO_SHIP and AIM_WAYPOINTS into one sub-function (removing the redundant code).
has got my attention...

Do these changes bring us any close to being able to dynamically issue move orders (working through a ship's normal flight AI instead of manually messing with the ship's controls/velocity)? I ask this because one of the major issues that got in the way of the FS-RTS mod's progress was not having any way to issue move orders. Even though that project's kind of mothballed right now, I'm still curious about how far off that capability is.

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: (AI changes) Autopilot and Waypoint Fixes
That first bullet point
Quote
Collapsed the code for the AI goals AIM_FLY_TO_SHIP and AIM_WAYPOINTS into one sub-function (removing the redundant code).
has got my attention...

Do these changes bring us any close to being able to dynamically issue move orders (working through a ship's normal flight AI instead of manually messing with the ship's controls/velocity)? I ask this because one of the major issues that got in the way of the FS-RTS mod's progress was not having any way to issue move orders. Even though that project's kind of mothballed right now, I'm still curious about how far off that capability is.
I didn't really change anything there other than removing the duplicate code.

Assuming that I understand your question correctly. In short the answer is no, this code does not affect the waypoint management code or the maximum number of waypoint lists (currently 32) or the maximum number of waypoints per list (currently 20).  And no, this does not really make it any closer.

That being said, there is no reason that I see that waypoints (and waypoint lists cannot be created/destroyed dynamically if they cannot already be) as the waypoints themselves are just objects of type OBJ_WAYPOINT.  There is also no reason that the specific data structures cannot be made dynamic so that the large numbers needed by an RTS would be possible.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline General Battuta

  • Poe's Law In Action
  • 214
  • i wonder when my postcount will exceed my iq
Re: (AI changes) Autopilot and Waypoint Fixes
I would like the ability to move waypoints mid-mission, and have the AI reflect this and compensate their courses to adjust.

 

Offline chief1983

  • Still lacks a custom title
  • Moderator
  • 212
  • ⬇️⬆️⬅️⬅️🅰➡️⬇️
    • Minecraft
    • Skype
    • Steam
    • Twitter
    • Fate of the Galaxy
Re: (AI changes) Autopilot and Waypoint Fixes
Let's focus on fixing the current issues with the waypoint code before we bolt on more stuff to try and break it again shall we?  :P

Seriously though put those requests in another thread if you really need them for something, and maybe we can look at those after 3.6.12.
Fate of the Galaxy - Now Hiring!  Apply within | Diaspora | SCP Home | Collada Importer for PCS2
Karajorma's 'How to report bugs' | Mantis
#freespace | #scp-swc | #diaspora | #SCP | #hard-light on EsperNet

"You may not sell or otherwise commercially exploit the source or things you created based on the source." -- Excerpt from FSO license, for reference

Nuclear1:  Jesus Christ zack you're a little too hamyurger for HLP right now...
iamzack:  i dont have hamynerge i just want ptatoc hips D:
redsniper:  Platonic hips?!
iamzack:  lays

 

Offline Sushi

  • Art Critic
  • 211
Re: (AI changes) Autopilot and Waypoint Fixes
Iss Mneur swings his +5 Two Handed Sword at the Ancient and Mighty Bug-Dragon!
Critical Hit!
The Ancient and Mighty Bug-Dragon has been slain!

:D

Nice work.

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: (AI changes) Autopilot and Waypoint Fixes
Iss Mneur swings his +5 Two Handed Sword at the Ancient and Mighty Bug-Dragon!
Critical Hit!
The Ancient and Mighty Bug-Dragon has been slain!

:D

Nice work.
Yes, as long as I haven't created another one by slaying this one.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline Woolie Wool

  • 211
  • Fire main batteries
Re: (AI changes) Autopilot and Waypoint Fixes
The autopilot seems fine to me right now although I don't think Talon has tested this build yet.
16:46   Quanto   ****, a mosquito somehow managed to bite the side of my palm
16:46   Quanto   it itches like hell
16:46   Woolie   !8ball does Quanto have malaria
16:46   BotenAnna   Woolie: The outlook is good.
16:47   Quanto   D:

"did they use anesthetic when they removed your sense of humor or did you have to weep and struggle like a tiny baby"
--General Battuta

 

Offline Talon 1024

  • 29
  • How do you turn this on?
    • Mods, Games, and Stuff
Re: (AI changes) Autopilot and Waypoint Fixes
It seems the waypoint system is broken in this build...  When an AI ship is assigned to fly a waypoint path once, the ship flies to the last waypoint on the path instead of flying on the waypoint path, and the game seems to think that the AI ship is done following the waypoints right when it is assigned to fly the waypoint path.  I created the attached mission to show how the waypoint system is broken in this build.

[attachment deleted by ninja]
To understand religion, you need to understand morality first. | WCSaga website | WCSaga Forum | 158th website | 158th forum | Project Leader: WC: Hostile Frontier | WCHF Thread at CIC | Wing Blender | Twist of Fate | Multipart turrets on angled surfaces, tutorial included. | My Google Drive stuff | To convert speeds from WC to WCS, multiply both the cruise speed and the Afterburner speed by 0.15625 (5/32)

FS2 Mods I'm waiting on: Inferno 10th Anniversary
Current Project: Contestant Android app, Learn4Life iOS app, Blender Commander (importer).
The FreeSpace Font Foundry is back in action!

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: (AI changes) Autopilot and Waypoint Fixes
Thank you Talon 1024!  :yes:  I have been trying to find the bug that was causing Cardinal Spear's mission "Knows Not Friend nor Foe" to be impossible with my patched binary.

Updated OP with a new patch and updated build.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline Woolie Wool

  • 211
  • Fire main batteries
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Also be aware that setting a ship's properties to autopilot needs link seems to cause a crash.
16:46   Quanto   ****, a mosquito somehow managed to bite the side of my palm
16:46   Quanto   it itches like hell
16:46   Woolie   !8ball does Quanto have malaria
16:46   BotenAnna   Woolie: The outlook is good.
16:47   Quanto   D:

"did they use anesthetic when they removed your sense of humor or did you have to weep and struggle like a tiny baby"
--General Battuta

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Also be aware that setting a ship's properties to autopilot needs link seems to cause a crash.

Fixed. Updated OP.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
If there are no more issue found with this patch by July 11th, I will push the patch to chief1983 to integrate into trunk and possibly 3.6.12.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 

Offline Talon 1024

  • 29
  • How do you turn this on?
    • Mods, Games, and Stuff
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
One more slight issue is that the player can fire primary and secondary weapons in autopilot.

Other than that, I do not think there are any more issues.  I'd also like to thank you for looking into this bug in the first place.
To understand religion, you need to understand morality first. | WCSaga website | WCSaga Forum | 158th website | 158th forum | Project Leader: WC: Hostile Frontier | WCHF Thread at CIC | Wing Blender | Twist of Fate | Multipart turrets on angled surfaces, tutorial included. | My Google Drive stuff | To convert speeds from WC to WCS, multiply both the cruise speed and the Afterburner speed by 0.15625 (5/32)

FS2 Mods I'm waiting on: Inferno 10th Anniversary
Current Project: Contestant Android app, Learn4Life iOS app, Blender Commander (importer).
The FreeSpace Font Foundry is back in action!

 

Offline FUBAR-BDHR

  • Self-Propelled Trouble Magnet
  • 212
  • Master Drunk
    • 165th Beer Drinking Hell Raisers
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
I don't think that one is a bug.  It's been that way since 3.6.9 at least.  Simple sexps to lock/unlock weapons in the autopilot events solve the issue. 
No-one ever listens to Zathras. Quite mad, they say. It is good that Zathras does not mind. He's even grown to like it. Oh yes. -Zathras

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Interestingly there actually is commented out code in the autopilot to lock and unlock the weapons.  The code was commented out in revision 4406, but the commit message doesn't give any reason for it. 

Uncommenting the code doesn't seem to break anything, so leave the behaviour as is, or automatically lock the weapons.
"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments

 
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
My opinion on this one is that weapons should be locked in autopilot mode. There is simply no good reason to have them unlocked - you need to be able to point the weapons for any form of accuracy.

</opinion mode="off">
STRONGTEA. Why can't the x86 be sane?

 

Offline chief1983

  • Still lacks a custom title
  • Moderator
  • 212
  • ⬇️⬆️⬅️⬅️🅰➡️⬇️
    • Minecraft
    • Skype
    • Steam
    • Twitter
    • Fate of the Galaxy
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
What about a player controlled turret?  You could be on a rail a la Call of Duty.
Fate of the Galaxy - Now Hiring!  Apply within | Diaspora | SCP Home | Collada Importer for PCS2
Karajorma's 'How to report bugs' | Mantis
#freespace | #scp-swc | #diaspora | #SCP | #hard-light on EsperNet

"You may not sell or otherwise commercially exploit the source or things you created based on the source." -- Excerpt from FSO license, for reference

Nuclear1:  Jesus Christ zack you're a little too hamyurger for HLP right now...
iamzack:  i dont have hamynerge i just want ptatoc hips D:
redsniper:  Platonic hips?!
iamzack:  lays

 

Offline Iss Mneur

  • Moderator
  • 210
  • TODO:
Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
What about a player controlled turret?  You could be on a rail a la Call of Duty.
We are only talking about locking the weapons for a cinematic autopilot, in which everyone is flying in formation.

And at any rate, the engine will not allow the either autopilot mode to be engaged while there are enemy ships within 5 km.

"I love deadlines. I like the whooshing sound they make as they fly by." -Douglas Adams
wxLauncher 0.9.4 public beta (now with no config file editing for FRED) | wxLauncher 2.0 Request for Comments