FS2_Open
Open source remastering of the Freespace 2 engine
autopilot.cpp
Go to the documentation of this file.
1 // Autopilot.cpp
2 // Derek Meek
3 // 4-30-2004
4 
5 
6 
7 
8 #include "ai/ai.h"
9 #include "ai/aigoals.h"
10 #include "asteroid/asteroid.h"
11 #include "autopilot/autopilot.h"
12 #include "camera/camera.h"
13 #include "cfile/cfile.h"
14 #include "freespace2/freespace.h"
15 #include "gamesnd/eventmusic.h"
16 #include "globalincs/def_files.h"
17 #include "globalincs/linklist.h"
18 #include "iff_defs/iff_defs.h"
19 #include "io/timer.h"
20 #include "localization/localize.h"
21 #include "mission/missionmessage.h"
23 #include "object/objcollide.h"
24 #include "object/waypoint.h"
25 #include "parse/parselo.h"
26 #include "parse/sexp.h"
27 #include "ship/ship.h"
28 #include "sound/audiostr.h"
29 
30 #include <map>
31 
32 // Extern functions/variables
33 extern int Player_use_ai;
34 extern int get_wing_index(object *objp, int wingnum);
35 extern object * get_wing_leader(int wingnum);
37 
38 
39 // Module variables
44 float ramp_bias;
49 // time offsets for autonav events
54 //float CameraSpeed;
58 
61 
62 // used for ramping time compression;
64 
65 // ********************************************************************************************
66 
68 {
69  // this function sets wp_index properly;
71 }
72 
73 
74 // ********************************************************************************************
76 {
77  if (AutoPilotEngaged)
78  return false;
79 
80  int i;
81  if (CurrentNav == -1)
82  {
83  for (i = 0; i < MAX_NAVPOINTS; i++)
84  {
85  if (Navs[i].flags & NP_VALIDTYPE && !(Navs[i].flags & NP_NOSELECT))
86  {
87  CurrentNav=i;
88  return true;
89  }
90  }
91  }
92  else
93  {
94  for (i = CurrentNav+1; i < MAX_NAVPOINTS+CurrentNav; i++)
95  {
96  if (Navs[i%MAX_NAVPOINTS].flags & NP_VALIDTYPE && !(Navs[i%MAX_NAVPOINTS].flags & NP_NOSELECT))
97  {
98  if (i != CurrentNav)
99  {
100  CurrentNav=i%MAX_NAVPOINTS;
101  return true;
102  }
103  }
104  }
105  }
106  return false;
107 }
108 
109 
110 // ********************************************************************************************
112 {
113  if (flags & NP_WAYPOINT)
114  {
116  Assert(wpt != NULL);
117  return wpt->get_pos();
118  }
119  else
120  {
121  return &Objects[((ship*) target_obj)->objnum].pos;
122  }
123 }
124 
126 {
127  char *NavName;
128  char strtmp[33];
129 
130  if (flags & NP_WAYPOINT)
131  {
132  NavName = new char[strlen(((waypoint_list*)target_obj)->get_name())+5];
133  memset(NavName, 0, strlen(((waypoint_list*)target_obj)->get_name())+5);
134  strcpy(NavName, ((waypoint_list*)target_obj)->get_name());
135 
136  strcat(NavName, ":");
137  sprintf(strtmp, "%d", waypoint_num);
138  strcat(NavName, strtmp);
139  }
140  else
141  {
142  NavName = new char[strlen(((ship*)target_obj)->ship_name)+1];
143  memset(NavName, 0, strlen(((ship*)target_obj)->ship_name)+1);
144  strcpy(NavName, ((ship*)target_obj)->ship_name);
145  }
146 
147  return NavName;
148 }
149 
150 // ********************************************************************************************
151 bool CanAutopilot(vec3d targetPos, bool send_msg)
152 {
153  if (CurrentNav == -1)
154  {
155  if (send_msg)
157  return false;
158  }
159 
161  {
162  if (send_msg)
164  return false;
165  }
166 
167  // You cannot autopilot if you're within 1000 meters of your destination nav point
168  if (vm_vec_dist_quick(&targetPos, Navs[CurrentNav].GetPosition()) < 1000) {
169  if (send_msg)
171  return false;
172  }
173 
174  if ( AutopilotMinEnemyDistance > 0 ) {
175  // see if any hostiles are nearby
176  for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
177  {
178  object *other_objp = &Objects[so->objnum];
179  // attacks player?
180  if (iff_x_attacks_y(obj_team(other_objp), obj_team(Player_obj))
181  && !(Ship_info[Ships[other_objp->instance].ship_info_index].flags & SIF_CARGO)) // ignore cargo
182  {
183  // Cannot autopilot if enemy within AutopilotMinEnemyDistance meters
184  if (vm_vec_dist_quick(&targetPos, &other_objp->pos) < AutopilotMinEnemyDistance) {
185  if (send_msg)
187  return false;
188  }
189  }
190  }
191  }
192 
193  if ( AutopilotMinAsteroidDistance > 0 ) {
194  //check for asteroids
195  for (int n=0; n<MAX_ASTEROIDS; n++)
196  {
197  // asteroid
198  if (Asteroids[n].flags & AF_USED)
199  {
200  // Cannot autopilot if asteroid within AutopilotMinAsteroidDistance meters
201  if (vm_vec_dist_quick(&targetPos, &Objects[Asteroids[n].objnum].pos) < AutopilotMinAsteroidDistance) {
202  if (send_msg)
204  return false;
205  }
206  }
207  }
208  }
209 
210  // check for support ships
211  // cannot autopilot if support ship present
212  if ( ship_find_repair_ship(Player_obj) != 0 ) {
213  if (send_msg)
215  return false;
216  }
217 
218  return true;
219 }
220 
221 extern object* Autopilot_flight_leader;
222 // ********************************************************************************************
223 // Engages autopilot
224 // This does:
225 // * Control switched from player to AI
226 // * Time compression to 32x
227 // * Lock time compression -WMC
228 // * Tell AI to fly to targeted Nav Point (for all nav-status wings/ships)
229 // * Sets max waypoint speed to the best-speed of the slowest ship tagged
231 {
232  // Check for support ship and dismiss it if it is not doing anything.
233  // If the support ship is doing something then tell the user such.
235  {
236  if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD))
237  {
238  Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
239  "objp does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d",
241  ship *shipp = &Ships[objp->instance];
242 
243  if (shipp->team != Player_ship->team)
244  continue;
245 
246  Assertion((shipp->ship_info_index >= 0) && (shipp->ship_info_index < static_cast<int>(Ship_info.size())),
247  "Ship '%s' does not have a valid pointer to a ship class. Pointer is %d, which is smaller than 0 or bigger than %d",
248  shipp->ship_name, shipp->ship_info_index, static_cast<int>(Ship_info.size()));
249  ship_info *sip = &Ship_info[shipp->ship_info_index];
250 
251  if ( !(sip->flags & SIF_SUPPORT) )
252  continue;
253 
254  // don't deal with dying or departing support ships
255  if ( shipp->flags & (SF_DYING | SF_DEPARTING) )
256  continue;
257 
258  Assert(shipp->ai_index != -1);
259  ai_info* support_ship_aip = &(Ai_info[Ships[objp->instance].ai_index]);
260 
261  // is support ship trying to rearm-repair
262  if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
263  // no, so tell it to depart
264  ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
265  } else {
266  // yes
268  return false;
269  }
270  }
271  }
272  if (!CanAutopilot())
273  return false;
274 
275  AutoPilotEngaged = true;
276 
277  // find the ship that is "leading" all of the ships when the player starts
278  // autopilot
279  // by default the ship that is leading the autopilot session the player's
280  // wing leader (if the player is the wing leader then it will be the
281  // player).
282  // TODO:implement a way to allow a FREDer to say a different ship is leader
283  Autopilot_flight_leader = get_wing_leader(Player_ship->wingnum);
284  if ( Autopilot_flight_leader == NULL ) {
285  // force player to be the leader if he doesn't have a wing
286  Autopilot_flight_leader = Player_obj;
287  }
288 
290  LockAPConv = timestamp(); // lock convergence instantly
291  else
292  LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
293  Player_use_ai = 1;
295  lock_time_compression(true);
296 
297  // determine speed cap
298  int i,j, wcount=1, tc_factor=1;
299  float speed_cap = 1000000.0; // 1m is a safe starting point
300  float radius = Player_obj->radius, distance = 0.0f, ftemp;
301  bool capshipPresent = false;
302  int capship_counts[3]; // three size classes
303  capship_counts[0] = 0;
304  capship_counts[1] = 0;
305  capship_counts[2] = 0;
306 
307  int capship_placed[3]; // three size classes
308  capship_placed[0] = 0;
309  capship_placed[1] = 0;
310  capship_placed[2] = 0;
311 
312  float capship_spreads[3];
313  capship_spreads[0] = 0.0f;
314  capship_spreads[1] = 0.0f;
315  capship_spreads[2] = 0.0f;
316 
317  SCP_vector<int> capIndexes;
318 
319  // empty the autopilot wings map
320  autopilot_wings.clear();
321 
322  // vars for usage w/ cinematic
323  vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero;
324  memset(&zero, 0, sizeof(vec3d));
325 
326 
327  // instantly turn player toward tpos
329  {
330  vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
331  vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL);
332  }
333 
334  for (i = 0; i < MAX_SHIPS; i++)
335  {
336  if (Ships[i].objnum != -1 &&
337  (Ships[i].flags2 & SF2_NAVPOINT_CARRY ||
338  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
339  )
340  )
341  {
342  if (speed_cap > vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel))
343  speed_cap = vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel);
344  }
345  }
346 
347  // damp speed_cap to 90% of actual -- to make sure ships stay in formation
349  speed_cap = 0.90f * speed_cap;
350 
351  if ( speed_cap < 1.0f ) {
352  /* We need to deal with this so that incorrectly flagged ships will not
353  cause the engine to fail to limit all the ships speeds correctly. */
354  Warning(LOCATION, "Ship speed cap is way too small (%f)!\n"
355  "This is normally caused by a ship that has nav-carry-status set, but cannot move itself (like a Cargo container).\n"
356  "Speed cap has been set to 1.0 m/s.",
357  speed_cap);
358  speed_cap = 1.0f;
359  }
360 
361  ramp_bias = speed_cap/50.0f;
362 
363  // assign ship goals
364  // when assigning goals to individual ships only do so if Ships[shipnum].wingnum != -1
365  // we will assign wing goals below
366 
367  for (i = 0; i < MAX_SHIPS; i++)
368  {
369  if (Ships[i].objnum != -1 &&
370  (Ships[i].flags2 & SF2_NAVPOINT_CARRY ||
371  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
372  )
373  )
374  {
375  // do we have capital ships in the area?
376  if (Ship_info[Ships[i].ship_info_index].flags
378  {
379  capshipPresent = true;
380 
381  capIndexes.push_back(i);
382  // ok.. what size class
383 
384  if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
385  {
386  capship_counts[0]++;
387  if (capship_spreads[0] < Objects[Ships[i].objnum].radius)
388  capship_spreads[0] = Objects[Ships[i].objnum].radius;
389  }
390  else if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CORVETTE))
391  {
392  capship_counts[1]++;
393  if (capship_spreads[1] < Objects[Ships[i].objnum].radius)
394  capship_spreads[1] = Objects[Ships[i].objnum].radius;
395  }
396  else
397  {
398  capship_counts[2]++;
399  if (capship_spreads[2] < Objects[Ships[i].objnum].radius)
400  capship_spreads[2] = Objects[Ships[i].objnum].radius;
401  }
402  }
403 
404 
405 
406  // check for bigger radius for usage later
407  /*if (!vm_vec_cmp(&rpos, &Player_obj->pos))
408  // want to make sure rpos isn't player pos - we can worry about it being largest object's later
409  {
410  rpos = Objects[Ships[i].objnum].pos;
411  }*/
412 
413  if (Objects[Ships[i].objnum].radius > radius)
414  {
415  rpos = Objects[Ships[i].objnum].pos;
416  radius = Objects[Ships[i].objnum].radius;
417  }
418 
420  {// instantly turn the ship to match the direction player is looking
421  //vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
422  vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
423  }
424 
425  // snap wings into formation
426  if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS && // only if using cinematics
427  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
428  && Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
429  {
430  ai_info *aip = &Ai_info[Ships[i].ai_index];
431  int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
432  vec3d goal_point;
433  object *leader_objp = get_wing_leader(wingnum);
434 
435  if (leader_objp != &Objects[Ships[i].objnum])
436  {
437  // not leader.. get our position relative to leader
438  get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
439  }
440  else
441  {
442  ai_clear_wing_goals(wingnum);
443  j = 1+int( (float)floor(double(wcount-1)/2.0) );
444  switch (wcount % 2)
445  {
446  case 1: // back-left
447  vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
448  //vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
449  vm_vec_normalize(&perp);
450  vm_vec_scale(&perp, -166.0f*j); // 166m is supposedly the optimal range according to tolwyn
451  vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
452  break;
453 
454  default: //back-right
455  case 0:
456  vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
457  //vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
458  vm_vec_normalize(&perp);
459  vm_vec_scale(&perp, 166.0f*j);
460  vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
461  break;
462  }
463  autopilot_wings[wingnum] = wcount;
464  wcount++;
465  }
466  Objects[Ships[i].objnum].pos = goal_point;
467  if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos) > distance)
468  {
469  distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos);
470  }
471  }
472  // lock primary and secondary weapons
475 
476  // clear the ship goals and cap the waypoint speed
477  ai_clear_ship_goals(&Ai_info[Ships[i].ai_index]);
478  Ai_info[Ships[i].ai_index].waypoint_speed_cap = (int)speed_cap;
479 
480 
481  // if they're not part of a wing set their goal
482  if (Ships[i].wingnum == -1 || The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
483  {
484  if (Navs[CurrentNav].flags & NP_WAYPOINT)
485  {
486  ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
487  //fixup has to wait until after wing goals
488  }
489  else
490  {
491  ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
492  }
493 
494  }
495  }
496  }
497 
498  // assign wing goals
500  {
501  for (i = 0; i < MAX_WINGS; i++)
502  {
503  if (Wings[i].flags & WF_NAV_CARRY )
504  {
505  //ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );
506 
507  //ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
508  //ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
509  //ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) );
510 
511  ai_clear_wing_goals( i );
512  if (Navs[CurrentNav].flags & NP_WAYPOINT)
513  {
514 
516 
517  // "fix up" the goal
518  for (j = 0; j < MAX_AI_GOALS; j++)
519  {
520  if (Wings[i].ai_goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
521  Wings[i].ai_goals[j].ai_mode == AIM_WAYPOINTS )
522  {
523  autopilot_ai_waypoint_goal_fixup(&(Wings[i].ai_goals[j]));
524  }
525  }
526  }
527  else
528  {
529  ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );
530 
531  }
532  }
533  }
534  }
535 
536  // fixup has to go down here because ships are assigned goals during wing goals as well
537  for (i = 0; i < MAX_SHIPS; i++)
538  {
539  if (Ships[i].objnum != -1)
540  {
541  if (Ships[i].flags2 & SF2_NAVPOINT_CARRY ||
542  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY))
543  for (j = 0; j < MAX_AI_GOALS; j++)
544  {
545  if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
546  Ai_info[Ships[i].ai_index].goals[j].ai_mode == AIM_WAYPOINTS)
547  {
548  autopilot_ai_waypoint_goal_fixup( &(Ai_info[Ships[i].ai_index].goals[j]) );
549 
550 
551  // formation fixup
552  //ai_form_on_wing(&Objects[Ships[i].objnum], &Objects[Player_ship->objnum]);
553  }
554  }
555  }
556  }
558 
559  // ----------------------------- setup cinematic -----------------------------
561  {
562  if (capshipPresent)
563  {
564  // position capships
565 
566  vec3d right, front, up, offset;
567  for (SCP_vector<int>::iterator idx = capIndexes.begin(); idx != capIndexes.end(); ++idx)
568  {
569  vm_vec_add(&right, &Autopilot_flight_leader->orient.vec.rvec, &zero);
570  vm_vec_add(&front, &Autopilot_flight_leader->orient.vec.fvec, &zero);
571  vm_vec_add(&up, &Autopilot_flight_leader->orient.vec.uvec, &zero);
572  vm_vec_add(&offset, &zero, &zero);
573  if (Ship_info[Ships[*idx].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
574  {
575  //0 - below - three lines of position
576 
577  // front/back to zero
578  vm_vec_add(&front, &zero, &zero);
579 
580  // position below
581  vm_vec_scale(&up, capship_spreads[0]); // scale the up vector by the radius of the largest ship in this formation part
582 
583 
584  switch (capship_placed[0] % 3)
585  {
586  case 1: // right
587  vm_vec_scale(&right, capship_spreads[0]);
588  break;
589 
590  case 2: // left
591  vm_vec_scale(&right, -capship_spreads[0]);
592  break;
593 
594  default: // straight
595  case 0:
596  vm_vec_add(&right, &zero, &zero);
597  vm_vec_scale(&up, 1.5); // add an extra half-radius
598  break;
599  }
600 
601  // scale by row
602  vm_vec_scale(&right, (1+((float)floor((float)capship_placed[0]/3))));
603  vm_vec_scale(&up, -(1+((float)floor((float)capship_placed[0]/3))));
604 
605  capship_placed[0]++;
606  }
607  else if (Ship_info[Ships[*idx].ship_info_index].flags & SIF_CORVETTE)
608  {
609  //1 above - 3 lines of position
610  // front/back to zero
611  vm_vec_add(&front, &zero, &zero);
612 
613  // position below
614  vm_vec_scale(&up, capship_spreads[1]); // scale the up vector by the radius of the largest ship in this formation part
615 
616 
617  switch (capship_placed[1] % 3)
618  {
619  case 1: // right
620  vm_vec_scale(&right, capship_spreads[1]);
621  break;
622 
623  case 2: // left
624  vm_vec_scale(&right, -capship_spreads[1]);
625  break;
626 
627  default: // straight
628  case 0:
629  vm_vec_add(&right, &zero, &zero);
630  vm_vec_scale(&up, 1.5); // add an extra half-radius
631  break;
632  }
633 
634  // scale by row
635  vm_vec_scale(&right, (1+((float)floor((float)capship_placed[1]/3))));
636  vm_vec_scale(&up, (1+((float)floor((float)capship_placed[1]/3))));
637 
638  // move ourselves up and out of the way of the smaller ships
639  vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.uvec, &zero);
640  vm_vec_scale(&perp, capship_spreads[2]);
641  vm_vec_add(&up, &up, &perp);
642 
643  capship_placed[1]++;
644  }
645  else
646  {
647  //2 either side - 6 lines of position (right (dir, front, back), left (dir, front, back) )
648  // placing pattern: right, left, front right, front left, rear right, rear left
649 
650  // up/down to zero
651  vm_vec_add(&up, &zero, &zero);
652 
653 
654  switch (capship_placed[2] % 6)
655  {
656  case 5: // rear left
657  vm_vec_scale(&right, -capship_spreads[2]);
658  vm_vec_scale(&front, -capship_spreads[2]);
659  break;
660 
661  case 4: // rear right
662  vm_vec_scale(&right, capship_spreads[2]);
663  vm_vec_scale(&front, -capship_spreads[2]);
664  break;
665 
666  case 3: // front left
667  vm_vec_scale(&right, -capship_spreads[2]);
668  vm_vec_scale(&front, capship_spreads[2]);
669  break;
670 
671  case 2: // front right
672  vm_vec_scale(&right, capship_spreads[2]);
673  vm_vec_scale(&front, capship_spreads[2]);
674  break;
675 
676  case 1: // straight left
677  vm_vec_scale(&right, 1.5);
678  vm_vec_scale(&right, -capship_spreads[2]);
679  vm_vec_add(&front, &zero, &zero);
680  break;
681 
682  default: // straight right
683  case 0:
684  vm_vec_scale(&right, 1.5);
685  vm_vec_scale(&right, capship_spreads[2]);
686  vm_vec_add(&front, &zero, &zero);
687  break;
688  }
689  // these ships seem to pack a little too tightly
690  vm_vec_scale(&right, 2*(1+((float)floor((float)capship_placed[2]/3))));
691  vm_vec_scale(&front, 2*(1+((float)floor((float)capship_placed[2]/3))));
692 
693  // move "out" by 166*(wcount-1) so we don't bump into fighters
694  vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.rvec, &zero);
695  vm_vec_scale(&perp, 166.0f*float(wcount-1));
696  if ( (capship_placed[2] % 2) == 0)
697  vm_vec_add(&right, &right, &perp);
698  else
699  vm_vec_sub(&right, &right, &perp);
700 
701  capship_placed[2]++;
702  }
703 
704  // integrate the up/down componant
705  vm_vec_add(&offset, &offset, &up);
706 
707  //integrate the left/right componant
708  vm_vec_add(&offset, &offset, &right);
709 
710  //integrate the left/right componant
711  vm_vec_add(&offset, &offset, &front);
712 
713  // global scale the position by 50%
714  //vm_vec_scale(&offset, 1.5);
715 
716  vm_vec_add(&Objects[Ships[*idx].objnum].pos, &Autopilot_flight_leader->pos, &offset);
717 
718  if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos) > distance)
719  {
720  distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos);
721  }
722  }
723  }
724 
725  ftemp = floor(Autopilot_flight_leader->phys_info.max_vel.xyz.z/speed_cap);
726  if (ftemp >= 2.0f && ftemp < 4.0f)
727  tc_factor = 2;
728  else if (ftemp >= 4.0f && ftemp < 8.0f)
729  tc_factor = 4;
730  else if (ftemp >= 8.0f)
731  tc_factor = 8;
732 
733 
734 
735  tpos = *Navs[CurrentNav].GetPosition();
736  // determine distance toward nav at which camera will be
737  vm_vec_sub(&pos, &tpos, &Autopilot_flight_leader->pos);
738  vm_vec_normalize(&pos); // pos is now a unit vector in the direction we will be moving the camera
739  //norm1 = pos;
740  vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
741  vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship
742 
743  switch (myrand()%24)
744  // 8 different ways of getting perp points
745  // 4 of which will not be used when capships are present (anything below, or straight above)
746  {
747 
748  case 1: // down
749  case 9:
750  case 16:
751  if (capship_placed[0] == 0)
752  vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
753  else
754  { // become up-left
755  vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
756  vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
757  }
758  break;
759 
760  case 2: // up
761  case 10:
762  case 23:
763  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
764  if (capshipPresent) // become up-right
765  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
766  break;
767 
768  case 3: // left
769  case 11:
770  case 22:
771  vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
772  break;
773 
774  case 4: // up-left
775  case 12:
776  case 21:
777  vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
778  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
779  break;
780 
781  case 5: // up-right
782  case 13:
783  case 20:
784  vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
785  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
786  break;
787 
788  case 6: // down-left
789  case 14:
790  case 19:
791  vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
792  if (capship_placed[0] < 2)
793  vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
794  else
795  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
796  break;
797 
798  case 7: // down-right
799  case 15:
800  case 18:
801  vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
802  if (capship_placed[0] < 1)
803  vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
804  else
805  vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
806  break;
807 
808  default:
809  case 0: // right
810  case 8:
811  case 17:
812  perp = Autopilot_flight_leader->orient.vec.rvec;
813  break;
814 
815  }
816  vm_vec_normalize(&perp);
817  //vm_vec_scale(&perp, 2*radius+distance);
818 
819  vm_vec_scale(&perp, Autopilot_flight_leader->radius+radius);
820 
821  // randomly scale up/down by up to 20%
822  j = 20-myrand()%40; // [-20,20]
823 
824  vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
825  vm_vec_add(&cameraPos, &pos, &perp);
826 
827  if (capshipPresent)
828  {
829  vm_vec_normalize(&perp);
830 
831  // place it behind
832  //vm_vec_copy_scale(&norm1, &Player_obj->orient.vec.fvec, -2*(Player_obj->radius+radius*(1.0f+(float(j)/100.0f))));
833  //vm_vec_add(&cameraTarget, &cameraTarget, &norm1);
834 
835  vm_vec_copy_scale(&cameraTarget,&perp, radius/5.0f);
836 
837  //vm_vec_scale(&cameraTarget, Player_obj->radius+radius*(1.0f+(float(j)/100.0f)));
838 
839  //vm_vec_add(&cameraTarget, &pos, &cameraTarget);
840  //CameraSpeed = (radius+distance)/25;
841 
842  //vm_vec_add(&cameraTarget, &zero, &perp);
843  //vm_vec_scale(&CameraVelocity, (radius+distance/100.f));
844  //vm_vec_scale(&CameraVelocity, 1.0f/float(NPS_TICKRATE*tc_factor));
845  }
846  else
847  {
848  vm_vec_add(&cameraTarget, &zero, &zero);
849  //CameraSpeed = 0;
850  }
851  //CameraMoving = false;
852 
853 
854  EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic
855  MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
856  camMovingTime = int(4.5*float(tc_factor));
857  set_time_compression((float)tc_factor);
858  }
859 
860  return true;
861 }
862 
863 // ********************************************************************************************
864 // Disengages autopilot
865 // this does:
866 // * Time compression to 1x
867 // * Delete AI nav goal
868 // * Control switched from AI to player
870 {
871  AutoPilotEngaged = false;
872 
873  Autopilot_flight_leader = NULL;
874 
876  lock_time_compression(false);
877  Player_use_ai = 0;
878  //Clear AI Goals
879 
880  if (CinematicStarted) // clear cinematic if we need to
881  {
882  if (UseCutsceneBars)
883  {
885  }
887  CinematicStarted = false;
888  }
889 
890  Assert( CurrentNav >= 0 );
891 
892  int goal = 0;
893  char *goal_name = NULL;
894 
895  if (Navs[CurrentNav].flags & NP_WAYPOINT)
896  {
897  goal = AI_GOAL_WAYPOINTS_ONCE;
898  goal_name = ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name();
899  }
900  else
901  {
902  goal = AI_GOAL_FLY_TO_SHIP;
903  goal_name = ((ship*)Navs[CurrentNav].target_obj)->ship_name;
904  }
905 
906  // assign ship goals
907  // when assigning goals to individual ships only do so if Ships[shipnum].wingnum != -1
908  // we will assign wing goals below
909  int i, j;
910 
911  for (i = 0; i < MAX_SHIPS; i++)
912 
913  {
914  if (Ships[i].objnum != -1 &&
915  (
916  Ships[i].flags2 & SF2_NAVPOINT_CARRY ||
917  (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY )
918  )
919  )
920  {
921  //unlock their weaponry
924  Ai_info[Ships[i].ai_index].waypoint_speed_cap = -1; // uncap their speed
925  Ai_info[Ships[i].ai_index].mode = AIM_NONE; // make AI re-evaluate current ship mode
926 
927  for (j = 0; j < MAX_AI_GOALS; j++)
928  {
929  ai_goal *aigp = &Ai_info[Ships[i].ai_index].goals[j];
930 
931  if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
932  && (aigp->ai_mode == goal) )
933  {
934  ai_remove_ship_goal(&Ai_info[Ships[i].ai_index], j);
935  }
936  }
937 
938  if (Ships[i].wingnum != -1)
939  {
940  for (j = 0; j < MAX_AI_GOALS; j++)
941  {
942  ai_goal *aigp = &Wings[Ships[i].wingnum].ai_goals[j];
943 
944  if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
945  && (aigp->ai_mode == goal) )
946  {
947  aigp->ai_mode = AI_GOAL_NONE;
948  aigp->signature = -1;
949  aigp->priority = -1;
950  aigp->flags = 0;
951  }
952  }
953  }
954  }
955  }
956 
957  // un-assign wing goals
959  {
960  for (i = 0; i < MAX_WINGS; i++)
961  {
962  if (Wings[i].flags & WF_NAV_CARRY )
963  {
964  for (j = 0; j < MAX_AI_GOALS; j++)
965  {
966  ai_goal *aigp = &Wings[i].ai_goals[j];
967 
968  if ( ((aigp->target_name != NULL) && !stricmp(aigp->target_name, goal_name))
969  && (aigp->ai_mode == goal) )
970  {
971  aigp->ai_mode = AI_GOAL_NONE;
972  aigp->signature = -1;
973  aigp->priority = -1;
974  aigp->flags = 0;
975  }
976  }
977  }
978  }
979  }
980 }
981 
982 
983 // ********************************************************************************************
984 
986 {
987  static camid nav_camera;
988  if(!nav_camera.isValid())
989  {
990  nav_camera = cam_create("Nav camera");
991  }
992 
993  cam_set_camera(nav_camera);
994 
995  return nav_camera.getCamera();
996 }
997 
998 extern int Cmdline_old_collision_sys;
999 void nav_warp(bool prewarp=false)
1000 {
1001  /* ok... find our end distance - norm1 is still a unit vector in the
1002  direction from the flight leader to the navpoint */
1003  vec3d targetPos, tpos=Autopilot_flight_leader->pos, pos, velocity;
1004 
1005  /* calculate a vector that we can use to make a path from the flight
1006  leader's location to the nav point */
1007  vm_vec_sub(&pos, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos);
1009  velocity = pos; // make a copy for later when we do setup veleocity vector
1010  vm_vec_scale(&pos, 250.0f); // we move by increments of 250
1011 
1012  /* using the vector of the flight leaders's path, simulate moving the
1013  flight along this path by checking the autopilot conditions as specific
1014  intervals along the path*/
1015  while (CanAutopilot(tpos))
1016  {
1017  vm_vec_add(&tpos, &tpos, &pos);
1018  }
1019  vm_vec_sub(&targetPos, &tpos, &Autopilot_flight_leader->pos);
1020  /* targetPos is actually a vector that describes the exact 3D movement that
1021  the flgith leader needs to execute to reach the location that the auto
1022  pilot is to shut off */
1023 
1024  // Check if we are actually just setting up for the cinimatic shot of the
1025  // flight flying on autopilot. Only jump halfway. Also we also need to
1026  // put the camera in the correct position to show the player this cinimatic
1027  if (prewarp)
1028  {
1029  vm_vec_scale(&targetPos, 0.5);
1030  vm_vec_add(&cameraPos, &cameraPos, &targetPos);
1031  }
1032 
1033  /* calcuate the speed that everyone is supposed to be going so that there
1034  is no need for anyone to accelerate or decelerate (most obvious with
1035  the player's fighter slowing down as it changes the camera pan speed). */
1036  Assert( Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap > 0 );
1037  vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap);
1038 
1039  // Find all ships that are supposed to autopilot with the player and move them
1040  // to the cinimatic location or the final destination
1041  for (int i = 0; i < MAX_SHIPS; i++)
1042  {
1043  if (Ships[i].objnum != -1
1044  && (Ships[i].flags2 & SF2_NAVPOINT_CARRY
1045  || (Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)))
1046  {
1047  vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos);
1048  Objects[Ships[i].objnum].phys_info.vel = velocity;
1049  }
1050  }
1051 
1052  // retime all collision pairs
1053  if ( Cmdline_old_collision_sys ) {
1055  } else {
1057  }
1058 }
1059 
1060 // ********************************************************************************************
1061 // Checks for changes every NPS_TICKRATE milliseconds
1062 // Checks:
1063 // * if we've gotten close enough to a nav point for it to be counted as "Visited"
1064 // * If we're current AutoNavigating it checks if we need to autodisengage
1066 {
1067  static unsigned int last_update = 0;
1068  if (clock () - last_update > NPS_TICKRATE)
1069  {
1070  if (AutoPilotEngaged)
1071  {
1073  {
1074  camera *cam = nav_get_set_camera();
1075  if (CinematicStarted)
1076  {
1077  // update our cinematic and possibly perform warp
1078  //if (!CameraMoving)
1079  if(cam != NULL)
1081 
1082  if (timestamp() >= MoveCamera && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
1083  {
1084  //Free_camera->set_position(&cameraTarget, float(camMovingTime), float(camMovingTime)/2.0f);
1085  //Free_camera->set_translation_velocity(&cameraTarget);
1086  CameraMoving = true;
1087  }
1088 
1089 
1090  if (timestamp() >= EndAPCinematic || !CanAutopilot())
1091  {
1092  nav_warp();
1093  EndAutoPilot();
1094  }
1095  }
1096  else
1097  {
1098  // start cinematic
1099  if (UseCutsceneBars)
1100  {
1103  }
1104  nav_warp(true);
1105 
1106  if(cam != NULL)
1107  {
1108  cam->set_position(&cameraPos);
1109  cam->set_rotation_facing(&Autopilot_flight_leader->pos);
1110  }
1111 
1112  CinematicStarted = true;
1113  }
1114  }
1115  else
1116  {
1117  if (!CanAutopilot())
1118  EndAutoPilot();
1119 
1120  }
1121 
1122  }
1123  // check if a NavPoints target has left, delete it if so
1124  int i;
1125 
1126  for (i = 0; i < MAX_NAVPOINTS; i++)
1127  {
1128  if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_obj != NULL))
1129  {
1130  if (((ship*)Navs[i].target_obj)->objnum == -1)
1131  {
1132  if (CurrentNav == i)
1133  CurrentNav = -1;
1134  DelNavPoint(i);
1135  }
1136  }
1137  }
1138 
1139  // check if we're reached a Node
1140  for (i = 0; i < MAX_NAVPOINTS; i++)
1141  {
1142  if (Navs[i].target_obj != NULL)
1143  {
1144  if (Navs[i].flags & NP_VALIDTYPE && DistanceTo(i) < 1000)
1145  Navs[i].flags |= NP_VISITED;
1146  }
1147  }
1148  }
1149 
1150  // ramp time compression - only if not using cinematics
1152  {
1153  int dstfrm_start = start_dist - DistanceTo(CurrentNav);
1154 
1155  // Ramp UP time compression
1156  if (dstfrm_start < (3500*ramp_bias))
1157  {
1158 
1159  if (dstfrm_start >= (3000*ramp_bias) && DistanceTo(CurrentNav) > 30000)
1161  else if (dstfrm_start >= (2000*ramp_bias))
1163  else if (dstfrm_start >= (1600*ramp_bias))
1165  else if (dstfrm_start >= (1200*ramp_bias))
1167  else if (dstfrm_start >= (800*ramp_bias))
1169  else if (dstfrm_start >= (400*ramp_bias))
1171  }
1172 
1173  // Ramp DOWN time compression
1174  if (DistanceTo(CurrentNav) <= (7000*ramp_bias))
1175  {
1176  int dist = DistanceTo(CurrentNav);
1177  if (dist >= (5000*ramp_bias))
1179  else if (dist >= (4000*ramp_bias))
1181  else if (dist >= (3000*ramp_bias))
1183  else if (dist >= (2000*ramp_bias))
1185  else if (dist >= (1000*ramp_bias))
1187  }
1188  }
1189 
1190  /* Link in any ships that need to be linked in when the player gets close
1191  enough. Always done by the player because: "making sure the AI fighters
1192  are where they're supposed to be at all times is like herding cats" -Woolie Wool
1193  */
1194  for (int i = 0; i < MAX_SHIPS; i++)
1195  {
1196  if (Ships[i].objnum != -1 && Ships[i].flags2 & SF2_NAVPOINT_NEEDSLINK)
1197  {
1198  object *other_objp = &Objects[Ships[i].objnum];
1199 
1200  if (vm_vec_dist_quick(&Player_obj->pos, &other_objp->pos) < (NavLinkDistance + other_objp->radius))
1201  {
1202  Ships[i].flags2 &= ~SF2_NAVPOINT_NEEDSLINK;
1203  Ships[i].flags2 |= SF2_NAVPOINT_CARRY;
1204 
1206  }
1207 
1208  }
1209  }
1210 }
1211 // ********************************************************************************************
1212 
1213 void send_autopilot_msgID(int msgid)
1214 {
1215  if (msgid < 0 || msgid >= NP_NUM_MESSAGES)
1216  return;
1217 
1218  send_autopilot_msg(NavMsgs[msgid].message, NavMsgs[msgid].filename);
1219 }
1220 // ********************************************************************************************
1221 
1222 void send_autopilot_msg(char *msg, char *snd)
1223 {
1224  // setup
1225  if (audio_handle != -1)
1226  {
1228  audio_handle = -1;
1229  }
1230 
1231  if (msg[0] != '\0' && strcmp(msg, "none"))
1232  change_message("autopilot builtin message", msg, -1, 0);
1233 
1234  // load sound
1235  if ((snd != NULL) && (snd[0] != '\0' && !strcmp(snd, "none")))
1236  {
1238  }
1239 
1240  // send/play
1241  if (audio_handle != -1)
1242  {
1244  }
1245 
1246  if (msg[0] != '\0' && strcmp(msg, "none"))
1247  message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
1248 }
1249 
1250 // ********************************************************************************************
1251 // Inits the Nav System
1253 {
1254  for (int i = 0; i < MAX_NAVPOINTS; i++)
1255  Navs[i].clear();
1256 
1257  AutoPilotEngaged = false;
1258  CurrentNav = -1;
1259  audio_handle = -1;
1260  CinematicStarted = false;
1261  UseCutsceneBars = true;
1262 
1263  // defaults... can be tabled or bound to mission later
1264  if (cf_exists_full("autopilot.tbl", CF_TYPE_TABLES))
1265  parse_autopilot_table("autopilot.tbl");
1266  else
1267  parse_autopilot_table(NULL);
1268 }
1269 
1270 // ********************************************************************************************
1271 
1273 {
1274  SCP_vector<SCP_string> lines;
1275 
1276  try
1277  {
1278  if (filename == NULL)
1279  read_file_text_from_array(defaults_get_file("autopilot.tbl"));
1280  else
1281  read_file_text(filename, CF_TYPE_TABLES);
1282 
1283  reset_parse();
1284 
1285 
1286  required_string("#Autopilot");
1287 
1288  // autopilot link distance
1289  required_string("$Link Distance:");
1291 
1292  if (optional_string("$Interrupt autopilot if enemy within distance:"))
1294  else
1296 
1297  if (optional_string("$Interrupt autopilot if asteroid within distance:"))
1299  else
1301 
1302  if (optional_string("$Lock Weapons During Autopilot:"))
1304  else
1306 
1307  // optional no cutscene bars
1308  if (optional_string("+No_Cutscene_Bars"))
1309  UseCutsceneBars = false;
1310  // optional no cutscene bars
1311  if (optional_string("+No_Autopilot_Interrupt"))
1313 
1314  // No Nav selected message
1315  char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
1316  "$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
1317  "$Support Present:", "$Support Working:" };
1318  for (int i = 0; i < NP_NUM_MESSAGES; i++)
1319  {
1320  required_string(msg_tags[i]);
1321 
1322  required_string("+Msg:");
1323  stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
1324 
1325  required_string("+Snd File:");
1326  stuff_string(NavMsgs[i].filename, F_NAME, 256);
1327  }
1328 
1329 
1330  required_string("#END");
1331  }
1332  catch (const parse::ParseException& e)
1333  {
1334  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default autopilot.tbl>", e.what()));
1335  return;
1336  }
1337 }
1338 
1339 
1340 // ********************************************************************************************
1341 // Finds a Nav point by name
1342 int FindNav(char *Nav)
1343 {
1344  for (int i = 0; i < MAX_NAVPOINTS; i++)
1345  {
1346  if (!stricmp(Navs[i].m_NavName, Nav))
1347  return i;
1348  }
1349 
1350  return -1;
1351 }
1352 
1353 // ********************************************************************************************
1354 // Removes a Nav
1355 bool DelNavPoint(char *Nav)
1356 {
1357  int n = FindNav(Nav);
1358 
1359  return DelNavPoint(n);
1360 
1361 }
1362 
1363 bool DelNavPoint(int nav)
1364 {
1365  if (nav != -1)
1366  {
1367  if (nav != MAX_NAVPOINTS-1)
1368  {
1369  for (int i = nav; i < MAX_NAVPOINTS-1; i++)
1370  {
1371  Navs[nav] = Navs[nav+1];
1372  }
1373 
1374  }
1375  Navs[MAX_NAVPOINTS-1].clear();
1376  return true;
1377  }
1378 
1379  return false;
1380 }
1381 
1382 // ********************************************************************************************
1383 // adds a Nav
1384 bool AddNav_Ship(char *Nav, char *TargetName, int flags)
1385 {
1386  // find an empty nav - should be the end
1387 
1388  int empty = -1;
1389  int i;
1390 
1391  for (i = 0; i < MAX_NAVPOINTS && empty == -1; i++)
1392  {
1393  if (Navs[i].flags == 0)
1394  empty = i;
1395  }
1396 
1397  if (empty == -1) // no empty navpoint slots
1398  return false;
1399 
1400  // Create the NavPoint struct
1401  NavPoint tnav;
1402 
1403  strcpy_s(tnav.m_NavName, Nav);
1404  tnav.flags = NP_SHIP | flags;
1405 
1406  Assert(!(tnav.flags & NP_WAYPOINT));
1407 
1408 
1409  for (i = 0; i < MAX_SHIPS; i++)
1410  {
1411  if (Ships[i].objnum != -1 && !stricmp(TargetName, Ships[i].ship_name))
1412  {
1413  tnav.target_obj = (void *)&Ships[i];
1414  }
1415  }
1416 
1417  tnav.waypoint_num = 0; // unused for NP_SHIP
1418 
1419 
1420  // copy it into it's location
1421  Navs[empty] = tnav;
1422 
1423  return true;
1424 }
1425 
1426 
1427 bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags)
1428 {
1429  // find an empty nav - should be the end
1430 
1431  int empty = -1;
1432  int i;
1433 
1434  if (node == 0)
1435  node = 1;
1436 
1437  for (i = 0; i < MAX_NAVPOINTS && empty == -1; i++)
1438  {
1439  if (Navs[i].flags == 0)
1440  empty = i;
1441  }
1442 
1443  if (empty == -1) // no empty navpoint slots
1444  return false;
1445 
1446  // Create the NavPoint struct
1447  NavPoint tnav;
1448 
1449  strcpy_s(tnav.m_NavName, Nav);
1450  tnav.flags = NP_WAYPOINT | flags;
1451 
1452  Assert(!(tnav.flags & NP_SHIP));
1453 
1454  tnav.target_obj = find_matching_waypoint_list(WP_Path);
1455  tnav.waypoint_num = node;
1456 
1457  // copy it into it's location
1458  Navs[empty] = tnav;
1459 
1460  return true;
1461 }
1462 
1463 // ********************************************************************************************
1464 //Change Flags
1465 bool Nav_Alt_Flags(char *Nav, int flags)
1466 {
1467  flags &= ~NP_VALIDTYPE; //clear the NP_SHIP and NP_WAYPOINT bits, make sure they haven't been set
1468 
1469  int nav = FindNav(Nav);
1470 
1471  if (nav != -1)
1472  {
1473  Navs[nav].flags &= NP_VALIDTYPE; // Clear all bits BUT NP_SHIP or NO_WAYPOINT
1474  Navs[nav].flags |= flags; // merge
1475  }
1476 
1477  return (nav != -1);
1478 }
1479 
1480 //Get Flags
1481 int Nav_Get_Flags(char *Nav)
1482 {
1483  int flags = 0;
1484 
1485  int nav = FindNav(Nav);
1486 
1487  if (nav != -1)
1488  flags = Navs[nav].flags;
1489 
1490  return flags;
1491 }
1492 
1493 // ********************************************************************************************
1494 // Sexp Accessors
1495 
1496 //Generic
1497 bool Nav_Set_Flag(char *Nav, int flag)
1498 {
1499  Assert(!(flag & NP_VALIDTYPE));
1500  int nav = FindNav(Nav);
1501 
1502  if (nav != -1)
1503  {
1504  Navs[nav].flags |= flag;
1505  return true;
1506  }
1507 
1508  return false;
1509 }
1510 
1511 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1512 
1513 bool Nav_UnSet_Flag(char *Nav, int flag)
1514 {
1515  Assert(!(flag & NP_VALIDTYPE));
1516 
1517  int nav = FindNav(Nav);
1518 
1519  if (nav != -1)
1520  {
1521  Navs[nav].flags &= ~flag;
1522  return true;
1523  }
1524 
1525  return false;
1526 }
1527 
1528 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1529 //Named
1530 bool Nav_Set_Hidden(char *Nav)
1531 {
1532  return Nav_Set_Flag(Nav, NP_HIDDEN);
1533 
1534 }
1535 
1536 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1537 
1538 bool Nav_Set_NoAccess(char *Nav)
1539 {
1540  return Nav_Set_Flag(Nav, NP_NOACCESS);
1541 }
1542 
1543 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1544 
1545 bool Nav_Set_Visited(char *Nav)
1546 {
1547 
1548  return Nav_Set_Flag(Nav, NP_VISITED);
1549 }
1550 
1551 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1552 
1553 bool Nav_UnSet_Hidden(char *Nav)
1554 {
1555  return Nav_UnSet_Flag(Nav, NP_HIDDEN);
1556 }
1557 
1558 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1559 
1560 bool Nav_UnSet_NoAccess(char *Nav)
1561 {
1562  return Nav_UnSet_Flag(Nav, NP_NOACCESS);
1563 }
1564 
1565 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1566 
1567 bool Nav_UnSet_Visited(char *Nav)
1568 {
1569  return Nav_UnSet_Flag(Nav, NP_VISITED);
1570 }
1571 
1572 // ********************************************************************************************
1573 // Selects a navpoint by name.
1574 void SelectNav(char *Nav)
1575 {
1576  for (int i = 0; i < MAX_NAVPOINTS; i++)
1577  {
1578  if (!stricmp(Navs[i].m_NavName, Nav))
1579  if (!(Nav_Get_Flags(Nav) & NP_HIDDEN || Nav_Get_Flags(Nav) & NP_NOACCESS)) CurrentNav = i;
1580  }
1581 }
1582 
1583 // ********************************************************************************************
1584 // Deselects any navpoint selected.
1586 {
1587  CurrentNav = 0;
1588 }
1589 
1590 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591 
1592 
1593 unsigned int DistanceTo(char *nav)
1594 {
1595  int n = FindNav(nav);
1596 
1597  return DistanceTo(n);
1598 }
1599 
1600 unsigned int DistanceTo(int nav)
1601 {
1602  if (nav >= MAX_NAVPOINTS || nav < 0)
1603  return 0xFFFFFFFF;
1604 
1605  return (uint)vm_vec_dist_quick(&Player_obj->pos, Navs[nav].GetPosition());
1606 }
1607 
1608 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1609 
1610 bool IsVisited(char *nav)
1611 {
1612  int n = FindNav(nav);
1613 
1614  return IsVisited(n);
1615 }
1616 
1617 bool IsVisited(int nav)
1618 {
1619  if (nav >= MAX_NAVPOINTS || nav < 0)
1620  return 0;
1621 
1622  if (Navs[nav].flags & NP_VISITED)
1623  return 1;
1624  return 0;
1625 }
void autopilot_ai_waypoint_goal_fixup(ai_goal *aigp)
Definition: autopilot.cpp:67
int timestamp(int delta_ms)
Definition: timer.cpp:226
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
int i
Definition: multi_pxo.cpp:466
camid cam_create(char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_object, int n_object_host_submodel)
Definition: camera.cpp:888
unsigned int DistanceTo(char *nav)
Definition: autopilot.cpp:1593
bool CanAutopilot(vec3d targetPos, bool send_msg)
Definition: autopilot.cpp:151
int team
Definition: ship.h:606
int Cmdline_old_collision_sys
Definition: cmdline.cpp:489
int CurrentNav
Definition: autopilot.cpp:43
void lock_time_compression(bool is_locked)
Definition: fredstubs.cpp:227
#define ASF_MENUMUSIC
Definition: audiostr.h:20
int objnum
Definition: ship.h:537
int obj_team(object *objp)
Definition: object.cpp:1843
#define SIF_SUPERCAP
Definition: ship.h:901
bool Nav_UnSet_Hidden(char *Nav)
Definition: autopilot.cpp:1553
int ai_find_goal_index(ai_goal *aigp, int mode, int submode=-1, int priority=-1)
Definition: aigoals.cpp:1017
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
void ai_add_ship_goal_player(int type, int mode, int submode, char *shipname, ai_info *aip)
Definition: aigoals.cpp:757
void obj_all_collisions_retime(int checkdly)
Definition: objcollide.cpp:80
asteroid Asteroids[MAX_ASTEROIDS]
Definition: asteroid.cpp:63
void ai_add_wing_goal_player(int type, int mode, int submode, char *shipname, int wingnum)
Definition: aigoals.cpp:783
physics_info phys_info
Definition: object.h:157
#define MAX_WINGS
Definition: globals.h:50
int flags
Definition: autopilot.h:33
#define MAX_SHIPS
Definition: globals.h:37
#define MISSION_FLAG_USE_AP_CINEMATICS
Definition: missionparse.h:89
void ai_clear_wing_goals(int wingnum)
Definition: aigoals.cpp:270
bool IsVisited(char *nav)
Definition: autopilot.cpp:1610
int camMovingTime
Definition: autopilot.cpp:53
#define SIF_CRUISER
Definition: ship.h:887
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
#define NP_HIDDEN
Definition: autopilot.h:22
bool AddNav_Waypoint(char *Nav, char *WP_Path, int node, int flags)
Definition: autopilot.cpp:1427
Definition: pstypes.h:88
int EndAPCinematic
Definition: autopilot.cpp:51
#define mprintf(args)
Definition: pstypes.h:238
int ai_index
Definition: ship.h:538
int AutopilotMinEnemyDistance
Definition: autopilot.cpp:59
void set_position(vec3d *in_position=NULL, float in_translation_time=0.0f, float in_translation_acceleration_time=0.0f, float in_translation_deceleration_time=0.0f, float in_end_velocity=0.0f)
Definition: camera.cpp:162
#define SIF_CARGO
Definition: ship.h:884
struct vec3d::@225::@227 xyz
void NavSystem_Init()
Definition: autopilot.cpp:1252
int waypoint_num
Definition: autopilot.h:36
bool cam_set_camera(camid cid)
Definition: camera.cpp:980
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
const char * defaults_get_file(const char *filename)
Definition: def_files.cpp:103
bool Nav_Set_NoAccess(char *Nav)
Definition: autopilot.cpp:1538
#define AI_GOAL_WARP
Definition: aigoals.h:33
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define SF2_NAVPOINT_CARRY
Definition: ship.h:488
object obj_used_list
Definition: object.cpp:53
void nav_warp(bool prewarp=false)
Definition: autopilot.cpp:999
#define NP_MSG_FAIL_SUPPORT_PRESENT
Definition: autopilot.h:58
#define NP_MSG_MISC_LINKED
Definition: autopilot.h:56
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: Glext.h:5156
Definition: ai.h:329
#define AIM_NONE
Definition: ai.h:175
uint flags
Definition: ship.h:644
void ai_clear_ship_goals(ai_info *aip)
Definition: aigoals.cpp:251
hull_check orient
Definition: lua.cpp:5049
object * objp
Definition: lua.cpp:3105
#define AI_GOAL_NONE
Definition: ai.h:194
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
char m_NavName[32]
Definition: autopilot.h:32
#define SIF_GAS_MINER
Definition: ship.h:909
int ai_flags
Definition: ai.h:330
bool CameraMoving
Definition: autopilot.cpp:55
bool Nav_UnSet_NoAccess(char *Nav)
Definition: autopilot.cpp:1560
void cam_reset_camera()
Definition: camera.cpp:1002
#define AIF_FORMATION_OBJECT
Definition: ai.h:43
bool CinematicStarted
Definition: autopilot.cpp:55
#define AIM_WAYPOINTS
Definition: ai.h:173
#define AIG_TYPE_PLAYER_SHIP
Definition: ai.h:99
bool isValid()
Definition: camera.cpp:851
#define SIF_CAPITAL
Definition: ship.h:889
bool Nav_Set_Visited(char *Nav)
Definition: autopilot.cpp:1545
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
int waypoint_speed_cap
Definition: ai.h:375
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
GLintptr offset
Definition: Glext.h:5497
#define NP_MSG_FAIL_NOSEL
Definition: autopilot.h:52
struct matrix::@228::@230 vec
unsigned int uint
Definition: pstypes.h:64
vec3d * get_pos()
Definition: waypoint.cpp:46
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
bool Nav_Alt_Flags(char *Nav, int flags)
Definition: autopilot.cpp:1465
int flags
Definition: ship.h:1227
bool object_get_gliding(object *objp)
Definition: object.cpp:2059
char * filename
int wingnum
Definition: ship.h:623
ai_goal goals[MAX_AI_GOALS]
Definition: ai.h:412
int mode
Definition: ai.h:336
bool AddNav_Ship(char *Nav, char *TargetName, int flags)
Definition: autopilot.cpp:1384
vec3d cameraPos
Definition: autopilot.cpp:56
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
int AutopilotMinAsteroidDistance
Definition: autopilot.cpp:60
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
int ai_mode
Definition: ai.h:136
int Cmdline_autopilot_interruptable
Definition: cmdline.cpp:381
void set_time_compression(float multiplier, float change_time)
Definition: fredstubs.cpp:229
#define MAX_AI_GOALS
Definition: ai.h:91
void DeselectNav()
Definition: autopilot.cpp:1585
int priority
Definition: ai.h:141
char * GetInternalName()
Definition: autopilot.cpp:125
bool Nav_Set_Flag(char *Nav, int flag)
Definition: autopilot.cpp:1497
int required_string(const char *pstr)
Definition: parselo.cpp:468
char * target_name
Definition: ai.h:143
#define AIG_TYPE_PLAYER_WING
Definition: ai.h:100
SCP_map< int, int > autopilot_wings
Definition: autopilot.cpp:57
int optional_string(const char *pstr)
Definition: parselo.cpp:539
void SelectNav(char *Nav)
Definition: autopilot.cpp:1574
void parse_autopilot_table(char *filename)
Definition: autopilot.cpp:1272
Definition: ship.h:534
#define NP_VISITED
Definition: autopilot.h:24
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
void message_training_queue(char *text, int timestamp, int length)
int idx
Definition: multiui.cpp:761
bool AutoPilotEngaged
Definition: autopilot.cpp:40
#define AF_USED
Definition: asteroid.h:96
#define MAX_NAVPOINTS
Definition: autopilot.h:18
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
#define AI_GOAL_FLY_TO_SHIP
Definition: aigoals.h:56
vec3d * GetPosition()
Definition: autopilot.cpp:111
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
GLclampd n
Definition: Glext.h:7286
#define WF_NAV_CARRY
Definition: ship.h:1513
camera * nav_get_set_camera()
Definition: autopilot.cpp:985
void read_file_text_from_array(const char *array, char *processed_text, char *raw_text)
Definition: parselo.cpp:2022
#define AI_GOAL_WAYPOINTS_ONCE
Definition: aigoals.h:32
ship * Player_ship
Definition: ship.cpp:124
bool change_message(char *name, char *message, int persona_index, int multi_team)
void stuff_boolean(int *i, bool a_to_eol)
Definition: parselo.cpp:2519
bool Nav_UnSet_Flag(char *Nav, int flag)
Definition: autopilot.cpp:1513
#define NPS_TICKRATE
Definition: autopilot.h:16
int ship_find_repair_ship(object *requester_obj, object **ship_we_found)
Definition: ship.cpp:14008
matrix orient
Definition: object.h:153
#define F_MESSAGE
Definition: parselo.h:42
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define OBJ_SHIP
Definition: object.h:32
#define NP_MSG_FAIL_SUPPORT_WORKING
Definition: autopilot.h:59
GLbitfield flags
Definition: Glext.h:6722
bool StartAutopilot()
Definition: autopilot.cpp:230
void reset_parse(char *text)
Definition: parselo.cpp:3305
GLdouble GLdouble right
Definition: Glext.h:10330
int Player_use_ai
bool Nav_UnSet_Visited(char *Nav)
Definition: autopilot.cpp:1567
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d vel
Definition: physics.h:77
int Cutscene_bar_flags
Definition: systemvars.cpp:32
#define NP_NUM_MESSAGES
Definition: autopilot.h:60
#define SIF_SUPPORT
Definition: ship.h:878
bool UseCutsceneBars
Definition: autopilot.cpp:41
NavMessage NavMsgs[NP_NUM_MESSAGES]
Definition: autopilot.cpp:46
#define SF2_PRIMARIES_LOCKED
Definition: ship.h:492
#define SIF_FREIGHTER
Definition: ship.h:888
void stuff_int(int *i)
Definition: parselo.cpp:2372
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void audiostream_close_file(int i, int fade)
Definition: audiostr.cpp:1772
#define SF_DEPARTING
Definition: ship.h:475
void NavSystem_Do()
Definition: autopilot.cpp:1065
void send_autopilot_msg(char *msg, char *snd)
Definition: autopilot.cpp:1222
bool Sel_NextNav()
Definition: autopilot.cpp:75
waypoint_list * find_matching_waypoint_list(const char *name)
Definition: waypoint.cpp:164
int audio_handle
Definition: autopilot.cpp:47
Definition: pstypes.h:606
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
#define CUB_CUTSCENE
Definition: systemvars.h:52
class camera * getCamera()
Definition: camera.cpp:833
int start_dist
Definition: autopilot.cpp:63
void * target_obj
Definition: autopilot.h:35
ship_obj Ship_obj_list
Definition: ship.cpp:162
int ship_info_index
Definition: ship.h:539
int FindNav(char *Nav)
Definition: autopilot.cpp:1342
#define F_NAME
Definition: parselo.h:34
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
float Master_event_music_volume
Definition: eventmusic.cpp:40
object * Autopilot_flight_leader
Definition: aicode.cpp:291
#define NP_MSG_FAIL_HAZARD
Definition: autopilot.h:57
#define SIF_TRANSPORT
Definition: ship.h:890
#define SIF_AWACS
Definition: ship.h:910
int Nav_Get_Flags(char *Nav)
Definition: autopilot.cpp:1481
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
int LockAPConv
Definition: autopilot.cpp:50
hull_check pos
Definition: lua.cpp:5050
void audiostream_play(int i, float volume, int looping)
Definition: audiostr.cpp:1803
int wing
Definition: ai.h:333
#define NP_MSG_FAIL_TOCLOSE
Definition: autopilot.h:54
waypoint_list * wp_list
Definition: ai.h:145
void EndAutoPilot()
Definition: autopilot.cpp:869
object * Player_obj
Definition: object.cpp:56
Definition: ai.h:134
uint flags2
Definition: ship.h:645
#define AI_GOAL_REARM_REPAIR
Definition: aigoals.h:49
#define SF_DYING
Definition: ship.h:447
int audiostream_open(const char *filename, int type)
Definition: audiostr.cpp:1713
void clear()
Definition: autopilot.h:41
Definition: camera.h:18
#define MAX_ASTEROIDS
Definition: asteroid.h:24
#define NP_WAYPOINT
Definition: autopilot.h:20
object * get_wing_leader(int wingnum)
Definition: aicode.cpp:11251
waypoint * find_waypoint_at_index(waypoint_list *list, int index)
Definition: waypoint.cpp:307
#define NP_NOACCESS
Definition: autopilot.h:23
uint flags
Definition: object.h:151
#define NP_SHIP
Definition: autopilot.h:21
float radius
Definition: object.h:154
vec3d cameraTarget
Definition: autopilot.cpp:56
mission The_mission
bool Nav_Set_Hidden(char *Nav)
Definition: autopilot.cpp:1530
#define CUB_GRADUAL
Definition: systemvars.h:54
#define SF2_NAVPOINT_NEEDSLINK
Definition: ship.h:497
bool DelNavPoint(char *Nav)
Definition: autopilot.cpp:1355
int MoveCamera
Definition: autopilot.cpp:52
char type
Definition: object.h:146
#define NP_NOSELECT
Definition: autopilot.h:26
int get_wing_index(object *objp, int wingnum)
Definition: aicode.cpp:11230
int NavLinkDistance
Definition: autopilot.cpp:48
void obj_collide_retime_cached_pairs(int checkdly)
#define SF2_SECONDARIES_LOCKED
Definition: ship.h:493
float aav_music_volume
Definition: sound.cpp:79
#define stricmp(s1, s2)
Definition: config.h:271
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
bool LockWeaponsDuringAutopilot
Definition: autopilot.cpp:42
int flags
Definition: ai.h:139
NavPoint Navs[MAX_NAVPOINTS]
Definition: autopilot.cpp:45
char ship_name[NAME_LENGTH]
Definition: ship.h:604
void set_rotation_facing(vec3d *in_target, float in_rotation_time=0.0f, float in_rotation_acceleration_time=0.0f, float in_rotation_deceleration_time=0.0f)
Definition: camera.cpp:225
int signature
Definition: ai.h:135
#define NP_VALIDTYPE
Definition: autopilot.h:27
int myrand()
Definition: systemvars.cpp:102
#define NP_MSG_FAIL_HOSTILES
Definition: autopilot.h:55
#define SIF_CORVETTE
Definition: ship.h:908
void get_absolute_wing_pos_autopilot(vec3d *result_pos, object *leader_objp, int wing_index, int formation_object_flag)
Definition: aicode.cpp:11432
int flags
Definition: ship.h:1556
ai_goal ai_goals[MAX_AI_GOALS]
Definition: ship.h:1558
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
#define NP_MSG_FAIL_GLIDING
Definition: autopilot.h:53
float ramp_bias
Definition: autopilot.cpp:44
#define strcpy_s(...)
Definition: safe_strings.h:67
void ai_remove_ship_goal(ai_info *aip, int index)
Definition: aigoals.cpp:231
void send_autopilot_msgID(int msgid)
Definition: autopilot.cpp:1213