Hard Light Productions Forums

Modding, Mission Design, and Coding => FS2 Open Coding - The Source Code Project (SCP) => Test Builds => Topic started by: Iss Mneur on July 02, 2010, 12:48:39 am

Title: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 02, 2010, 12:48:39 am
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):

Debug and release windows build (no pdbs). (http://www.box.net/shared/dxeifl41ya) 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;
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 02, 2010, 01:03:09 pm
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Aardwolf on July 02, 2010, 06:00:00 pm
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 03, 2010, 01:01:18 am
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: General Battuta on July 03, 2010, 01:19:22 am
I would like the ability to move waypoints mid-mission, and have the AI reflect this and compensate their courses to adjust.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 03, 2010, 02:09:17 am
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Sushi on July 03, 2010, 10:27:04 am
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 03, 2010, 02:45:20 pm
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.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Woolie Wool on July 03, 2010, 03:20:37 pm
The autopilot seems fine to me right now although I don't think Talon has tested this build yet.
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Talon 1024 on July 04, 2010, 05:49:18 pm
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]
Title: Re: (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 04, 2010, 10:01:36 pm
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.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Woolie Wool on July 04, 2010, 10:17:51 pm
Also be aware that setting a ship's properties to autopilot needs link seems to cause a crash.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 05, 2010, 12:42:52 am
Also be aware that setting a ship's properties to autopilot needs link seems to cause a crash.

Fixed. Updated OP.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 07, 2010, 11:08:10 am
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.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Talon 1024 on July 07, 2010, 03:38:56 pm
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.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: FUBAR-BDHR on July 07, 2010, 04:10:54 pm
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. 
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 08, 2010, 01:05:47 am
Interestingly there actually is commented out code in the autopilot to lock and unlock the weapons.  The code was commented out in revision 4406 (https://svn.icculus.org/fs2open?view=rev&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.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: portej05 on July 08, 2010, 06:41:07 am
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">
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 08, 2010, 09:57:42 am
What about a player controlled turret?  You could be on a rail a la Call of Duty.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 08, 2010, 10:11:34 am
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.

Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 08, 2010, 10:17:25 am
That sounds like a silly restriction on FREDers.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 08, 2010, 10:26:40 am
That sounds like a silly restriction on FREDers.
What does?  The locking the weapons?
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 08, 2010, 11:14:41 am
No the enemy ships in range thing.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 08, 2010, 11:47:26 am
I suppose.  Though remember that this code was written specifically for WCSaga, so it follows the Wing Commander rules. 

But honestly, I don't know if anyone would want to allow the player to autopilot while the their are enemies near, because (to be clear) the autopilot is not a intrasystem jump like FreeSpace uses whereas under autopilot the ships envolved are physically "flying" the route (in fact, even though the cinematic autopilot code slews the ships around the world it still checks the "flight path" for the rules so that you don't autopilot past some enemies).

That being said, removing that test with a tbl setting would be easy enough if someone actually wants this type of feature.
Title: Re: [Updated July 4, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: The E on July 08, 2010, 11:54:44 am
A "$No autopilot if enemy within distance: NUMBER" setting would be good (defaulting to 5000).
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 11, 2010, 01:58:02 am
Okay, new build (hopefully the last before it gets put into trunk), is available in the first post.

Adds: $Interrupt autopilot if enemy within distance:, $Interrupt autopilot if asteroid within distance:, and $Lock Weapons During Autopilot:.
Cleans up some more duplicated code.  Removed some useless code.
Clarified some warnings that may be emitted by the new code.  Also clarified some comments in the code.

Delaying pushing the patch to chief1983 until July 13th.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Woolie Wool on July 14, 2010, 11:38:23 pm
Does that mean I can have a cinematic autopilot and have enemies jump in midway between the two nav points (or simply have them sitting there, waiting for someone to stumble across them) and the cinematic autopilot will drop out as the player is waylaid by the enemies?
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 15, 2010, 12:23:22 am
Interrupt may be misleading, I think the original intent was to prevent it being initialized in the first place.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 15, 2010, 10:18:39 am
Interrupt may be misleading, I think the original intent was to prevent it being initialized in the first place.

No, interrupt is exactly what it will do.

Does that mean I can have a cinematic autopilot and have enemies jump in midway between the two nav points (or simply have them sitting there, waiting for someone to stumble across them) and the cinematic autopilot will drop out as the player is waylaid by the enemies?

No. Yes.

The enemies (or asteroids for that matter) have to be within the Interrupt distance of the flight path when the autopilot is calculating the route.  So  the enemies cannot warp in after the autopilot has engaged, but if they are just sitting there within Interrupt distance of the flight path (same goes for the asteroids) then the autopilot will drop the group out the Interrupt distance from the object causing the interrupt.

I have not changed this behaviour, just exposed the distance value to the MODer.  This also applies to both the cinematic autopilot and the time compression autopilot.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Talon 1024 on July 28, 2010, 06:41:45 pm
I'm sorry I was so late on this, but if a ship is given the ai-waypoints goal, it only follows the waypoint path once, instead of patrolling the path like it should.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 28, 2010, 06:48:51 pm
Can't you reset the goal upon completion?
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 28, 2010, 09:01:33 pm
I'm sorry I was so late on this, but if a ship is given the ai-waypoints goal, it only follows the waypoint path once, instead of patrolling the path like it should.

Please try: http://www.box.net/shared/j235mil0mf
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Talon 1024 on July 28, 2010, 09:42:06 pm
Hmmm...  Using this build, the ai-waypoints AI goal does not work properly if it is in the wing/ship's initial orders, but it does work properly if that AI goal is assigned via a SEXP.

EDIT: Edited for clarity
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 29, 2010, 01:45:56 am
Okay, I have looked at the code that assigns the initial orders, and it seems that initial orders are sexps  and as such implemented by the sexp system which means it follows pretty much exactly the same code path as when the goal is assigned by the events sexps.  Also, the only part of the ai code that I have changed for this patch interacts at the mode level of the AI (ie the part that actually makes a goal happen).

Thus, Talon 1024, can you please provide a basic mission that exhibits ai-waypoints not working as initial orders and a mission that exhibits ai-waypoints working as a sexp.

Also, does this issue only appear in builds after my autopilot fixes where added, or before?
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: chief1983 on July 29, 2010, 01:49:25 am
Easy build to test that last bit would be RC3, as it had no autopilot fixes but is otherwise very close to RC4 which does have them all save for this last tweak.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: The E on July 29, 2010, 01:10:40 pm
Please try this build:
http://blueplanet.fsmods.net/E/fs2_open_3_6_13d_INF_SSE2.7z

It seems that the waypoint goal was cleared, regardless of whether or not the AI was ordered to fly them once or repeatedly.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 29, 2010, 02:40:25 pm
Please try this build:
http://blueplanet.fsmods.net/E/fs2_open_3_6_13d_INF_SSE2.7z

It seems that the waypoint goal was cleared, regardless of whether or not the AI was ordered to fly them once or repeatedly.

Did my build provided in my post further up (http://www.hard-light.net/forums/index.php?topic=70178.msg1396129#msg1396129) not fix ai-waypoints for you?

The issue now it seems is that ai-waypoints does not repeat when used as an initial order for a wing or ship, but works find when used as an order later.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: The E on July 29, 2010, 02:46:23 pm
Hey, I did not test this (due to a lack of a test case), I am just trying to fix the issue.

Here's the code patch:
Code: [Select]
Index: aicode.cpp
===================================================================
--- aicode.cpp (revision 6332)
+++ aicode.cpp (working copy)
@@ -4453,18 +4453,18 @@
  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 );
+ }
  }
- // 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 );
- }
  }
  }
 }

The problem, as I understood it by reading the code, was that the ai-waypoints goal was cleared once the ship reached the last waypoint, regardless of whether or not it was supposed to repeat the waypoint path. I think this should fix it, but as noone was around on IRC to talk to regarding the AI, I kinda had to take a guess.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Talon 1024 on July 29, 2010, 04:32:55 pm
Hmmm...  Using this build, the ai-waypoints AI goal does not work properly if it is in the wing/ship's initial orders...
Oh shoot.  I'm sorry. :(

This was actually a stupid oversight on my part.  I had two wings, one of them was given the ai-waypoints goal (Bravo), and one was given the ai-waypoints-once goal (Charlie).  I had an event that fired once Charlie wing finished it's waypoints, and Charlie wing coincidentially finished their waypoints at the same time that Bravo wing had nearly finished theirs, and that event cleared Bravo's orders and assigned Charlie the orders to patrol another waypoint path.  Bravo's AI goals being cleared had lead me to believe that this SEXP was not working properly if it was being called from initial orders, but that was not the case.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Zacam on July 29, 2010, 04:37:43 pm
So, to clarify, the build Iss Mneur linked on 07-28-2010 does work? Or that a build earlier than that worked?
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: The E on July 29, 2010, 05:32:43 pm
Iss' build works. My build works. RC4 does not. Question is, what was Iss' code change?
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: Iss Mneur on July 29, 2010, 08:43:56 pm
Iss' build works. My build works. RC4 does not. Question is, what was Iss' code change?
Letter for letter with what you posted as a patch, save for an addition newline between "stay on last waypoint" and the comment about logging the waypoint.  So just put your patch in trunk and I will add the revision to the 3.6.12 backport thread; otherwise, I will bug chief or another commiter about it when I am back to my computer on Saturday.
Title: Re: [Updated July 11, 2010] (AI changes) Autopilot and Waypoint Fixes
Post by: The E on July 30, 2010, 12:43:10 am
Oh, that's good. For a sec, I thought we had different approaches, somehow. Patch is in trunk.