FS2_Open
Open source remastering of the Freespace 2 engine
aigoals.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "ai/aigoals.h"
14 #include "globalincs/linklist.h"
15 #include "mission/missionlog.h"
16 #include "mission/missionparse.h"
17 #include "network/multi.h"
18 #include "network/multimsgs.h"
19 #include "object/object.h"
20 #include "object/objectdock.h"
21 #include "object/waypoint.h"
22 #include "parse/sexp.h"
23 #include "playerman/player.h"
24 #include "ship/ship.h"
25 #include "weapon/weapon.h"
26 
27 
28 // all ai goals dealt with in this code are goals that are specified through
29 // sexpressions in the mission file. They are either specified as part of a
30 // ships goals in the #Object section of the mission file, or are created (and
31 // removed) dynamically using the #Events section. Default goal behaviour and
32 // dynamic goals are not handled here.
33 
34 // defines for player issued goal priorities
35 #define PLAYER_PRIORITY_MIN 90
36 #define PLAYER_PRIORITY_SHIP 100
37 #define PLAYER_PRIORITY_WING 95
38 #define PLAYER_PRIORITY_SUPPORT_LOW 10
39 
40 #define MAX_GOAL_PRIORITY 200
41 
42 // define for which goals cause other goals to get purged
43 // Goober5000 - okay, this seems really stupid. If any ship in the mission is assigned a goal
44 // in PURGE_GOALS_ALL_SHIPS, *every* other ship will have certain goals purged. So I added
45 // PURGE_GOALS_ONE_SHIP for goals which should only purge other goals in the one ship.
46 #define PURGE_GOALS_ALL_SHIPS (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
47 #define PURGE_GOALS_ONE_SHIP (AI_GOAL_IGNORE_NEW)
48 
49 // goals given from the player to other ships in the game are also handled in this
50 // code
51 
52 
53 #define AI_GOAL_ACHIEVABLE 1
54 #define AI_GOAL_NOT_ACHIEVABLE 2
55 #define AI_GOAL_NOT_KNOWN 3
56 #define AI_GOAL_SATISFIED 4
57 
61 
63 {
64  { "Attack ship", AI_GOAL_CHASE, 0 },
65  { "Dock", AI_GOAL_DOCK, 0 },
66  { "Waypoints", AI_GOAL_WAYPOINTS, 0 },
67  { "Waypoints once", AI_GOAL_WAYPOINTS_ONCE, 0 },
68  { "Depart", AI_GOAL_WARP, 0 },
69  { "Attack subsys", AI_GOAL_DESTROY_SUBSYSTEM, 0 },
70  { "Form on wing", AI_GOAL_FORM_ON_WING, 0 },
71  { "Undock", AI_GOAL_UNDOCK, 0 },
72  { "Attack wing", AI_GOAL_CHASE_WING, 0 },
73  { "Guard ship", AI_GOAL_GUARD, 0 },
74  { "Disable ship", AI_GOAL_DISABLE_SHIP, 0 },
75  { "Disarm ship", AI_GOAL_DISARM_SHIP, 0 },
76  { "Attack any", AI_GOAL_CHASE_ANY, 0 },
77  { "Ignore ship", AI_GOAL_IGNORE, 0 },
78  { "Ignore ship (new)", AI_GOAL_IGNORE_NEW, 0 },
79  { "Guard wing", AI_GOAL_GUARD_WING, 0 },
80  { "Evade ship", AI_GOAL_EVADE_SHIP, 0 },
81  { "Stay near ship", AI_GOAL_STAY_NEAR_SHIP, 0 },
82  { "keep safe dist", AI_GOAL_KEEP_SAFE_DISTANCE, 0 },
83  { "Rearm ship", AI_GOAL_REARM_REPAIR, 0 },
84  { "Stay still", AI_GOAL_STAY_STILL, 0 },
85  { "Play dead", AI_GOAL_PLAY_DEAD, 0 },
86  { "Attack weapon", AI_GOAL_CHASE_WEAPON, 0 },
87  { "Fly to ship", AI_GOAL_FLY_TO_SHIP, 0 },
88 };
89 
90 int Num_ai_goals = sizeof(Ai_goal_names) / sizeof(ai_goal_list);
91 
92 // AL 11-17-97: A text description of the AI goals. This is used for printing out on the
93 // HUD what a ship's current orders are. If the AI goal doesn't correspond to something that
94 // ought to be printable, then NULL is used.
95 // JAS: Converted to a function in order to externalize the strings
96 const char *Ai_goal_text(int goal)
97 {
98  switch(goal) {
99  case 1:
100  return XSTR( "attack ", 474);
101  case 2:
102  return XSTR( "dock ", 475);
103  case 3:
104  return XSTR( "waypoints", 476);
105  case 4:
106  return XSTR( "waypoints", 476);
107  case 6:
108  return XSTR( "destroy ", 477);
109  case 7:
110  return XSTR( "form on ", 478);
111  case 8:
112  return XSTR( "undock ", 479);
113  case 9:
114  return XSTR( "attack ", 474);
115  case 10:
116  return XSTR( "guard ", 480);
117  case 11:
118  return XSTR( "disable ", 481);
119  case 12:
120  return XSTR( "disarm ", 482);
121  case 15:
122  return XSTR( "guard ", 480);
123  case 16:
124  return XSTR( "evade ", 483);
125  case 19:
126  return XSTR( "rearm ", 484);
127  }
128 
129  // Avoid compiler warning
130  return NULL;
131 }
132 
133 // function to maybe add the form on my wing goal for a player's starting wing. Called when a player wing arrives.
135 {
136  int j;
137 
138  // iterate through the ship_index list of this wing and check for orders. We will do
139  // this for all ships in the wing instead of on a wing only basis in case some ships
140  // in the wing actually have different orders than others
141  for ( j = 0; j < wingp->current_count; j++ ) {
142  ai_info *aip;
143 
144  Assert( wingp->ship_index[j] != -1 ); // get Allender
145 
146  aip = &Ai_info[Ships[wingp->ship_index[j]].ai_index];
147  // don't process Player_ship
148  if ( aip == Player_ai )
149  continue;
150 
151  // it is sufficient enough to check the first goal entry to see if it has a valid goal
152  if ( aip->goals[0].ai_mode == AI_GOAL_NONE ) {
153  // need to add a form on my wing goal here. Ships are always forming on the player's wing.
155  }
156  }
157 }
158 
160 {
161  object *objp;
162  int i;
163 
164  // Check ships in player starting wings. Those ships should follow these rules:
165  // (1) if they have no orders, they should get a form on my wing order
166  // (2) if they have an order, they are free to act on it.
167  //
168  // So basically, we are checking for (1)
169  if ( !Fred_running ) {
170  // MK, 5/9/98: Used to iterate through MAX_STARTING_WINGS, but this was too many ships forming on player.
171  // Goober5000 - MK originally iterated on only the first wing; now we iterate on only the player wing
172  // because the player wing may not be first
173  for ( i = 0; i < MAX_STARTING_WINGS; i++ ) {
174  if (Starting_wings[i] >= 0 && Starting_wings[i] == Player_ship->wingnum) {
175  wing *wingp;
176 
177  wingp = &Wings[Starting_wings[i]];
178 
179  ai_maybe_add_form_goal( wingp );
180 
181  }
182  }
183  }
184 
185  // for every valid ship object, call process_mission_orders to be sure that ships start the
186  // mission following the orders in the mission file right away instead of waiting N seconds
187  // before following them. Do both the created list and the object list for safety
188  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
189  if ( objp->type != OBJ_SHIP )
190  continue;
192  }
193  for ( objp = GET_FIRST(&obj_create_list); objp != END_OF_LIST(&obj_create_list); objp = GET_NEXT(objp) ) {
194  if ( (objp->type != OBJ_SHIP) || Fred_running )
195  continue;
197  }
198 
199  return;
200 }
201 
208 int ai_query_goal_valid( int ship, int ai_goal_type )
209 {
210  int accepted;
211 
212  if (ai_goal_type == AI_GOAL_NONE)
213  return 1; // anything can have no orders.
214 
215  accepted = 0;
216 
217  //WMC - This is much simpler with shiptypes.tbl
218  //Except you have to add the orders into it by hand.
219  int ship_type = Ship_info[Ships[ship].ship_info_index].class_type;
220  if(ship_type > -1)
221  {
222  if(ai_goal_type & Ship_types[ship_type].ai_valid_goals) {
223  accepted = 1;
224  }
225  }
226 
227  return accepted;
228 }
229 
230 // remove an ai goal from it's list. Uses the active_goal member as the goal to remove
232 {
233  // only need to set the ai_mode for the particular goal to AI_GOAL_NONE
234  // reset ai mode to default behavior. Might get changed next time through
235  // ai goal code look
236  Assert ( index >= 0 ); // must have a valid goal
237 
239  aip->goals[index].signature = -1;
240  aip->goals[index].priority = -1;
241  aip->goals[index].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
242 
243  if ( index == aip->active_goal )
244  aip->active_goal = AI_GOAL_NONE;
245 
246  // mwa -- removed this line 8/5/97. Just because we remove a goal doesn't mean to do the default
247  // behavior. We will make the call commented out below in a more reasonable location
248  //ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );
249 }
250 
252 {
253  int i;
254 
255  for (i = 0; i < MAX_AI_GOALS; i++)
256  ai_remove_ship_goal( aip, i ); // resets active_goal and default behavior
257 
258  aip->active_goal = AI_GOAL_NONE; // for good measure
259 
260  // next line moved here on 8/5/97 by MWA
261  // Don't reset player ai (and hence target)
262  // Goober5000 - account for player ai
263  //if ( !((Player_ship != NULL) && (&Ships[aip->shipnum] == Player_ship)) || Player_use_ai ) {
264  if ( (Player_ship == NULL) || (&Ships[aip->shipnum] != Player_ship) || Player_use_ai )
265  {
267  }
268 }
269 
270 void ai_clear_wing_goals( int wingnum )
271 {
272  int i;
273  wing *wingp = &Wings[wingnum];
274  //p_object *objp;
275 
276  // clear the goals for all ships in the wing
277  for (i = 0; i < wingp->current_count; i++) {
278  int num = wingp->ship_index[i];
279 
280  if ( num > -1 )
281  ai_clear_ship_goals( &Ai_info[Ships[num].ai_index] );
282 
283  }
284 
285  // clear out the goals for the wing now
286  for (i = 0; i < MAX_AI_GOALS; i++) {
287  wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
288  wingp->ai_goals[i].signature = -1;
289  wingp->ai_goals[i].priority = -1;
290  wingp->ai_goals[i].flags = 0;
291  }
292 
293 
294 }
295 
296 // routine which marks a wing goal as being complete. We get the wingnum and a pointer to the goal
297 // structure of the goal to be removed. This process is slightly tricky since some member of the wing
298 // might be pursuing a different goal. We will have to compare based on mode, submode, priority,
299 // and name.. This routine is only currently called from waypoint code!!!
300 void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
301 {
302  int mode, submode, priority, i;
303  char *name;
304  ai_goal *aigp;
305  wing *wingp;
306 
307  wingp = &Wings[wingnum];
308 
309  // set up locals for faster access.
310  mode = remove_goalp->ai_mode;
311  submode = remove_goalp->ai_submode;
312  priority = remove_goalp->priority;
313  name = remove_goalp->target_name;
314 
315  Assert ( name ); // should not be NULL!!!!
316 
317  // remove the goal from all the ships currently in the wing
318  for (i = 0; i < wingp->current_count; i++ ) {
319  int num, j;
320  ai_info *aip;
321 
322  num = wingp->ship_index[i];
323  Assert ( num >= 0 );
324  aip = &Ai_info[Ships[num].ai_index];
325  for ( j = 0; j < MAX_AI_GOALS; j++ ) {
326  aigp = &(aip->goals[j]);
327 
328  // don't need to worry about these types of goals since they can't possibly be a goal we are looking for.
329  if ( (aigp->ai_mode == AI_GOAL_NONE) || !aigp->target_name )
330  continue;
331 
332  if ( (aigp->ai_mode == mode) && (aigp->ai_submode == submode) && (aigp->priority == priority) && !stricmp(name, aigp->target_name) ) {
333  ai_remove_ship_goal( aip, j );
334  ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] ); // do the default behavior
335  break; // we are all done
336  }
337  }
338  }
339 
340  // now remove the goal from the wing
341  for (i = 0; i < MAX_AI_GOALS; i++ ) {
342  aigp = &(wingp->ai_goals[i]);
343  if ( (aigp->ai_mode == AI_GOAL_NONE) || !aigp->target_name )
344  continue;
345 
346  if ( (aigp->ai_mode == mode) && (aigp->ai_submode == submode) && (aigp->priority == priority) && !stricmp(name, aigp->target_name) ) {
347  wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
348  wingp->ai_goals[i].signature = -1;
349  wingp->ai_goals[i].priority = -1;
350  wingp->ai_goals[i].flags = 0;
351  break;
352  }
353  }
354 
355 }
356 
357 // routine which is called with an ai object complete it's goal. Do some action
358 // based on the goal what was just completed
359 
361 {
362  // if the active goal is dynamic or none, just return. (AI_GOAL_NONE is probably an error, but
363  // I don't think that this is a problem)
364  if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) )
365  return;
366 
367  ai_remove_ship_goal( aip, aip->active_goal );
368  ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] ); // do the default behavior
369 
370 }
371 
372 // function to prune out goals which are no longer valid, based on a goal pointer passed in.
373 // for instance, if we get passed a goal of "disable X", then any goals in the given goal array
374 // which are destroy, etc, should get removed. goal list is the list of goals to purge. It is
375 // always MAX_AI_GOALS in length. This function will only get called when the goal which causes
376 // purging becomes valid.
377 void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *aip, int ai_wingnum )
378 {
379  int i, j;
380  ai_goal *purge_goal;
381  char *name;
382  int mode, ship_index, wingnum;
383 
384  // get locals for easer access
385  name = aigp->target_name;
386  mode = aigp->ai_mode;
387 
388  // these goals cannot be associated to wings, but can to a ship in a wing. So, we should find out
389  // if the ship is in a wing so we can purge goals which might operate on that wing
390  ship_index = ship_name_lookup(name);
391  if ( ship_index == -1 ) {
392  Int3(); // get allender -- this is sort of odd
393  return;
394  }
395  wingnum = Ships[ship_index].wingnum;
396 
397  purge_goal = goal_list;
398  for ( i = 0; i < MAX_AI_GOALS; purge_goal++, i++ ) {
399  int purge_ai_mode, purge_wing;
400 
401  purge_ai_mode = purge_goal->ai_mode;
402 
403  // don't need to process AI_GOAL_NONE
404  if ( purge_ai_mode == AI_GOAL_NONE )
405  continue;
406 
407  // goals must operate on something to be purged.
408  if ( purge_goal->target_name == NULL )
409  continue;
410 
411  // determine if the purge goal is acting either on the ship or the ship's wing.
412  purge_wing = wing_name_lookup( purge_goal->target_name, 1 );
413 
414  // if the target of the purge goal is a ship (purge_wing will be -1), then if the names
415  // don't match, we can continue; if the wing is valid, don't process if the wing numbers
416  // are different.
417  if ( purge_wing == -1 ) {
418  if ( stricmp(purge_goal->target_name, name ) )
419  continue;
420  } else if ( purge_wing != wingnum )
421  continue;
422 
423  switch (mode)
424  {
425  // ignore goals should get rid of any kind of attack goal
426  case AI_GOAL_IGNORE:
427  case AI_GOAL_IGNORE_NEW:
429  purge_goal->flags |= AIGF_PURGE;
430  break;
431 
432  // disarm/disable goals should remove attacks from certain ships types
433  case AI_GOAL_DISARM_SHIP:
435  if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING) ) {
436  int ai_ship_type;
437 
438  // for wings we grab the ship type of the wing leader
439  if (ai_wingnum >= 0) {
440  ai_ship_type = Ship_info[Ships[Wings[ai_wingnum].special_ship].ship_info_index].class_type;
441  }
442  // otherwise we simply grab it from the ship itself
443  else {
444  Assert(aip != NULL);
445  ai_ship_type = Ship_info[Ships[aip->shipnum].ship_info_index].class_type;
446  }
447 
448  // grab the ship type of the ship that is being disarmed/disabled
449  ship_type_info *crippled_ships_type = &Ship_types[Ship_info[Ships[ship_index].ship_info_index].class_type];
450 
451  // work through all the ship types which to see if the class matching our ai ship must ignore the ship
452  // being disarmed/disabled
453  for ( j=0 ; j < (int)crippled_ships_type->ai_cripple_ignores.size(); j++) {
454  if (crippled_ships_type->ai_cripple_ignores[j] == ai_ship_type) {
455  purge_goal->flags |= AIGF_PURGE;
456  }
457  }
458  }
459  break;
460  }
461  }
462 }
463 
464 // function to purge the goals of *all* ships in the game based on the incoming goal structure
466 {
467  int i;
468  ship_obj *sop;
469 
470  // only purge goals if a new goal is one of the types in next statement
471  if (!(aigp->ai_mode & PURGE_GOALS_ALL_SHIPS))
472  return;
473 
474  for (sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop))
475  {
476  ship *shipp = &Ships[Objects[sop->objnum].instance];
477  ai_goal_purge_invalid_goals(aigp, Ai_info[shipp->ai_index].goals, &Ai_info[shipp->ai_index], -1);
478  }
479 
480  // we must do the same for the wing goals
481  for (i = 0; i < Num_wings; i++)
482  {
483  ai_goal_purge_invalid_goals(aigp, Wings[i].ai_goals, NULL, i);
484  }
485 }
486 
487 // Goober5000
488 int ai_goal_find_dockpoint(int shipnum, int dock_type)
489 {
490  int dock_index = -1;
491  int loop_count = 0;
492 
493  ship *shipp = &Ships[shipnum];
494  object *objp = &Objects[shipp->objnum];
495 
496  // only check 100 points for sanity's sake
497  while (loop_count < 100)
498  {
499  dock_index = model_find_dock_index(Ship_info[shipp->ship_info_index].model_num, dock_type, dock_index+1);
500 
501  // not found?
502  if (dock_index == -1)
503  {
504  if (loop_count == 0)
505  {
506  // first time around... there are no slots fitting this description
507  return -1;
508  }
509  else
510  {
511  // every slot is full
512  break;
513  }
514  }
515 
516  // we've found something... check if it's occupied
517  if (dock_find_object_at_dockpoint(objp, dock_index) == NULL)
518  {
519  // not occupied... yay, we've found an index
520  return dock_index;
521  }
522 
523  // keep track
524  loop_count++;
525  }
526 
527  // insanity?
528  if (loop_count >= 100)
529  Warning(LOCATION, "Too many iterations while looking for a dockpoint on %s.\n", shipp->ship_name);
530 
531  // if we're here, just return the first dockpoint
532  return model_find_dock_index(Ship_info[shipp->ship_info_index].model_num, dock_type);
533 }
534 
535 // function to fix up dock point references for objects.
536 // passed are the pointer to goal we are working with. aip is the ai_info pointer
537 // of the ship with the order. aigp is a pointer to the goal (of aip) of which we are
538 // fixing up the docking points
540 {
541  int shipnum, docker_index, dockee_index;
542 
543  Assert ( aip->shipnum != -1 );
544  shipnum = ship_name_lookup( aigp->target_name );
545  Assertion ( shipnum != -1, "Couldn't find ai goal's target_name (%s); get a coder!\n", aigp->target_name );
546  docker_index = -1;
547  dockee_index = -1;
548 
549  //WMC - This gets a bit complex with shiptypes.tbl
550  //Basically this finds the common dockpoint.
551  //For this, the common flags for aip's active point (ie point it wants to dock with)
552  //and aigp's passive point (point it wants to be docked with) are combined
553  //and the common ones are used, in order of precedence.
554  //Yes, it does sound vaguely like a double-entree.
555 
556  int aip_type_dock = Ship_info[Ships[aip->shipnum].ship_info_index].class_type;
557  int aigp_type_dock = Ship_info[Ships[shipnum].ship_info_index].class_type;
558 
559  int common_docks = 0;
560 
561  if(aip_type_dock > -1) {
562  aip_type_dock = Ship_types[aip_type_dock].ai_active_dock;
563  } else {
564  aip_type_dock = 0;
565  }
566 
567  if(aigp_type_dock > -1) {
568  aigp_type_dock = Ship_types[aigp_type_dock].ai_passive_dock;
569  } else {
570  aigp_type_dock = 0;
571  }
572 
573  common_docks = aip_type_dock & aigp_type_dock;
574 
575  //Now iterate through types.
576  for(int i = 0; i < Num_dock_type_names; i++)
577  {
578  if(common_docks & Dock_type_names[i].def) {
579  docker_index = ai_goal_find_dockpoint(aip->shipnum, Dock_type_names[i].def);
580  dockee_index = ai_goal_find_dockpoint(shipnum, Dock_type_names[i].def);
581  break;
582  }
583  }
584 
585  // look for docking points of the appriopriate type. Use cargo docks for cargo ships.
586  /*
587  if (Ship_info[Ships[shipnum].ship_info_index].flags & SIF_CARGO) {
588  docker_index = ai_goal_find_dockpoint(aip->shipnum, DOCK_TYPE_CARGO);
589  dockee_index = ai_goal_find_dockpoint(shipnum, DOCK_TYPE_CARGO);
590  } else if (Ship_info[Ships[aip->shipnum].ship_info_index].flags & SIF_SUPPORT) {
591  docker_index = ai_goal_find_dockpoint(aip->shipnum, DOCK_TYPE_REARM);
592  dockee_index = ai_goal_find_dockpoint(shipnum, DOCK_TYPE_REARM);
593  }
594  */
595 
596  // if we didn't find dockpoints above, then we should just look for generic docking points
597  if ( docker_index == -1 )
598  docker_index = ai_goal_find_dockpoint(aip->shipnum, DOCK_TYPE_GENERIC);
599  if ( dockee_index == -1 )
600  dockee_index = ai_goal_find_dockpoint(shipnum, DOCK_TYPE_GENERIC);
601 
602  aigp->docker.index = docker_index;
603  aigp->dockee.index = dockee_index;
605 }
606 
607 // these functions deal with adding goals sent from the player. They are slightly different
608 // from the mission goals (i.e. those goals which come from events) in that we don't
609 // use sexpressions for goals from the player...so we enumerate all the parameters
610 
611 void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp )
612 {
613  Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
614 
615  aigp->time = Missiontime;
616  aigp->type = type; // from player for sure -- could be to ship or to wing
617  aigp->ai_mode = mode; // major mode for this goal
618  aigp->ai_submode = submode; // could mean different things depending on mode
619 
620  if ( mode == AI_GOAL_WARP ) {
621  if (submode >= 0) {
622  aigp->wp_list = find_waypoint_list_at_index(submode);
623  Assert(aigp->wp_list != NULL);
624  } else {
625  aigp->wp_list = NULL;
626  }
627  }
628 
629  if ( mode == AI_GOAL_CHASE_WEAPON ) {
630  aigp->target_instance = submode; // submode contains the instance of the weapon
631  aigp->target_signature = Objects[Weapons[submode].objnum].signature;
632  } else {
633  aigp->target_instance = -1;
634  aigp->target_signature = -1;
635  }
636 
637  if ( target_name != NULL )
638  aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
639  else
640  aigp->target_name = NULL;
641 
642  // special case certain orders from player so that ships continue to do the right thing
643 
644  // make priority for these two support ship orders low so that they will prefer repairing
645  // a ship over staying near a ship.
646  if ( (mode == AI_GOAL_STAY_NEAR_SHIP) || (mode == AI_GOAL_KEEP_SAFE_DISTANCE) )
648 
649  // Goober5000 - same with form-on-wing, since it's a type of staying near
650  else if ( mode == AI_GOAL_FORM_ON_WING )
652 
653  else if ( aigp->type == AIG_TYPE_PLAYER_WING )
654  aigp->priority = PLAYER_PRIORITY_WING; // player wing goals not as high as ship goals
655  else
657 }
658 
659 // Goober5000 - Modified this function for clarity and to avoid returning the active goal's index
660 // as the empty slot. This avoids overwriting the active goal while it's being executed. So far
661 // the only time I've noticed it being a problem is during a rare situation where more than five
662 // friendlies want to rearm at the same time. The support ship forgets what it's doing and flies
663 // off to repair somebody while still docked. I reproduced this with retail, so it's not a bug in
664 // my new docking code. :)
665 int ai_goal_find_empty_slot( ai_goal *goals, int active_goal )
666 {
667  int gindex, oldest_index;
668 
669  oldest_index = -1;
670  for ( gindex = 0; gindex < MAX_AI_GOALS; gindex++ )
671  {
672  // get the index for the first unused goal
673  if (goals[gindex].ai_mode == AI_GOAL_NONE)
674  return gindex;
675 
676  // if this is the active goal, don't consider it for pre-emption!!
677  if (gindex == active_goal)
678  continue;
679 
680  // store the index of the oldest goal
681  if (oldest_index < 0)
682  oldest_index = gindex;
683  else if (goals[gindex].time < goals[oldest_index].time)
684  oldest_index = gindex;
685  }
686 
687  // if we didn't find an empty slot, use the oldest goal's slot
688  return oldest_index;
689 }
690 
691 int ai_goal_num(ai_goal *goals)
692 {
693  int gindex = 0;
694  int num_goals = 0;
695  for(gindex = 0; gindex < MAX_AI_GOALS; gindex++)
696  {
697  if(goals[gindex].ai_mode != AI_GOAL_NONE)
698  num_goals++;
699  }
700 
701  return num_goals;
702 }
703 
704 
705 void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, char *target_name, ai_goal *aigp )
706 {
707  Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
708 
709  aigp->time = Missiontime;
710  aigp->type = type; // from player for sure -- could be to ship or to wing
711  aigp->ai_mode = mode; // major mode for this goal
712  aigp->ai_submode = submode; // could mean different things depending on mode
713 
714  if ( mode == AI_GOAL_WARP )
715  aigp->wp_list = NULL;
716 
717  if ( mode == AI_GOAL_CHASE_WEAPON ) {
718  aigp->target_instance = submode; // submode contains the instance of the weapon
719  aigp->target_signature = Objects[Weapons[submode].objnum].signature;
720  }
721 
722  if ( target_name != NULL )
723  aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
724  else
725  aigp->target_name = NULL;
726 
727  aigp->priority = priority;
728 }
729 
730 void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip)
731 {
732  int empty_index;
733  ai_goal *aigp;
734 
735  empty_index = ai_goal_find_empty_slot(aip->goals, aip->active_goal);
736  aigp = &aip->goals[empty_index];
737 
738  //WMC - hack to get docking setup correctly
739  if ( mode == AI_GOAL_DOCK ) {
740  aigp->docker.name = Ships[aip->shipnum].ship_name;
741  aigp->dockee.name = shipname;
742  aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
743  }
744  ai_add_goal_sub_scripting(AIG_TYPE_PLAYER_SHIP, mode, submode, priority, shipname, aigp);
745 
746  if ( (mode == AI_GOAL_REARM_REPAIR) || ((mode == AI_GOAL_DOCK) && (submode == AIS_DOCK_0)) ) {
747  ai_goal_fixup_dockpoints( aip, aigp );
748  }
749 
750  aigp->signature = Ai_goal_signature++;
751 }
752 
753 // adds a goal from a player to the given ship's ai_info structure. 'type' tells us if goal
754 // is issued to ship or wing (from player), mode is AI_GOAL_*. submode is the submode the
755 // ship should go into. shipname is the object of the action. aip is the ai_info pointer
756 // of the ship receiving the order
757 void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip )
758 {
759  int empty_index;
760  ai_goal *aigp;
761 
762  empty_index = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
763 
764  // get a pointer to the goal structure
765  aigp = &aip->goals[empty_index];
766  ai_add_goal_sub_player( type, mode, submode, shipname, aigp );
767 
768  // if the goal is to dock, then we must determine which dock points on the two ships to use.
769  // If the target of the dock is a cargo type container, then we should use DOCK_TYPE_CARGO
770  // on both ships. Code is here instead of in ai_add_goal_sub_player() since a dock goal
771  // should only occur to a specific ship.
772 
773  if ( (mode == AI_GOAL_REARM_REPAIR) || ((mode == AI_GOAL_DOCK) && (submode == AIS_DOCK_0)) ) {
774  ai_goal_fixup_dockpoints( aip, aigp );
775  }
776 
777  aigp->signature = Ai_goal_signature++;
778 
779 }
780 
781 // adds a goal from the player to the given wing (which in turn will add it to the proper
782 // ships in the wing
783 void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum )
784 {
785  int i, empty_index;
786  wing *wingp = &Wings[wingnum];
787 
788  // add the ai goal for any ship that is currently arrived in the game.
789  if ( !Fred_running ) { // only add goals to ships if fred isn't running
790  for (i = 0; i < wingp->current_count; i++) {
791  int num = wingp->ship_index[i];
792  if ( num == -1 ) // ship must have been destroyed or departed
793  continue;
794  ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index] );
795  }
796  }
797 
798  // add the sexpression index into the wing's list of goal sexpressions if
799  // there are more waves to come. We use the same method here as when adding a goal to
800  // a ship -- find the first empty entry. If none exists, take the oldest entry and replace it.
801  empty_index = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
802  ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index] );
803 }
804 
805 
806 // common routine to add a sexpression mission goal to the appropriate goal structure.
807 void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp, char *actor_name )
808 {
809  int node, dummy, op;
810  char *text;
811 
812  Assert ( Sexp_nodes[sexp].first != -1 );
813  node = Sexp_nodes[sexp].first;
814  text = CTEXT(node);
815 
816  aigp->signature = Ai_goal_signature++;
817 
818  aigp->target_name = NULL;
819  aigp->time = Missiontime;
820  aigp->type = type;
821  aigp->flags = 0;
822 
823  op = get_operator_const( text );
824 
825  switch (op) {
826 
828  case OP_AI_WAYPOINTS: {
829  int ref_type;
830 
831  ref_type = Sexp_nodes[CDR(node)].subtype;
832  if (ref_type == SEXP_ATOM_STRING) { // referenced by name
833  // save the waypoint path name -- the list will get resolved when the goal is checked
834  // for achievability.
835  aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
836  aigp->wp_list = NULL;
837 
838  } else
839  Int3();
840 
841  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
842  aigp->ai_mode = AI_GOAL_WAYPOINTS;
843  if ( op == OP_AI_WAYPOINTS_ONCE )
845  break;
846  }
847 
851  // store the name of the subsystem in the docker.name field for now -- this field must get
852  // fixed up when the goal is valid since we need to locate the subsystem on the ship's model
853  aigp->docker.name = ai_get_goal_target_name(CTEXT(CDR(CDR(node))), &dummy);
855  aigp->priority = atoi( CTEXT(CDR(CDR(CDR(node)))) );
856  break;
857 
858  case OP_AI_DISABLE_SHIP:
861  aigp->ai_submode = -SUBSYSTEM_ENGINE;
862  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
863  break;
864 
865  case OP_AI_DISARM_SHIP:
868  aigp->ai_submode = -SUBSYSTEM_TURRET;
869  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
870  break;
871 
872  case OP_AI_WARP_OUT:
873  aigp->ai_mode = AI_GOAL_WARP;
874  aigp->priority = atoi( CTEXT(CDR(node)) );
875  break;
876 
877  // the following goal is obsolete, but here for compatibility
878  case OP_AI_WARP:
879  aigp->ai_mode = AI_GOAL_WARP;
880  aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
881  aigp->wp_list = NULL;
882  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
883  break;
884 
885  case OP_AI_UNDOCK:
886  aigp->priority = atoi( CTEXT(CDR(node)) );
887 
888  // Goober5000 - optional undock with something
889  if (CDR(CDR(node)) != -1)
891  else
892  aigp->target_name = NULL;
893 
894  aigp->ai_mode = AI_GOAL_UNDOCK;
895  aigp->ai_submode = AIS_UNDOCK_0;
896  break;
897 
898  case OP_AI_STAY_STILL:
899  aigp->ai_mode = AI_GOAL_STAY_STILL;
900  aigp->target_name = ai_get_goal_target_name(CTEXT(CDR(node)), &aigp->target_name_index); // waypoint path name;
901  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
902  break;
903 
904  case OP_AI_DOCK:
906  aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
907  aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
908  aigp->flags &= ~AIGF_DOCK_INDEXES_VALID;
909  aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
910 
911  aigp->ai_mode = AI_GOAL_DOCK;
912  aigp->ai_submode = AIS_DOCK_0; // be sure to set the submode
913  break;
914 
915  case OP_AI_CHASE_ANY:
916  aigp->priority = atoi( CTEXT(CDR(node)) );
917  aigp->ai_mode = AI_GOAL_CHASE_ANY;
918  break;
919 
920  case OP_AI_PLAY_DEAD:
921  aigp->priority = atoi( CTEXT(CDR(node)) );
922  aigp->ai_mode = AI_GOAL_PLAY_DEAD;
923  break;
924 
926  aigp->priority = atoi( CTEXT(CDR(node)) );
928  break;
929 
930  case OP_AI_FORM_ON_WING:
931  aigp->priority = 99;
934  break;
935 
936  case OP_AI_CHASE:
937  case OP_AI_GUARD:
938  case OP_AI_GUARD_WING:
939  case OP_AI_CHASE_WING:
940  case OP_AI_EVADE_SHIP:
942  case OP_AI_IGNORE:
943  case OP_AI_IGNORE_NEW:
945  aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
946 
947  if ( op == OP_AI_CHASE ) {
948  aigp->ai_mode = AI_GOAL_CHASE;
949 
950  // in the case of ai_chase (and ai_guard) we must do a wing_name_lookup on the name
951  // passed here to see if we could be chasing a wing. Hoffoss and I have consolidated
952  // sexpression operators which makes this step necessary
953  if ( wing_name_lookup(aigp->target_name, 1) != -1 )
954  aigp->ai_mode = AI_GOAL_CHASE_WING;
955 
956  } else if ( op == OP_AI_GUARD ) {
957  aigp->ai_mode = AI_GOAL_GUARD;
958  if ( wing_name_lookup(aigp->target_name, 1) != -1 )
959  aigp->ai_mode = AI_GOAL_GUARD_WING;
960 
961  } else if ( op == OP_AI_EVADE_SHIP ) {
962  aigp->ai_mode = AI_GOAL_EVADE_SHIP;
963 
964  } else if ( op == OP_AI_GUARD_WING ) {
965  aigp->ai_mode = AI_GOAL_GUARD_WING;
966  } else if ( op == OP_AI_CHASE_WING ) {
967  aigp->ai_mode = AI_GOAL_CHASE_WING;
968  } else if ( op == OP_AI_STAY_NEAR_SHIP ) {
970  } else if ( op == OP_AI_IGNORE ) {
971  aigp->ai_mode = AI_GOAL_IGNORE;
972  } else if ( op == OP_AI_IGNORE_NEW ) {
973  aigp->ai_mode = AI_GOAL_IGNORE_NEW;
974  } else
975  Int3(); // this is impossible
976 
977  break;
978 
979  default:
980  Int3(); // get ALLENDER -- invalid ai-goal specified for ai object!!!!
981  }
982 
983  if ( aigp->priority > MAX_GOAL_PRIORITY ) {
984  nprintf (("AI", "bashing sexpression priority of goal %s from %d to %d.\n", text, aigp->priority, MAX_GOAL_PRIORITY));
985  aigp->priority = MAX_GOAL_PRIORITY;
986  }
987 
988  // Goober5000 - we now have an extra optional chase argument to allow chasing our own team
989  if ( op == OP_AI_CHASE || op == OP_AI_CHASE_WING || op == OP_AI_DISABLE_SHIP || op == OP_AI_DISARM_SHIP ) {
990  if ((CDDDR(node) != -1) && is_sexp_true(CDDDR(node)))
991  aigp->flags |= AIGF_TARGET_OWN_TEAM;
992  }
993  if ( op == OP_AI_DESTROY_SUBSYS ) {
994  if ((CDDDDR(node) != -1) && is_sexp_true(CDDDDR(node)))
995  aigp->flags |= AIGF_TARGET_OWN_TEAM;
996  }
997 
998  // Goober5000 - since none of the goals act on the actor,
999  // don't assign the goal if the actor's goal target is itself
1000  if (aigp->target_name != NULL && !strcmp(aigp->target_name, actor_name))
1001  {
1002  // based on ai_remove_ship_goal, these seem to be the only statements
1003  // necessary to cause this goal to "never have been assigned"
1004  aigp->ai_mode = AI_GOAL_NONE;
1005  aigp->signature = -1;
1006  aigp->priority = -1;
1007  aigp->flags = 0;
1008  }
1009 }
1010 
1011 /* Find the index of the goal in the passed ai_goal array
1012  * Call something like ai_find_goal_index( aiip->goals, AIM_* );
1013  * Pass -1 in submode to ignore ai_submode when searching
1014  * Pass -1 in priority to ignore priority when searching
1015  * Returns -1 if not found, or [0, MAX_AI_GOALS)
1016  */
1017 int ai_find_goal_index( ai_goal* aigp, int mode, int submode, int priority )
1018 {
1019  Assert( aigp != NULL );
1020  for ( int i = 0; i < MAX_AI_GOALS; i++ )
1021  {
1022  if ( aigp[ i ].ai_mode == mode &&
1023  ( submode == -1 || aigp[ i ].ai_submode == submode ) &&
1024  ( priority == -1 || aigp[ i ].priority == priority ) )
1025  {
1026  return i;
1027  }
1028  }
1029 
1030  return -1;
1031 }
1032 
1033 /* Remove a goal from the given goals structure
1034  * Returns the index of the goal that it clears out.
1035  * This is importnat so that if active_goal == index you can set AI_GOAL_NONE
1036  */
1038 {
1039  /* Sanity check */
1040  Assert( Sexp_nodes[ sexp ].first != -1 );
1041 
1042  /* The bits we're searching for in the goals list */
1043  int priority = -1;
1044 
1045  int goalmode = -1;
1046  int goalsubmode = -1;
1047 
1048  /* Sexp node */
1049  int node = -1;
1050  /* The operator to use */
1051  char* op_text = NULL;
1052  int op = -1;
1053 
1054  node = Sexp_nodes[ sexp ].first;
1055  op_text = CTEXT( node );
1056  op = get_operator_const( op_text );
1057 
1058  /* We now need to determine what the mode and submode values are*/
1059  switch( op )
1060  {
1061  case OP_AI_WAYPOINTS_ONCE:
1062  goalmode = AI_GOAL_WAYPOINTS_ONCE;
1063  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1064  break;
1065  case OP_AI_WAYPOINTS:
1066  goalmode = AI_GOAL_WAYPOINTS;
1067  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1068  break;
1069  case OP_AI_DESTROY_SUBSYS:
1070  goalmode = AI_GOAL_DESTROY_SUBSYSTEM;
1071  priority = ( CDR( CDR( CDR(node) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( node ) ) ) ) ) : -1;
1072  break;
1073  case OP_AI_DISABLE_SHIP:
1074  goalmode = AI_GOAL_DISABLE_SHIP;
1075  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1076  break;
1077  case OP_AI_DISARM_SHIP:
1078  goalmode = AI_GOAL_DISABLE_SHIP;
1079  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1080  break;
1081  case OP_AI_WARP_OUT:
1082  goalmode = AI_GOAL_WARP;
1083  priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
1084  break;
1085  case OP_AI_WARP:
1086  goalmode = AI_GOAL_WARP;
1087  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1088  break;
1089  case OP_AI_UNDOCK:
1090  goalmode = AI_GOAL_UNDOCK;
1091  goalsubmode = AIS_UNDOCK_0;
1092  priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
1093  break;
1094  case OP_AI_STAY_STILL:
1095  goalmode = AI_GOAL_STAY_STILL;
1096  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1097  break;
1098  case OP_AI_DOCK:
1099  goalmode = AI_GOAL_DOCK;
1100  goalsubmode = AIS_DOCK_0;
1101  priority = ( CDR( CDR( CDR( CDR(node) ) ) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( CDR( CDR( node ) ) ) ) ) ) : -1;
1102  break;
1103  case OP_AI_CHASE_ANY:
1104  goalmode = AI_GOAL_CHASE_ANY;
1105  priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
1106  break;
1107  case OP_AI_PLAY_DEAD:
1108  goalmode = AI_GOAL_PLAY_DEAD;
1109  priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
1110  break;
1112  priority = ( CDR(node) >= 0 ) ? atoi( CTEXT( CDR( node ) ) ) : -1;
1113  goalmode = AI_GOAL_KEEP_SAFE_DISTANCE;
1114  break;
1115  case OP_AI_CHASE:
1116  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1117  if ( wing_name_lookup( CTEXT( CDR( node ) ), 1 ) != -1 )
1118  goalmode = AI_GOAL_CHASE_WING;
1119  else
1120  goalmode = AI_GOAL_CHASE;
1121  break;
1122  case OP_AI_GUARD:
1123  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1124  if ( wing_name_lookup( CTEXT( CDR( node ) ), 1 ) != -1 )
1125  goalmode = AI_GOAL_GUARD_WING;
1126  else
1127  goalmode = AI_GOAL_GUARD;
1128  break;
1129  case OP_AI_GUARD_WING:
1130  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1131  goalmode = AI_GOAL_GUARD_WING;
1132  break;
1133  case OP_AI_CHASE_WING:
1134  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1135  goalmode = AI_GOAL_CHASE_WING;
1136  break;
1137  case OP_AI_EVADE_SHIP:
1138  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1139  goalmode = AI_GOAL_EVADE_SHIP;
1140  break;
1141  case OP_AI_STAY_NEAR_SHIP:
1142  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1143  goalmode = AI_GOAL_STAY_NEAR_SHIP;
1144  break;
1145  case OP_AI_IGNORE:
1146  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1147  goalmode = AI_GOAL_IGNORE;
1148  break;
1149  case OP_AI_IGNORE_NEW:
1150  priority = ( CDR( CDR(node) ) >= 0 ) ? atoi( CTEXT( CDR( CDR( node ) ) ) ) : -1;
1151  goalmode = AI_GOAL_IGNORE_NEW;
1152  break;
1153  default:
1154  Int3( );
1155  break;
1156  };
1157 
1158  /* Attempt to find the goal */
1159  int goalindex = ai_find_goal_index( aigp, goalmode, goalsubmode, priority );
1160 
1161  if ( goalindex == -1 )
1162  return -1; /* no more to do; */
1163 
1164  /* Clear out the contents of the goal. We can't use ai_remove_ship_goal since it needs ai_info and
1165  * we've only got ai_goals */
1166  aigp[goalindex].ai_mode = AI_GOAL_NONE;
1167  aigp[goalindex].signature = -1;
1168  aigp[goalindex].priority = -1;
1169  aigp[goalindex].flags = 0; // must reset the flags since not doing so will screw up goal sorting.
1170 
1171  return goalindex;
1172 }
1173 
1174 // code to add ai goals to wings.
1175 void ai_remove_wing_goal_sexp(int sexp, int wingnum)
1176 {
1177  int i;
1178  int goalindex = -1;
1179  wing *wingp = &Wings[wingnum];
1180 
1181  // add the ai goal for any ship that is currently arrived in the game (only if fred isn't running)
1182  if ( !Fred_running ) {
1183  for (i = 0; i < wingp->current_count; i++) {
1184  int num = wingp->ship_index[i];
1185  if ( num == -1 ) // ship must have been destroyed or departed
1186  continue;
1187  goalindex = ai_remove_goal_sexp_sub( sexp, Ai_info[Ships[num].ai_index].goals );
1188  if ( Ai_info[Ships[num].ai_index].active_goal == goalindex )
1190  }
1191  }
1192 
1193  if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running)
1194  {
1195  ai_remove_goal_sexp_sub( sexp, wingp->ai_goals );
1196  }
1197 }
1198 
1199 // adds an ai goal for an individual ship
1200 // type determines who has issues this ship a goal (i.e. the player/mission event/etc)
1201 void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip )
1202 {
1203  int gindex;
1204 
1205  gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
1206  ai_add_goal_sub_sexp( sexp, type, &aip->goals[gindex], Ships[aip->shipnum].ship_name );
1207 }
1208 
1209 // code to add ai goals to wings.
1210 void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
1211 {
1212  int i;
1213  wing *wingp = &Wings[wingnum];
1214 
1215  // add the ai goal for any ship that is currently arrived in the game (only if fred isn't running)
1216  if ( !Fred_running ) {
1217  for (i = 0; i < wingp->current_count; i++) {
1218  int num = wingp->ship_index[i];
1219  if ( num == -1 ) // ship must have been destroyed or departed
1220  continue;
1221  ai_add_ship_goal_sexp( sexp, type, &Ai_info[Ships[num].ai_index] );
1222  }
1223  }
1224 
1225  // add the sexpression index into the wing's list of goal sexpressions if
1226  // there are more waves to come
1227  if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running) {
1228  int gindex;
1229 
1230  gindex = ai_goal_find_empty_slot( wingp->ai_goals, -1 );
1231  ai_add_goal_sub_sexp( sexp, type, &wingp->ai_goals[gindex], wingp->name );
1232  }
1233 }
1234 
1235 // function for internal code to add a goal to a ship. Needed when the AI finds itself in a situation
1236 // that it must get out of by issuing itself an order.
1237 //
1238 // objp is the object getting the goal
1239 // goal_type is one of AI_GOAL_*
1240 // other_name is a character string objp might act on (for docking, this is a shipname, for guarding
1241 // this name can be a shipname or a wingname)
1242 // docker_point and dockee_point are used for the AI_GOAL_DOCK command to tell two ships where to dock
1243 // immediate means to process this order right away
1244 void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate )
1245 {
1246  int gindex;
1247  ai_goal *aigp;
1248 
1249 #ifndef NDEBUG
1250  // Goober5000 - none of the goals act on the actor, as in ai_add_goal_sub_sexp
1251  if (!strcmp(name, Ships[aip->shipnum].ship_name))
1252  {
1253  // not good
1254  Int3();
1255  return;
1256  }
1257 #endif
1258 
1259  // find an empty slot to put this goal in.
1260  gindex = ai_goal_find_empty_slot( aip->goals, aip->active_goal );
1261  aigp = &(aip->goals[gindex]);
1262 
1263  aigp->signature = Ai_goal_signature++;
1264 
1265  aigp->time = Missiontime;
1266  aigp->type = AIG_TYPE_DYNAMIC;
1267  aigp->flags = AIGF_GOAL_OVERRIDE;
1268 
1269  switch ( goal_type ) {
1270 
1271 /* Goober5000 - this seems to not be used
1272  case AI_GOAL_DOCK:
1273  aigp->ship_name = name;
1274  aigp->docker.index = docker_point;
1275  aigp->dockee.index = dockee_point;
1276  aigp->priority = 100;
1277 
1278  aigp->ai_mode = AI_GOAL_DOCK;
1279  aigp->ai_submode = AIS_DOCK_0; // be sure to set the submode
1280  break;
1281 */
1282 
1283  case AI_GOAL_UNDOCK:
1284  aigp->target_name = name;
1285  aigp->priority = MAX_GOAL_PRIORITY;
1286  aigp->ai_mode = AI_GOAL_UNDOCK;
1287  aigp->ai_submode = AIS_UNDOCK_0;
1288  break;
1289 
1290 /* Goober5000 - this seems to not be used
1291  case AI_GOAL_GUARD:
1292  if ( wing_name_lookup(name, 1) != -1 )
1293  aigp->ai_mode = AI_GOAL_GUARD_WING;
1294  else
1295  aigp->ai_mode = AI_GOAL_GUARD;
1296  aigp->priority = PLAYER_PRIORITY_MIN-1; // make the priority always less than what the player's is
1297  break;
1298 */
1299 
1300  case AI_GOAL_REARM_REPAIR:
1301  aigp->ai_mode = AI_GOAL_REARM_REPAIR;
1302  aigp->ai_submode = 0;
1303  aigp->target_name = name;
1304  aigp->priority = PLAYER_PRIORITY_MIN-1; // make the priority always less than what the player's is
1305  aigp->flags &= ~AIGF_GOAL_OVERRIDE; // don't override this goal. rearm repair requests should happen in order
1306  ai_goal_fixup_dockpoints( aip, aigp );
1307  break;
1308 
1309  default:
1310  Int3(); // unsupported internal goal -- see Mike K or Mark A.
1311  return;
1312  }
1313 
1314 
1315  // process the orders immediately so that these goals take effect right away
1316  if ( immediate )
1318 }
1319 
1320 // function to add an internal goal to a wing. Mike K says that the goal doesn't need to persist
1321 // across waves of the wing so we merely need to add the goal to each ship in the wing. Certain
1322 // goal are simply not valid for wings (like dock, undock). Immediate parameter gets passed to add_ship_goal
1323 // to say whether or not we should process this goal right away
1324 void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate )
1325 {
1326  int i;
1327 
1328  // be sure we are not trying to issue dock or undock goals to wings
1329  Assert ( (goal_type != AI_GOAL_DOCK) && (goal_type != AI_GOAL_UNDOCK) );
1330 
1331  for (i = 0; i < wingp->current_count; i++) {
1332  int num = wingp->ship_index[i];
1333  if ( num == -1 ) // ship must have been destroyed or departed
1334  continue;
1335  ai_add_goal_ship_internal( &Ai_info[Ships[num].ai_index], goal_type, name, -1, -1, immediate);
1336  }
1337 }
1338 
1339 // this function copies goals from a wing to an ai_info * from a ship.
1341 {
1342  int j;
1343 
1344  for ( j = 0; j < MAX_AI_GOALS; j++ ) {
1345  if ( aip->goals[j].ai_mode == AI_GOAL_NONE ) {
1346  aip->goals[j] = *aigp;
1347  break;
1348  }
1349  }
1350 
1351  if (j >= MAX_AI_GOALS) {
1352  mprintf(("Unable to assign wing goal to ship %s; the ship goals are already filled to capacity", Ships[aip->shipnum].ship_name));
1353  }
1354 }
1355 
1356 
1357 #define SHIP_STATUS_GONE 1
1358 #define SHIP_STATUS_NOT_ARRIVED 2
1359 #define SHIP_STATUS_ARRIVED 3
1360 #define SHIP_STATUS_UNKNOWN 4
1361 
1362 // function to determine if an ai goal is achieveable or not. Will return
1363 // one of the AI_GOAL_* values. Also determines is a goal was successful.
1364 
1365 int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
1366 {
1367  int status;
1368  int return_val;
1369  object *objp;
1370  ai_info *aip;
1371  int index = -1, sindex = -1;
1372  int modelnum = -1;
1373 
1374  objp = &Objects[objnum];
1375  Assert( objp->instance != -1 );
1376  aip = &Ai_info[Ships[objp->instance].ai_index];
1377 
1378  // these orders are always achievable.
1379  if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE)
1380  || (aigp->ai_mode == AI_GOAL_CHASE_ANY) || (aigp->ai_mode == AI_GOAL_STAY_STILL)
1381  || (aigp->ai_mode == AI_GOAL_PLAY_DEAD) )
1382  return AI_GOAL_ACHIEVABLE;
1383 
1384  // warp (depart) only achievable if there's somewhere to depart to
1385  if (aigp->ai_mode == AI_GOAL_WARP)
1386  {
1387  ship *shipp = &Ships[objp->instance];
1388 
1389  // always valid if has subspace drive
1390  if (!(shipp->flags2 & SF2_NO_SUBSPACE_DRIVE))
1391  return AI_GOAL_ACHIEVABLE;
1392 
1393  // if no subspace drive, only valid if our mothership is present
1394 
1395  // check that we have a mothership and that we can depart to it
1396  if (shipp->departure_location == DEPART_AT_DOCK_BAY)
1397  {
1398  int anchor_shipnum = ship_name_lookup(Parse_names[shipp->departure_anchor]);
1399  if (anchor_shipnum >= 0 && ship_useful_for_departure(anchor_shipnum, shipp->departure_path_mask))
1400  return AI_GOAL_ACHIEVABLE;
1401  }
1402 
1403  return AI_GOAL_NOT_KNOWN;
1404  }
1405 
1406 
1407  // form on wing is always achievable if we are forming on Player, but it's up for grabs otherwise
1408  // if the wing target is valid then be sure to set the override bit so that it always
1409  // gets executed next
1410  if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
1411  sindex = ship_name_lookup( aigp->target_name );
1412 
1413  if (sindex < 0)
1414  return AI_GOAL_NOT_ACHIEVABLE;
1415 
1416  aigp->flags |= AIGF_GOAL_OVERRIDE;
1417  return AI_GOAL_ACHIEVABLE;
1418  }
1419 
1420  // check to see if we have a valid list. If not, then try to set one up. If that
1421  // fails, then we must pitch this order
1422  if ( (aigp->ai_mode == AI_GOAL_WAYPOINTS_ONCE) || (aigp->ai_mode == AI_GOAL_WAYPOINTS) ) {
1423  if ( aigp->wp_list == NULL ) {
1425 
1426  if ( aigp->wp_list == NULL ) {
1427  Warning(LOCATION, "Unknown waypoint list %s - not found in mission file. Killing ai goal", aigp->target_name );
1428  return AI_GOAL_NOT_ACHIEVABLE;
1429  }
1430  }
1431  return AI_GOAL_ACHIEVABLE;
1432  }
1433 
1434 
1435  return_val = AI_GOAL_SATISFIED;
1436 
1437  // next, determine if the goal has been completed successfully
1438  switch ( aigp->ai_mode )
1439  {
1440  case AI_GOAL_DOCK:
1441  case AI_GOAL_UNDOCK:
1442  //MWA 3/20/97 -- cannot short circuit a dock or undock goal already succeeded -- we must
1443  // rely on the goal removal code to just remove this goal. This is because docking/undock
1444  // can happen > 1 time per mission per pair of ships. The above checks will find only
1445  // if the ships docked or undocked at all, which is not what we want.
1446  status = 0;
1447  break;
1448 
1450  {
1451  ship_subsys *ssp;
1452 
1453  // shipnum could be -1 depending on if the ship hasn't arrived or died. only look for subsystem
1454  // destroyed when shipnum is valid
1455  sindex = ship_name_lookup( aigp->target_name );
1456 
1457  // can't determine the status of this goal if ship not valid
1458  // or we haven't found a valid subsystem index yet
1459  if ( (sindex == -1) || (aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP) ) {
1460  status = 0;
1461  break;
1462  }
1463 
1464  // if the ship is not in the mission or the subsystem name is still being stored, mark the status
1465  // as 0 so we can continue. (The subsystem name must be turned into an index into the ship's subsystems
1466  // for this goal to be valid).
1467  Assert ( aigp->ai_submode >= 0 );
1468  ssp = ship_get_indexed_subsys( &Ships[sindex], aigp->ai_submode );
1469  if (ssp != NULL) {
1471  } else {
1472  // not supposed to ever happen, but could if there is a mismatch between the table and model subsystems
1473  nprintf(("AI", "Couldn't find subsystem %d for ship %s\n", aigp->ai_submode, Ships[sindex].ship_name));
1474  status = 0;
1475  }
1476  break;
1477  }
1478 
1479  case AI_GOAL_DISABLE_SHIP:
1480  status = mission_log_get_time( LOG_SHIP_DISABLED, aigp->target_name, NULL, NULL );
1481  break;
1482 
1483  case AI_GOAL_DISARM_SHIP:
1484  status = mission_log_get_time( LOG_SHIP_DISARMED, aigp->target_name, NULL, NULL );
1485  break;
1486 
1487  // to guard or ignore a ship, the goal cannot continue if the ship being guarded is either destroyed
1488  // or has departed.
1489  case AI_GOAL_CHASE:
1490  case AI_GOAL_GUARD:
1491  case AI_GOAL_IGNORE:
1492  case AI_GOAL_IGNORE_NEW:
1493  case AI_GOAL_EVADE_SHIP:
1495  case AI_GOAL_FLY_TO_SHIP:
1496  case AI_GOAL_REARM_REPAIR:
1497  {
1498  // MWA -- 4/22/98. Check for the ship actually being in the mission before
1499  // checking departure and destroyed. In multiplayer, since ships can respawn,
1500  // they get log entries for being destroyed even though they have respawned.
1501  sindex = ship_name_lookup( aigp->target_name );
1502  if ( sindex < 0 ) {
1503  status = mission_log_get_time( LOG_SHIP_DEPARTED, aigp->target_name, NULL, NULL);
1504  if ( !status ) {
1505  status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->target_name, NULL, NULL);
1506  if ( !status ) {
1507  status = mission_log_get_time( LOG_SELF_DESTRUCTED, aigp->target_name, NULL, NULL);
1508  }
1509  }
1510 
1511  if ( status )
1512  return_val = AI_GOAL_NOT_ACHIEVABLE;
1513  } else {
1514  status = 0;
1515  }
1516 
1517  break;
1518  }
1519 
1520  case AI_GOAL_CHASE_WING:
1521  case AI_GOAL_GUARD_WING:
1522  {
1523  status = mission_log_get_time( LOG_WING_DEPARTED, aigp->target_name, NULL, NULL );
1524  if ( !status ) {
1525  status = mission_log_get_time( LOG_WING_DESTROYED, aigp->target_name, NULL, NULL);
1526  if ( status )
1527  return_val = AI_GOAL_NOT_ACHIEVABLE;
1528  }
1529 
1530  break;
1531  }
1532 
1533  // the following case statement returns control to caller on all paths!!!!
1534  case AI_GOAL_CHASE_WEAPON:
1535  {
1536  // for chase weapon, we simply need to look at the weapon instance that we are trying to
1537  // attack and see if the object still exists, and has the same signature that we expect.
1538  Assert( aigp->target_instance >= 0 );
1539 
1540  if ( Weapons[aigp->target_instance].objnum == -1 )
1541  return AI_GOAL_NOT_ACHIEVABLE;
1542 
1543  // if the signatures don't match, then goal isn't achievable.
1545  return AI_GOAL_NOT_ACHIEVABLE;
1546 
1547  // otherwise, we should be good to go
1548  return AI_GOAL_ACHIEVABLE;
1549 
1550  break;
1551  }
1552 
1553  default:
1554  Int3();
1555  status = 0;
1556  break;
1557  }
1558 
1559  // if status is true, then the mission log event was found and the goal was satisfied. return
1560  // AI_GOAL_SATISFIED which should allow this ai object to move onto the next order
1561  if ( status )
1562  return return_val;
1563 
1564  // determine the status of the shipname that this object is acting on. There are a couple of
1565  // special cases to deal with. Both the chase wing and undock commands will return from within
1566  // the if statement.
1567  if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) )
1568  {
1569  sindex = wing_name_lookup( aigp->target_name );
1570 
1571  if (sindex < 0)
1572  return AI_GOAL_NOT_KNOWN;
1573 
1574  wing *wingp = &Wings[sindex];
1575 
1576  if ( wingp->flags & WF_WING_GONE )
1577  return AI_GOAL_NOT_ACHIEVABLE;
1578  else if ( wingp->total_arrived_count == 0 )
1579  return AI_GOAL_NOT_KNOWN;
1580  else
1581  return AI_GOAL_ACHIEVABLE;
1582  }
1583  // Goober5000 - undocking from an unspecified object is always achievable;
1584  // undocking from a specified object is handled below
1585  else if ( (aigp->ai_mode == AI_GOAL_UNDOCK) && (aigp->target_name == NULL) )
1586  {
1587  return AI_GOAL_ACHIEVABLE;
1588  }
1589  else
1590  {
1591  // goal ship is currently in mission
1592  if ( ship_name_lookup( aigp->target_name ) != -1 )
1593  {
1594  status = SHIP_STATUS_ARRIVED;
1595  }
1596  // goal ship is still on the arrival list
1597  else if ( mission_parse_get_arrival_ship(aigp->target_name) )
1598  {
1599  status = SHIP_STATUS_NOT_ARRIVED;
1600  }
1601  // goal ship has left the area
1602  else if ( ship_find_exited_ship_by_name(aigp->target_name) != -1 )
1603  {
1604  status = SHIP_STATUS_GONE;
1605  }
1606  else
1607  {
1608  Int3(); // get ALLENDER
1609  status = SHIP_STATUS_UNKNOWN;
1610  }
1611  }
1612 
1613  // Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship...
1614  if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP))
1615  {
1616  // if the ship has no turrets, we can't disarm it!
1617  if (Ships[ship_name_lookup(aigp->target_name)].subsys_info[SUBSYSTEM_TURRET].type_count == 0)
1618  return AI_GOAL_NOT_ACHIEVABLE;
1619  }
1620 
1621  // if the goal is an ignore/disable/disarm goal, then
1622  // Goober5000 - see note at PURGE_GOALS_ALL_SHIPS... this is bizarre
1623  if ((status == SHIP_STATUS_ARRIVED) && !(aigp->flags & AIGF_GOALS_PURGED))
1624  {
1625  if (aigp->ai_mode & PURGE_GOALS_ALL_SHIPS) {
1627  aigp->flags |= AIGF_GOALS_PURGED;
1628  }
1629  else if (aigp->ai_mode & PURGE_GOALS_ONE_SHIP) {
1630  ai_goal_purge_invalid_goals(aigp, aip->goals, aip, -1);
1631  aigp->flags |= AIGF_GOALS_PURGED;
1632  }
1633  }
1634 
1635  // if we are docking, validate the docking indices on both ships. We might have to change names to indices.
1636  // only enter this calculation if the ship we are docking with has arrived. If the ship is gone, then
1637  // this goal will get removed.
1638  if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
1639  if (!(aigp->flags & AIGF_DOCKER_INDEX_VALID)) {
1640  modelnum = Ship_info[Ships[objp->instance].ship_info_index].model_num;
1641  Assert( modelnum >= 0 );
1642  index = model_find_dock_name_index(modelnum, aigp->docker.name);
1643  aigp->docker.index = index;
1644  aigp->flags |= AIGF_DOCKER_INDEX_VALID;
1645  }
1646 
1647  if (!(aigp->flags & AIGF_DOCKEE_INDEX_VALID)) {
1648  sindex = ship_name_lookup(aigp->target_name);
1649  if ( sindex != -1 ) {
1650  modelnum = Ship_info[Ships[sindex].ship_info_index].model_num;
1651  index = model_find_dock_name_index(modelnum, aigp->dockee.name);
1652  aigp->dockee.index = index;
1653  aigp->flags |= AIGF_DOCKEE_INDEX_VALID;
1654  } else
1655  aigp->dockee.index = -1; // this will force code into if statement below making goal not achievable.
1656  }
1657 
1658  if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
1659  Int3(); // for now, allender wants to know about these things!!!!
1660  return AI_GOAL_NOT_ACHIEVABLE;
1661  }
1662 
1663  // if ship is disabled, don't know if it can dock or not
1664  if ( Ships[objp->instance].flags & SF_DISABLED )
1665  return AI_GOAL_NOT_KNOWN;
1666 
1667  // we must also determine if we're prevented from docking for any reason
1668  sindex = ship_name_lookup(aigp->target_name);
1669  Assert( sindex >= 0 );
1670  object *goal_objp = &Objects[Ships[sindex].objnum];
1671 
1672  // if the ship that I am supposed to dock with is docked with something else, then I need to put my goal on hold
1673  // [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
1674  // This bug occurred only when mission goals were validated in the frame in which Comet docked, which happened about
1675  // once in 10-20 tries.]
1676  if ( object_is_docked(goal_objp) )
1677  {
1678  // if the dockpoint I need to dock to is occupied by someone other than me
1679  object *obstacle_objp = dock_find_object_at_dockpoint(goal_objp, aigp->dockee.index);
1680  if (obstacle_objp == NULL)
1681  {
1682  // nobody in the way... we're good
1683  }
1684  else if (obstacle_objp != objp)
1685  {
1686  // return NOT_KNOWN which will place the goal on hold until the dockpoint is clear
1687  return AI_GOAL_NOT_KNOWN;
1688  }
1689  }
1690 
1691  // if this ship is docked and needs to get docked with something else, then undock this ship
1692  if ( object_is_docked(objp) )
1693  {
1694  // if the dockpoint I need to dock with is occupied by someone other than the guy I need to dock to
1695  object *obstacle_objp = dock_find_object_at_dockpoint(objp, aigp->docker.index);
1696  if (obstacle_objp == NULL)
1697  {
1698  // nobody in the way... we're good
1699  }
1700  else if (obstacle_objp != goal_objp)
1701  {
1702  // if this goal isn't on hold yet, then issue the undock goal
1703  if ( !(aigp->flags & AIGF_GOAL_ON_HOLD) )
1704  ai_add_goal_ship_internal( aip, AI_GOAL_UNDOCK, Ships[obstacle_objp->instance].ship_name, -1, -1, 0 );
1705 
1706  // return NOT_KNOWN which will place the goal on hold until the undocking is complete.
1707  return AI_GOAL_NOT_KNOWN;
1708  }
1709  }
1710 
1711  // Goober5000 - necessitated by the multiple ship docking
1712  } else if ( (aigp->ai_mode == AI_GOAL_UNDOCK) && (status == SHIP_STATUS_ARRIVED) ) {
1713  // Put this goal on hold if we're already undocking. Otherwise the new goal will pre-empt
1714  // the current goal and strange things might happen. One is that the object movement code
1715  // forgets the previous undocking and "re-docks" the previous goal's ship. Other problems
1716  // might happen too, so err on the safe side. (Yay for emergent paragraph justification!)
1717  if ((aip->mode == AIM_DOCK) && (aip->submode >= AIS_UNDOCK_0))
1718  {
1719  // only put it on hold if it's someone other than the guy we're undocking from right now!!
1720  if (aip->goal_objnum != Ships[ship_name_lookup(aigp->target_name)].objnum)
1721  return AI_GOAL_NOT_KNOWN;
1722  }
1723 
1724  } else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
1725  // if the ship has arrived, and the goal is destroy subsystem, then check to see that we
1726  // have fixed up the subsystem name (of the subsystem to destroy) into an index into
1727  // the ship's subsystem list
1728  if ( aigp->flags & AIGF_SUBSYS_NEEDS_FIXUP ) {
1729  sindex = ship_name_lookup( aigp->target_name );
1730 
1731  if ( sindex != -1 ) {
1732  aigp->ai_submode = ship_get_subsys_index( &Ships[sindex], aigp->docker.name );
1733  aigp->flags &= ~AIGF_SUBSYS_NEEDS_FIXUP;
1734  } else {
1735  Int3();
1736  return AI_GOAL_NOT_ACHIEVABLE; // force this goal to be invalid
1737  }
1738  }
1739  } else if ( ((aigp->ai_mode == AI_GOAL_IGNORE) || (aigp->ai_mode == AI_GOAL_IGNORE_NEW)) && (status == SHIP_STATUS_ARRIVED) ) {
1740  object *ignored;
1741 
1742  // for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
1743  sindex = ship_name_lookup( aigp->target_name );
1744  Assert( sindex != -1 ); // should be true because of above status
1745  ignored = &Objects[Ships[sindex].objnum];
1746 
1747  ai_ignore_object(objp, ignored, (aigp->ai_mode == AI_GOAL_IGNORE_NEW));
1748 
1749  return AI_GOAL_SATISFIED;
1750  }
1751 
1752  switch ( aigp->ai_mode )
1753  {
1754  case AI_GOAL_CHASE:
1755  case AI_GOAL_CHASE_WING:
1756  case AI_GOAL_DOCK:
1757  case AI_GOAL_UNDOCK:
1758  case AI_GOAL_GUARD:
1759  case AI_GOAL_GUARD_WING:
1760  case AI_GOAL_DISABLE_SHIP:
1761  case AI_GOAL_DISARM_SHIP:
1763  case AI_GOAL_IGNORE:
1764  case AI_GOAL_IGNORE_NEW:
1765  case AI_GOAL_EVADE_SHIP:
1767  case AI_GOAL_FLY_TO_SHIP:
1768  {
1769  if ( status == SHIP_STATUS_ARRIVED )
1770  return AI_GOAL_ACHIEVABLE;
1771  else if ( status == SHIP_STATUS_NOT_ARRIVED )
1772  return AI_GOAL_NOT_KNOWN;
1773  else if ( status == SHIP_STATUS_GONE )
1774  return AI_GOAL_NOT_ACHIEVABLE;
1775  else if ( status == SHIP_STATUS_UNKNOWN )
1776  return AI_GOAL_NOT_KNOWN;
1777 
1778  Int3(); // get allender -- bad logic
1779  break;
1780  }
1781 
1782  // for rearm repair ships, a goal is only achievable if the support ship isn't repairing anything
1783  // else at the time, or is set to repair the ship for this goal. All other goals should be placed
1784  // on hold by returning GOAL_NOT_KNOWN.
1785  case AI_GOAL_REARM_REPAIR:
1786  {
1787  // short circuit a couple of cases. Ship not arrived shouldn't happen. Ship gone means
1788  // we mark the goal as not achievable.
1789  if ( status == SHIP_STATUS_NOT_ARRIVED ) {
1790  Int3(); // get Allender. this shouldn't happen!!!
1791  return AI_GOAL_NOT_ACHIEVABLE;
1792  }
1793 
1794  if ( status == SHIP_STATUS_GONE )
1795  return AI_GOAL_NOT_ACHIEVABLE;
1796 
1797  sindex = ship_name_lookup( aigp->target_name );
1798 
1799  if ( sindex < 0 ) {
1800  Int3();
1801  return AI_GOAL_NOT_ACHIEVABLE;
1802  }
1803 
1804  // if desitnation currently being repaired, then goal is stil active
1805  if ( Ai_info[Ships[sindex].ai_index].ai_flags & AIF_BEING_REPAIRED )
1806  return AI_GOAL_ACHIEVABLE;
1807 
1808  // if the destination ship is dying or departing (but not completed yet), the mark goal as
1809  // not achievable.
1810  if ( Ships[sindex].flags & (SF_DYING | SF_DEPARTING) )
1811  return AI_GOAL_NOT_ACHIEVABLE;
1812 
1813  // if the destination object is no longer awaiting repair, then remove the item
1814  if ( !(Ai_info[Ships[sindex].ai_index].ai_flags & AIF_AWAITING_REPAIR) )
1815  return AI_GOAL_NOT_ACHIEVABLE;
1816 
1817  // not repairing anything means that he can do this goal!!!
1818  if ( !(aip->ai_flags & AIF_REPAIRING) )
1819  return AI_GOAL_ACHIEVABLE;
1820 
1821  // test code!!!
1822  if ( aip->goal_objnum == -1 ) {
1823  return AI_GOAL_ACHIEVABLE;
1824  }
1825 
1826  // if he is repairing something, he can satisfy his repair goal (his goal_objnum)
1827  // return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
1828  // satisfied.
1829  if ( aip->goal_objnum != Ships[sindex].objnum )
1830  return AI_GOAL_NOT_KNOWN;
1831 
1832  return AI_GOAL_ACHIEVABLE;
1833  }
1834 
1835  default:
1836  Int3(); // invalid case in switch:
1837  }
1838 
1839  return AI_GOAL_NOT_KNOWN;
1840 }
1841 
1842 // Compare function for sorting ai_goals based on priority.
1843 // Return values set to sort array in _decreasing_ order.
1844 int ai_goal_priority_compare(const void *a, const void *b)
1845 {
1846  ai_goal *ga, *gb;
1847 
1848  ga = (ai_goal *) a;
1849  gb = (ai_goal *) b;
1850 
1851  // first, sort based on whether or not the ON_HOLD flag is set for the goal.
1852  // If the flag is set, don't push the goal higher in the list even if priority
1853  // is higher since goal cannot currently be achieved.
1854 
1855  if ( (ga->flags & AIGF_GOAL_ON_HOLD) && !(gb->flags & AIGF_GOAL_ON_HOLD) )
1856  return 1;
1857  else if ( !(ga->flags & AIGF_GOAL_ON_HOLD) && (gb->flags & AIGF_GOAL_ON_HOLD) )
1858  return -1;
1859 
1860  // check whether or not the goal override flag is set. If it is set, then push this goal higher
1861  // in the list
1862 
1863  else if ( (ga->flags & AIGF_GOAL_OVERRIDE) && !(gb->flags & AIGF_GOAL_OVERRIDE) )
1864  return -1;
1865  else if ( !(ga->flags & AIGF_GOAL_OVERRIDE) && (gb->flags & AIGF_GOAL_OVERRIDE) )
1866  return 1;
1867 
1868  // now normal priority processing
1869 
1870  if (ga->priority > gb->priority)
1871  return -1;
1872  else if ( ga->priority < gb->priority )
1873  return 1;
1874 
1875  // check based on time goal was issued
1876 
1877  if ( ga->time > gb->time )
1878  return -1;
1879  // V had this check commented out and would always return 1 here, that messes up where multiple goals
1880  // get assigned at the same time though, when the priorities are also the same (Enif station bug) - taylor
1881  else if ( ga->time < gb->time )
1882  return 1;
1883 
1884  // the two are equal
1885  return 0;
1886 }
1887 
1888 // Prioritize goal list.
1889 // First sort on priority.
1890 // Then sort on time for goals of equivalent priority.
1891 // *aip The AI info to act upon. Goals are stored at aip->goals
1893 {
1894  // First sort based on priority field.
1896 }
1897 
1898 // Scan the list of goals at aip->goals.
1899 // Remove obsolete goals.
1900 // objnum Object of interest. Redundant with *aip.
1901 // *aip contains goals at aip->goals.
1902 void validate_mission_goals(int objnum, ai_info *aip)
1903 {
1904  int i;
1905 
1906  // loop through all of the goals to determine which goal should be followed.
1907  // This determination will be based on priority, and the time at which it was issued.
1908  for ( i = 0; i < MAX_AI_GOALS; i++ ) {
1909  int state;
1910  ai_goal *aigp;
1911 
1912  aigp = &aip->goals[i];
1913 
1914  // quick check to see if this goal is valid or not, or if we are trying to process the
1915  // current goal
1916  if (aigp->ai_mode == AI_GOAL_NONE)
1917  continue;
1918 
1919  // purge any goals which should get purged
1920  if ( aigp->flags & AIGF_PURGE ) {
1921  ai_remove_ship_goal( aip, i );
1922  continue;
1923  }
1924 
1925  state = ai_mission_goal_achievable( objnum, aigp );
1926 
1927  // if this order is no longer a valid one, remove it
1928  if ( (state == AI_GOAL_NOT_ACHIEVABLE) || (state == AI_GOAL_SATISFIED) ) {
1929  ai_remove_ship_goal( aip, i );
1930  continue;
1931  }
1932 
1933  // if the status is achievable, and the on_hold flag is set, clear the flagb
1934  if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags & AIGF_GOAL_ON_HOLD) )
1935  aigp->flags &= ~AIGF_GOAL_ON_HOLD;
1936 
1937  // if the goal is not known, then set the ON_HOLD flag so that it doesn't get counted as
1938  // a goal to be pursued
1939  if ( state == AI_GOAL_NOT_KNOWN )
1940  aigp->flags |= AIGF_GOAL_ON_HOLD; // put this goal on hold until it becomes true
1941  }
1942 
1943  // if we had an active goal, and that goal is now in hold, make the mode AIM_NONE. If a new valid
1944  // goal is produced after prioritizing, then the mode will get reset immediately. Otherwise, setting
1945  // the mode to none will force ship to do default behavior.
1946  if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags & AIGF_GOAL_ON_HOLD) )
1947  aip->mode = AIM_NONE;
1948 
1949  // if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
1950  // on hold
1951  if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR) && object_is_docked(&Objects[objnum]) ) {
1952  for ( i = 1; i < MAX_AI_GOALS; i++ ) {
1953  if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
1954  continue;
1955  aip->goals[i].flags |= AIGF_GOAL_ON_HOLD;
1956  }
1957  }
1958 }
1959 
1960 //XSTR:OFF
1961 /*
1962 static char *Goal_text[5] = {
1963 "EVENT_SHIP",
1964 "EVENT_WING",
1965 "PLAYER_SHIP",
1966 "PLAYER_WING",
1967 "DYNAMIC",
1968 };
1969 */
1970 //XSTR:ON
1971 
1972 extern char *Mode_text[MAX_AI_BEHAVIORS];
1973 
1974 // code to process ai "orders". Orders include those determined from the mission file and those
1975 // given by the player to a ship that is under his control. This function gets called for every
1976 // AI object every N seconds through the ai loop.
1977 void ai_process_mission_orders( int objnum, ai_info *aip )
1978 {
1979  object *objp = &Objects[objnum];
1980  object *other_obj;
1981  ai_goal *current_goal;
1982  int wingnum, shipnum;
1983  int original_signature;
1984 
1985 /* if (!stricmp(Ships[objp->instance].ship_name, "gtt comet")) {
1986  for (int i=0; i<MAX_AI_GOALS; i++) {
1987  if (aip->goals[i].signature != -1) {
1988  nprintf(("AI", "%6.1f: mode=%s, type=%s, ship=%s\n", f2fl(Missiontime), Mode_text[aip->goals[i].ai_mode], Goal_text[aip->goals[i].type], aip->goals[i].ship_name));
1989  }
1990  }
1991  nprintf(("AI", "\n"));
1992  }
1993 */
1994 
1995  // AL 12-12-97: If a ship is entering/leaving a docking bay, wait until path
1996  // following is finished before pursuing goals.
1997  if ( aip->mode == AIM_BAY_EMERGE || aip->mode == AIM_BAY_DEPART ) {
1998  return;
1999  }
2000 
2001  // Goal #0 is always the active goal, as we maintain a sorted list.
2002  // Get the signature to see if sorting it again changes it.
2003  original_signature = aip->goals[0].signature;
2004 
2005  validate_mission_goals(objnum, aip);
2006 
2007  // Sort the goal array by priority and other factors.
2008  prioritize_goals(aip);
2009 
2010  // Make sure there's a goal to pursue, else return.
2011  if (aip->goals[0].signature == -1) {
2012  if (aip->mode == AIM_NONE)
2013  ai_do_default_behavior(objp);
2014  return;
2015  }
2016 
2017  // If goal didn't change, return.
2018  if ((aip->active_goal != -1) && (aip->goals[0].signature == original_signature))
2019  return;
2020 
2021  // if the first goal in the list has the ON_HOLD flag, set, there is no current valid goal
2022  // to pursue.
2023  if ( aip->goals[0].flags & AIGF_GOAL_ON_HOLD )
2024  return;
2025 
2026  // Kind of a hack for now. active_goal means the goal currently being pursued.
2027  // It will always be #0 since the list is prioritized.
2028  aip->active_goal = 0;
2029 
2030  //nprintf(("AI", "New goal for %s = %i\n", Ships[objp->instance].ship_name, aip->goals[0].ai_mode));
2031 
2032  current_goal = &aip->goals[0];
2033 
2034  if ( MULTIPLAYER_MASTER ){
2036  }
2037 
2038  // if this object was flying in formation off of another object, remove the flag that tells him
2039  // to do this. The form-on-my-wing command is removed from the goal list as soon as it is called, so
2040  // we are safe removing this bit here.
2041  aip->ai_flags &= ~AIF_FORMATION_OBJECT;
2042 
2043  // Goober5000 - we may want to use AI for the player
2044  // AL 3-7-98: If this is a player ship, and the goal is not a formation goal, then do a quick out
2045  if ( !(Player_use_ai) && (objp->flags & OF_PLAYER_SHIP) && (current_goal->ai_mode != AI_GOAL_FORM_ON_WING) )
2046  {
2047  return;
2048  }
2049 
2050 
2051 
2052  switch ( current_goal->ai_mode ) {
2053 
2054  case AI_GOAL_CHASE:
2055  if ( current_goal->target_name ) {
2056  shipnum = ship_name_lookup( current_goal->target_name );
2057  Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2058  other_obj = &Objects[Ships[shipnum].objnum];
2059  } else
2060  other_obj = NULL; // we get this case when we tell ship to engage enemy!
2061 
2062  // Mike -- debug code!
2063  // If a ship has a subobject on it, attack that instead of the main ship!
2064  ai_attack_object( objp, other_obj, NULL);
2065  break;
2066 
2067  case AI_GOAL_CHASE_WEAPON:
2068  Assert( Weapons[current_goal->target_instance].objnum >= 0 );
2069  other_obj = &Objects[Weapons[current_goal->target_instance].objnum];
2070  Assert( other_obj->signature == current_goal->target_signature );
2071  ai_attack_object( objp, other_obj, NULL );
2072  break;
2073 
2074  case AI_GOAL_GUARD:
2075  shipnum = ship_name_lookup( current_goal->target_name );
2076  Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2077  other_obj = &Objects[Ships[shipnum].objnum];
2078  // shipnum and other_obj are the shipnumber and object pointer of the object that you should
2079  // guard.
2080  if (objp != other_obj) {
2081  ai_set_guard_object(objp, other_obj);
2083  } else {
2084  mprintf(("Warning: Ship %s told to guard itself. Goal ignored.\n", Ships[objp->instance].ship_name));
2085  }
2086  // -- What is this doing here?? -- MK, 7/30/97 -- ai_do_default_behavior( objp );
2087  break;
2088 
2089  case AI_GOAL_GUARD_WING:
2090  wingnum = wing_name_lookup( current_goal->target_name );
2091  Assert (wingnum != -1 ); // shouldn't get here if this is false!!!!
2092  ai_set_guard_wing(objp, wingnum);
2094  break;
2095 
2096  case AI_GOAL_WAYPOINTS: // do nothing for waypoints
2097  case AI_GOAL_WAYPOINTS_ONCE: {
2098  int flags = 0;
2099 
2100  if ( current_goal->ai_mode == AI_GOAL_WAYPOINTS)
2101  flags |= WPF_REPEAT;
2102  ai_start_waypoints(objp, current_goal->wp_list, flags);
2103  break;
2104  }
2105 
2106  case AI_GOAL_FLY_TO_SHIP:
2107  shipnum = ship_name_lookup( current_goal->target_name );
2108  Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2109  ai_start_fly_to_ship(objp, shipnum);
2110  break;
2111 
2112  case AI_GOAL_DOCK: {
2113  shipnum = ship_name_lookup( current_goal->target_name );
2114  Assert (shipnum != -1 ); // shouldn't get here if this is false!!!!
2115  other_obj = &Objects[Ships[shipnum].objnum];
2116 
2117  // be sure that we have indices for docking points here! If we ever had names, they should
2118  // get fixed up in goal_achievable so that the points can be checked there for validity
2119  Assert (current_goal->flags & AIGF_DOCK_INDEXES_VALID);
2120  ai_dock_with_object( objp, current_goal->docker.index, other_obj, current_goal->dockee.index, AIDO_DOCK );
2121  break;
2122  }
2123 
2124  case AI_GOAL_UNDOCK:
2125  // try to find the object which which this object is docked with. Use that object as the
2126  // "other object" for the undocking proceedure. If "other object" isn't found, then the undock
2127  // goal cannot continue. Spit out a warning and remove the goal.
2128 
2129  // Goober5000 - do we have a specific ship to undock from?
2130  if ( current_goal->target_name != NULL )
2131  {
2132  shipnum = ship_name_lookup( current_goal->target_name );
2133 
2134  // hmm, perhaps he was destroyed
2135  if (shipnum == -1)
2136  {
2137  other_obj = NULL;
2138  }
2139  // he exists... let's undock from him
2140  else
2141  {
2142  other_obj = &Objects[Ships[shipnum].objnum];
2143  }
2144  }
2145  // no specific ship
2146  else
2147  {
2148  // are we docked?
2149  if (object_is_docked(objp))
2150  {
2151  // just pick the first guy we're docked to
2152  other_obj = dock_get_first_docked_object( objp );
2153 
2154  // and add the ship name so it displays on the HUD
2155  current_goal->target_name = Ships[other_obj->instance].ship_name;
2156  }
2157  // hmm, nobody exists that we can undock from
2158  else
2159  {
2160  other_obj = NULL;
2161  }
2162  }
2163 
2164  if ( other_obj == NULL ) {
2165  // assume that the guy he was docked with doesn't exist anymore. (i.e. a cargo containuer
2166  // can get destroyed while docked with a freighter.) We should just remove this goal and
2167  // let this ship pick up it's next goal.
2168  ai_mission_goal_complete( aip ); // mark as complete, so we can remove it and move on!!!
2169  break;
2170  }
2171 
2172  // Goober5000 - Sometimes a ship will be assigned a new goal before it can finish undocking. Later,
2173  // when the ship returns to this goal, it will try to resume undocking from a ship it's not attached
2174  // to. If this happens, remove the goal as above.
2175  if (!dock_check_find_direct_docked_object(objp, other_obj))
2176  {
2177  ai_mission_goal_complete( aip );
2178  break;
2179  }
2180 
2181  // passing 0, 0 is okay because the undock code will figure out where to undock from
2182  ai_dock_with_object( objp, 0, other_obj, 0, AIDO_UNDOCK );
2183  break;
2184 
2185 
2186  // when destroying a subsystem, we can destroy a specific instance of a subsystem
2187  // or all instances of a type of subsystem (i.e. a specific engine or all engines).
2188  // the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
2189  // instances of a specific type
2191  case AI_GOAL_DISABLE_SHIP:
2192  case AI_GOAL_DISARM_SHIP: {
2193  shipnum = ship_name_lookup( current_goal->target_name );
2194  Assert( shipnum >= 0 );
2195  other_obj = &Objects[Ships[shipnum].objnum];
2196  ai_attack_object( objp, other_obj, NULL);
2197  ai_set_attack_subsystem( objp, current_goal->ai_submode ); // submode stored the subsystem type
2198  if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
2199  if (aip->target_objnum != -1) {
2200  // Only protect if _not_ a capital ship. We don't want the Lucifer accidentally getting protected.
2201  if (Ship_types[Ship_info[Ships[shipnum].ship_info_index].class_type].ai_bools & STI_AI_PROTECTED_ON_CRIPPLE)
2203  }
2204  } else // Just in case this ship had been protected, unprotect it.
2205  if (aip->target_objnum != -1)
2207 
2208  break;
2209  }
2210 
2211  case AI_GOAL_CHASE_WING:
2212  wingnum = wing_name_lookup( current_goal->target_name );
2213  Assert( wingnum >= 0 );
2214  ai_attack_wing(objp, wingnum);
2215  break;
2216 
2217  case AI_GOAL_CHASE_ANY:
2218  ai_attack_object( objp, NULL, NULL );
2219  break;
2220 
2221  case AI_GOAL_WARP: {
2222  mission_do_departure( objp, true );
2223  break;
2224  }
2225 
2226  case AI_GOAL_EVADE_SHIP:
2227  shipnum = ship_name_lookup( current_goal->target_name );
2228  Assert( shipnum >= 0 );
2229  other_obj = &Objects[Ships[shipnum].objnum];
2230  ai_evade_object( objp, other_obj);
2231  break;
2232 
2233  case AI_GOAL_STAY_STILL:
2234  // for now, ignore any other parameters!!!!
2235  // clear out the object's goals. Seems to me that if a ship is staying still for a purpose
2236  // then we need to clear everything out since there is not a real way to get rid of this goal
2237  // clearing out goals is okay here since we are now what mode to set this AI object to.
2238  ai_clear_ship_goals( aip );
2239  ai_stay_still( objp, NULL );
2240  break;
2241 
2242  case AI_GOAL_PLAY_DEAD:
2243  // if a ship is playing dead, MWA says that it shouldn't try to do anything else.
2244  // clearing out goals is okay here since we are now what mode to set this AI object to.
2245  ai_clear_ship_goals( aip );
2246  aip->mode = AIM_PLAY_DEAD;
2247  aip->submode = -1;
2249  break;
2250 
2251  case AI_GOAL_FORM_ON_WING:
2252  // for form on wing, we need to clear out all goals for this ship, and then call the form
2253  // on wing AI code
2254  // clearing out goals is okay here since we are now what mode to set this AI object to.
2255  ai_clear_ship_goals( aip );
2256  shipnum = ship_name_lookup( current_goal->target_name );
2257  Assert( shipnum >= 0 );
2258  other_obj = &Objects[Ships[shipnum].objnum];
2259  ai_form_on_wing( objp, other_obj );
2260  break;
2261 
2262 // labels for support ship commands
2263 
2264  case AI_GOAL_STAY_NEAR_SHIP: {
2265  shipnum = ship_name_lookup( current_goal->target_name );
2266  Assert( shipnum >= 0 );
2267  other_obj = &Objects[Ships[shipnum].objnum];
2268  // todo MK: hook to keep support ship near other_obj -- other_obj could be the player object!!!
2269  float dist = 300.0f; // How far away to stay from ship. Should be set in SEXP?
2270  ai_do_stay_near(objp, other_obj, dist);
2271  break;
2272  }
2273 
2275  // todo MK: hook to keep support ship at a safe distance
2276 
2277  // Goober5000 - hmm, never implemented - let's see about that
2278  ai_do_safety(objp);
2279  break;
2280 
2281  case AI_GOAL_REARM_REPAIR:
2282  shipnum = ship_name_lookup( current_goal->target_name );
2283  Assert( shipnum >= 0 );
2284  other_obj = &Objects[Ships[shipnum].objnum];
2285  ai_rearm_repair( objp, current_goal->docker.index, other_obj, current_goal->dockee.index );
2286  break;
2287 
2288  default:
2289  Int3();
2290  break;
2291  }
2292 
2293 }
2294 
2295 void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name)
2296 {
2297  int i, mode, flag, dummy;
2298 
2299  for (i=0; i<MAX_AI_GOALS; i++) // loop through all the goals in the Ai_info entry
2300  {
2301  mode = goals[i].ai_mode;
2302  flag = 0;
2303  switch (type)
2304  {
2305  case REF_TYPE_SHIP:
2306  case REF_TYPE_PLAYER:
2307  switch (mode)
2308  {
2309  case AI_GOAL_CHASE:
2310  case AI_GOAL_DOCK:
2312  case AI_GOAL_GUARD:
2313  case AI_GOAL_DISABLE_SHIP:
2314  case AI_GOAL_DISARM_SHIP:
2315  case AI_GOAL_IGNORE:
2316  case AI_GOAL_IGNORE_NEW:
2317  case AI_GOAL_EVADE_SHIP:
2319  flag = 1;
2320  }
2321  break;
2322 
2323  case REF_TYPE_WING:
2324  switch (mode)
2325  {
2326  case AI_GOAL_CHASE_WING:
2327  case AI_GOAL_GUARD_WING:
2328  flag = 1;
2329  }
2330  break;
2331 
2332  case REF_TYPE_WAYPOINT:
2333  switch (mode)
2334  {
2335  case AI_GOAL_WAYPOINTS:
2337  flag = 1;
2338  }
2339  break;
2340 
2341  case REF_TYPE_PATH:
2342  switch (mode)
2343  {
2344  case AI_GOAL_WAYPOINTS:
2346 
2347  flag = 1;
2348  }
2349  break;
2350  }
2351 
2352  if (flag) // is this a valid goal to parse for this conversion?
2353  if (!stricmp(goals[i].target_name, old_name)) {
2354  if (*new_name == '<') // target was just deleted..
2355  goals[i].ai_mode = AI_GOAL_NONE;
2356  else
2357  goals[i].target_name = ai_get_goal_target_name(new_name, &dummy);
2358  }
2359  }
2360 }
2361 
2362 int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
2363 {
2364  int i, mode, flag;
2365 
2366  for (i=0; i<MAX_AI_GOALS; i++) // loop through all the goals in the Ai_info entry
2367  {
2368  mode = goals[i].ai_mode;
2369  flag = 0;
2370  switch (type)
2371  {
2372  case REF_TYPE_SHIP:
2373  switch (mode)
2374  {
2375  case AI_GOAL_CHASE:
2376  case AI_GOAL_DOCK:
2378  case AI_GOAL_GUARD:
2379  case AI_GOAL_DISABLE_SHIP:
2380  case AI_GOAL_DISARM_SHIP:
2381  case AI_GOAL_IGNORE:
2382  case AI_GOAL_IGNORE_NEW:
2383  case AI_GOAL_EVADE_SHIP:
2385  flag = 1;
2386  }
2387  break;
2388 
2389  case REF_TYPE_WING:
2390  switch (mode)
2391  {
2392  case AI_GOAL_CHASE_WING:
2393  case AI_GOAL_GUARD_WING:
2394  flag = 1;
2395  }
2396  break;
2397 
2398  case REF_TYPE_WAYPOINT:
2399  switch (mode)
2400  {
2401  case AI_GOAL_WAYPOINTS:
2403  flag = 1;
2404  }
2405  break;
2406 
2407  case REF_TYPE_PATH:
2408  switch (mode)
2409  {
2410  case AI_GOAL_WAYPOINTS:
2412  flag = 1;
2413  }
2414  break;
2415  }
2416 
2417  if (flag) // is this a valid goal to parse for this conversion?
2418  {
2419  if (!stricmp(goals[i].target_name, name))
2420  return 1;
2421  }
2422  }
2423 
2424  return 0;
2425 }
2426 
2427 char *ai_add_dock_name(const char *str)
2428 {
2429  char *ptr;
2430  int i;
2431 
2432  Assert(strlen(str) <= NAME_LENGTH - 1);
2433  for (i=0; i<Num_ai_dock_names; i++)
2434  if (!stricmp(Ai_dock_names[i], str))
2435  return Ai_dock_names[i];
2436 
2437  Assert(Num_ai_dock_names < MAX_AI_DOCK_NAMES);
2438  ptr = Ai_dock_names[Num_ai_dock_names++];
2439  strcpy(ptr, str);
2440  return ptr;
2441 }
SCP_string sexp
Definition: sexp.cpp:25556
char Parse_names[MAX_SHIPS+MAX_WINGS][NAME_LENGTH]
fix submode_start_time
Definition: ai.h:400
#define OP_AI_CHASE_ANY
Definition: sexp.h:747
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
#define AIF_REPAIRING
Definition: ai.h:41
int i
Definition: multi_pxo.cpp:466
fix Missiontime
Definition: systemvars.cpp:19
#define AI_GOAL_UNDOCK
Definition: aigoals.h:36
model_subsystem * system_info
Definition: ship.h:314
int Num_ai_goals
Definition: aigoals.cpp:90
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
#define STI_AI_PROTECTED_ON_CRIPPLE
Definition: ship.h:1010
union ai_goal::@1 dockee
void ai_mission_goal_complete(ai_info *aip)
Definition: aigoals.cpp:360
#define AIM_BAY_DEPART
Definition: ai.h:184
ai_info * Player_ai
Definition: ai.cpp:24
#define AIGF_SUBSYS_NEEDS_FIXUP
Definition: ai.h:107
int objnum
Definition: ship.h:537
#define AIM_BAY_EMERGE
Definition: ai.h:183
void ai_do_stay_near(object *objp, object *other_obj, float dist)
Definition: aicode.cpp:3254
#define OP_AI_FORM_ON_WING
Definition: sexp.h:755
void ai_attack_object(object *attacker, object *attacked, ship_subsys *ssp)
Definition: aicode.cpp:2257
#define PLAYER_PRIORITY_SUPPORT_LOW
Definition: aigoals.cpp:38
int Num_ai_dock_names
Definition: aigoals.cpp:59
char * Mode_text[MAX_AI_BEHAVIORS]
Definition: aicode.cpp:108
char * name
Definition: ai.h:153
#define REF_TYPE_WING
Definition: sexp.h:837
#define LOG_SHIP_SUBSYS_DESTROYED
Definition: missionlog.h:27
void ai_add_ship_goal_player(int type, int mode, int submode, char *shipname, ai_info *aip)
Definition: aigoals.cpp:757
#define SF2_NO_SUBSPACE_DRIVE
Definition: ship.h:487
GLuint index
Definition: Glext.h:5608
void ai_form_on_wing(object *objp, object *goal_objp)
Definition: aicode.cpp:3290
void ai_add_wing_goal_player(int type, int mode, int submode, char *shipname, int wingnum)
Definition: aigoals.cpp:783
#define AI_GOAL_CHASE_WING
Definition: aigoals.h:37
#define AI_GOAL_DOCK
Definition: aigoals.h:30
int active_goal
Definition: ai.h:413
int target_signature
Definition: ai.h:147
int Fred_running
Definition: fred.cpp:44
int mission_do_departure(object *objp, bool goal_is_to_warp)
#define AI_GOAL_WAYPOINTS
Definition: aigoals.h:31
void ai_clear_wing_goals(int wingnum)
Definition: aigoals.cpp:270
#define AI_GOAL_GUARD
Definition: aigoals.h:38
#define WF_WING_GONE
Definition: ship.h:1501
int departure_anchor
Definition: ship.h:618
#define OP_AI_IGNORE_NEW
Definition: sexp.h:754
void ai_ignore_object(object *ignorer, object *ignored, int ignore_new)
Definition: aicode.cpp:2440
int Num_dock_type_names
Definition: modelread.cpp:122
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)
int target_objnum
Definition: ai.h:339
int submode
Definition: ai.h:394
int ai_submode
Definition: ai.h:137
int departure_location
Definition: ship.h:617
#define mprintf(args)
Definition: pstypes.h:238
int ai_index
Definition: ship.h:538
#define CDDDR(n)
Definition: sexp.h:828
#define AI_GOAL_STAY_NEAR_SHIP
Definition: aigoals.h:47
#define AIGF_GOAL_ON_HOLD
Definition: ai.h:106
char * CTEXT(int n)
Definition: sexp.cpp:28821
#define AI_GOAL_CHASE_ANY
Definition: aigoals.h:41
void ai_add_goal_ship_internal(ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate)
Definition: aigoals.cpp:1244
#define LOG_WING_DEPARTED
Definition: missionlog.h:25
const char * Ai_goal_text(int goal)
Definition: aigoals.cpp:96
int ai_goal_num(ai_goal *goals)
Definition: aigoals.cpp:691
int ai_goal_find_empty_slot(ai_goal *goals, int active_goal)
Definition: aigoals.cpp:665
#define LOG_SHIP_DEPARTED
Definition: missionlog.h:24
object * dock_find_object_at_dockpoint(object *objp, int dockpoint)
Definition: objectdock.cpp:106
int ai_goal_find_dockpoint(int shipnum, int dock_type)
Definition: aigoals.cpp:488
int target_name_index
Definition: ai.h:144
#define AI_GOAL_WARP
Definition: aigoals.h:33
#define AIGF_GOALS_PURGED
Definition: ai.h:110
#define AI_GOAL_IGNORE
Definition: aigoals.h:42
bool dock_check_find_direct_docked_object(object *objp, object *other_objp)
Definition: objectdock.cpp:91
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
int ai_remove_goal_sexp_sub(int sexp, ai_goal *aigp)
Definition: aigoals.cpp:1037
#define Assertion(expr, msg,...)
Definition: clang.h:41
object obj_used_list
Definition: object.cpp:53
#define SHIP_STATUS_ARRIVED
Definition: aigoals.cpp:1359
#define AI_GOAL_DISARM_SHIP
Definition: aigoals.h:40
Definition: ship.h:1516
void ai_stay_still(object *still_objp, vec3d *view_pos)
Definition: aicode.cpp:2982
GLenum mode
Definition: Glext.h:5794
int ship_find_exited_ship_by_name(char *name)
Definition: ship.cpp:5338
Definition: ai.h:329
#define AIM_NONE
Definition: ai.h:175
#define DOCK_TYPE_GENERIC
Definition: model.h:520
int query_referenced_in_ai_goals(ai_goal *goals, int type, const char *name)
Definition: aigoals.cpp:2362
void ai_clear_ship_goals(ai_info *aip)
Definition: aigoals.cpp:251
char dockee_point[NAME_LENGTH]
flag_def_list Dock_type_names[]
Definition: modelread.cpp:115
#define OF_PLAYER_SHIP
Definition: object.h:109
#define OP_AI_DISABLE_SHIP
Definition: sexp.h:744
object * objp
Definition: lua.cpp:3105
void ai_add_goal_sub_player(int type, int mode, int submode, char *target_name, ai_goal *aigp)
Definition: aigoals.cpp:611
#define Int3()
Definition: pstypes.h:292
#define AI_GOAL_NONE
Definition: ai.h:194
ship * shipp
Definition: lua.cpp:9162
void ai_rearm_repair(object *objp, int docker_index, object *goal_objp, int dockee_index)
Definition: aicode.cpp:15493
int ai_flags
Definition: ai.h:330
int signature
Definition: object.h:145
GLenum type
Definition: Gl.h:1492
#define AIF_FORMATION_OBJECT
Definition: ai.h:43
void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags)
Definition: aicode.cpp:3215
#define AIG_TYPE_PLAYER_SHIP
Definition: ai.h:99
#define PURGE_GOALS_ONE_SHIP
Definition: aigoals.cpp:47
#define AI_ACTIVE_GOAL_DYNAMIC
Definition: ai.h:196
#define CDR(n)
Definition: sexp.h:821
int objnum
Definition: ship.h:1483
int object_is_docked(object *objp)
Definition: object.cpp:2019
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define AIS_DOCK_0
Definition: ai.h:269
int instance
Definition: object.h:150
void send_ai_info_update_packet(object *objp, char what, object *other_objp)
Definition: multimsgs.cpp:4943
#define DEPART_AT_DOCK_BAY
Definition: missionparse.h:246
void ai_add_goal_sub_sexp(int sexp, int type, ai_goal *aigp, char *actor_name)
Definition: aigoals.cpp:807
int model_find_dock_index(int modelnum, int dock_type, int index_to_start_at=0)
Definition: modelread.cpp:5031
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
#define AI_GOAL_NOT_KNOWN
Definition: aigoals.cpp:55
ship_subsys * ship_get_indexed_subsys(ship *sp, int index, vec3d *attacker_pos)
Definition: ship.cpp:13340
int type
Definition: ai.h:138
int mission_log_get_time(int type, char *pname, char *sname, fix *time)
Definition: missionlog.cpp:498
#define MAX_AI_BEHAVIORS
Definition: ai.h:189
#define LOG_WING_DESTROYED
Definition: missionlog.h:21
void ai_remove_wing_goal_sexp(int sexp, int wingnum)
Definition: aigoals.cpp:1175
#define LOG_SHIP_DISABLED
Definition: missionlog.h:29
void ai_add_goal_wing_internal(wing *wingp, int goal_type, char *name, int immediate)
Definition: aigoals.cpp:1324
#define nprintf(args)
Definition: pstypes.h:239
void ai_attack_wing(object *attacker, int wingnum)
Definition: aicode.cpp:2326
ai_goal_list Ai_goal_names[]
Definition: aigoals.cpp:62
SCP_vector< int > ai_cripple_ignores
Definition: ship.h:1041
char name[NAME_LENGTH]
Definition: ship.h:1517
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
int objnum
Definition: weapon.h:165
int wingnum
Definition: ship.h:623
void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type)
Definition: aicode.cpp:3098
#define MAX_STARTING_WINGS
Definition: globals.h:54
ai_goal goals[MAX_AI_GOALS]
Definition: ai.h:412
int subtype
Definition: sexp.h:1030
char Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH]
Definition: aigoals.cpp:60
int mode
Definition: ai.h:336
int shipnum
Definition: ai.h:331
fix time
Definition: ai.h:140
#define AIDO_UNDOCK
Definition: ai.h:83
object obj_create_list
Definition: object.cpp:54
#define OP_AI_DOCK
Definition: sexp.h:738
int Ai_goal_signature
Definition: aigoals.cpp:58
int ai_mode
Definition: ai.h:136
#define MAX_AI_GOALS
Definition: ai.h:91
#define OF_PROTECTED
Definition: object.h:108
#define OP_AI_EVADE_SHIP
Definition: sexp.h:748
#define SUBSYSTEM_TURRET
Definition: model.h:54
int target_instance
Definition: ai.h:146
void ai_do_default_behavior(object *obj)
Definition: aicode.cpp:14564
int priority
Definition: ai.h:141
#define AI_GOAL_STAY_STILL
Definition: aigoals.h:52
int Num_wings
Definition: ship.cpp:120
char * target_name
Definition: ai.h:143
#define AIG_TYPE_PLAYER_WING
Definition: ai.h:100
void ai_post_process_mission()
Definition: aigoals.cpp:159
object * dock_get_first_docked_object(object *objp)
Definition: objectdock.cpp:47
int ai_goal_priority_compare(const void *a, const void *b)
Definition: aigoals.cpp:1844
int current_count
Definition: ship.h:1530
int ai_query_goal_valid(int ship, int ai_goal_type)
Definition: aigoals.cpp:208
#define CDDDDR(n)
Definition: sexp.h:829
void insertion_sort(void *array_base, size_t array_size, size_t element_size, int(*fncompare)(const void *, const void *))
Definition: systemvars.cpp:599
#define SHIP_STATUS_NOT_ARRIVED
Definition: aigoals.cpp:1358
Definition: ship.h:534
#define REF_TYPE_WAYPOINT
Definition: sexp.h:839
int ai_find_goal_index(ai_goal *aigp, int mode, int submode, int priority)
Definition: aigoals.cpp:1017
#define AI_GOAL_EVADE_SHIP
Definition: aigoals.h:44
void prioritize_goals(ai_info *aip)
Definition: aigoals.cpp:1892
void validate_mission_goals(int objnum, ai_info *aip)
Definition: aigoals.cpp:1902
#define OP_AI_KEEP_SAFE_DISTANCE
Definition: sexp.h:750
#define AIF_AWAITING_REPAIR
Definition: ai.h:39
sexp_node * Sexp_nodes
Definition: sexp.cpp:844
#define OP_AI_STAY_STILL
Definition: sexp.h:752
void ai_update_goal_references(ai_goal *goals, int type, const char *old_name, const char *new_name)
Definition: aigoals.cpp:2295
#define SF_DISABLED
Definition: ship.h:448
#define AI_GOAL_IGNORE_NEW
Definition: aigoals.h:57
#define AI_GOAL_FLY_TO_SHIP
Definition: aigoals.h:56
#define REF_TYPE_PATH
Definition: sexp.h:840
bool ship_useful_for_departure(int shipnum, int path_mask)
Definition: ship.cpp:17448
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
#define AIM_DOCK
Definition: ai.h:174
#define AI_GOAL_PLAY_DEAD
Definition: aigoals.h:53
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
#define AI_GOAL_WAYPOINTS_ONCE
Definition: aigoals.h:32
#define OP_AI_CHASE_WING
Definition: sexp.h:772
#define OBJ_INDEX(objp)
Definition: object.h:235
ship * Player_ship
Definition: ship.cpp:124
int num_waves
Definition: ship.h:1522
#define LOG_SHIP_DESTROYED
Definition: missionlog.h:20
char * ai_get_goal_target_name(const char *name, int *index)
Definition: ai.cpp:85
void ai_start_fly_to_ship(object *objp, int shipnum)
Definition: aicode.cpp:3186
#define OBJ_SHIP
Definition: object.h:32
#define OP_AI_WAYPOINTS_ONCE
Definition: sexp.h:742
void ai_add_ship_goal_sexp(int sexp, int type, ai_info *aip)
Definition: aigoals.cpp:1201
#define AI_GOAL_SATISFIED
Definition: aigoals.cpp:56
#define AI_GOAL_GUARD_WING
Definition: aigoals.h:43
void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
Definition: aigoals.cpp:539
GLbitfield flags
Definition: Glext.h:6722
#define MAX_AI_DOCK_NAMES
Definition: aigoals.h:79
void ai_goal_purge_all_invalid_goals(ai_goal *aigp)
Definition: aigoals.cpp:465
int wing_name_lookup(const char *name, int ignore_count)
Definition: ship.cpp:12706
#define REF_TYPE_PLAYER
Definition: sexp.h:838
int Starting_wings[MAX_STARTING_WINGS]
Definition: ship.cpp:132
#define SHIP_STATUS_UNKNOWN
Definition: aigoals.cpp:1360
#define AIF_BEING_REPAIRED
Definition: ai.h:40
int is_sexp_true(int cur_node, int referenced_node)
Definition: sexp.cpp:22665
GLuint const GLchar * name
Definition: Glext.h:5608
#define AIGF_DOCKER_INDEX_VALID
Definition: ai.h:104
int Player_use_ai
#define OP_AI_UNDOCK
Definition: sexp.h:739
#define SUBSYSTEM_ENGINE
Definition: model.h:53
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
int model_find_dock_name_index(int modelnum, char *name)
Definition: modelread.cpp:5055
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define SF_DEPARTING
Definition: ship.h:475
#define REF_TYPE_SHIP
Definition: sexp.h:836
int total_arrived_count
Definition: ship.h:1528
GLuint GLuint num
Definition: Glext.h:9089
void ai_goal_purge_invalid_goals(ai_goal *aigp, ai_goal *goal_list, ai_info *aip, int ai_wingnum)
Definition: aigoals.cpp:377
#define OP_AI_DESTROY_SUBSYS
Definition: sexp.h:743
#define AIS_UNDOCK_0
Definition: ai.h:275
waypoint_list * find_matching_waypoint_list(const char *name)
Definition: waypoint.cpp:164
#define AIG_TYPE_DYNAMIC
Definition: ai.h:101
#define OP_AI_CHASE
Definition: sexp.h:737
char * ai_add_dock_name(const char *str)
Definition: aigoals.cpp:2427
#define AI_GOAL_KEEP_SAFE_DISTANCE
Definition: aigoals.h:48
#define NAME_LENGTH
Definition: globals.h:15
#define AIGF_DOCK_INDEXES_VALID
Definition: ai.h:114
#define AI_GOAL_DISABLE_SHIP
Definition: aigoals.h:39
void ai_maybe_add_form_goal(wing *wingp)
Definition: aigoals.cpp:134
#define PLAYER_PRIORITY_MIN
Definition: aigoals.cpp:35
waypoint_list * find_waypoint_list_at_index(int index)
Definition: waypoint.cpp:291
void ai_add_ship_goal_scripting(int mode, int submode, int priority, char *shipname, ai_info *aip)
Definition: aigoals.cpp:730
#define PLAYER_PRIORITY_WING
Definition: aigoals.cpp:37
int special_ship
Definition: ship.h:1537
void ai_mission_wing_goal_complete(int wingnum, ai_goal *remove_goalp)
Definition: aigoals.cpp:300
GLint first
Definition: Gl.h:1491
int current_wave
Definition: ship.h:1522
char subobj_name[MAX_NAME_LEN]
Definition: model.h:172
#define OP_AI_WARP
Definition: sexp.h:778
#define OP_AI_WAYPOINTS
Definition: sexp.h:741
ship_obj Ship_obj_list
Definition: ship.cpp:162
int ship_info_index
Definition: ship.h:539
#define MULTIPLAYER_MASTER
Definition: multi.h:130
void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
Definition: aigoals.cpp:1210
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define SHIP_STATUS_GONE
Definition: aigoals.cpp:1357
#define AIGF_PURGE
Definition: ai.h:109
#define AI_GOAL_CHASE_WEAPON
Definition: aigoals.h:54
#define OP_AI_STAY_NEAR_SHIP
Definition: sexp.h:749
int get_operator_const(const char *token)
Definition: sexp.cpp:1595
void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, char *target_name, ai_goal *aigp)
Definition: aigoals.cpp:705
union ai_goal::@0 docker
#define AI_GOAL_CHASE
Definition: aigoals.h:29
int departure_path_mask
Definition: ship.h:619
void ai_process_mission_orders(int objnum, ai_info *aip)
Definition: aigoals.cpp:1977
#define OP_AI_PLAY_DEAD
Definition: sexp.h:753
#define OP_AI_IGNORE
Definition: sexp.h:751
waypoint_list * wp_list
Definition: ai.h:145
void ai_set_guard_wing(object *objp, int wingnum)
Definition: aicode.cpp:7450
int first
Definition: sexp.h:1031
#define WPF_REPEAT
Definition: ai.h:295
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 goal_objnum
Definition: ai.h:355
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
#define OP_AI_DISARM_SHIP
Definition: sexp.h:745
int ship_get_subsys_index(ship *sp, char *ss_name, int error_bypass)
Definition: ship.cpp:13421
#define AIGF_TARGET_OWN_TEAM
Definition: ai.h:112
int ship_name_lookup(const char *name, int inc_players)
Definition: ship.cpp:12900
#define AIGF_GOAL_OVERRIDE
Definition: ai.h:108
uint flags
Definition: object.h:151
#define AIGF_DOCKEE_INDEX_VALID
Definition: ai.h:105
#define AI_GOAL_DESTROY_SUBSYSTEM
Definition: aigoals.h:34
#define PURGE_GOALS_ALL_SHIPS
Definition: aigoals.cpp:46
#define OP_AI_GUARD
Definition: sexp.h:746
void ai_evade_object(object *evader, object *evaded)
Definition: aicode.cpp:2362
int ai_mission_goal_achievable(int objnum, ai_goal *aigp)
Definition: aigoals.cpp:1365
char type
Definition: object.h:146
int ai_set_attack_subsystem(object *objp, int subnum)
Definition: aicode.cpp:7359
#define OP_AI_GUARD_WING
Definition: sexp.h:773
void ai_copy_mission_wing_goal(ai_goal *aigp, ai_info *aip)
Definition: aigoals.cpp:1340
#define OP_AI_WARP_OUT
Definition: sexp.h:740
void ai_do_safety(object *objp)
Definition: aicode.cpp:3273
#define AIM_PLAY_DEAD
Definition: ai.h:182
int index
Definition: ai.h:154
#define stricmp(s1, s2)
Definition: config.h:271
#define AIDO_DOCK
Definition: ai.h:81
#define SEXP_ATOM_STRING
Definition: sexp.h:913
#define AI_GOAL_FORM_ON_WING
Definition: aigoals.h:35
void ai_set_guard_object(object *objp, object *other_objp)
Definition: aicode.cpp:7532
int flags
Definition: ai.h:139
#define LOG_SHIP_DISARMED
Definition: missionlog.h:30
#define AI_UPDATE_ORDERS
Definition: multi.h:344
char ship_name[NAME_LENGTH]
Definition: ship.h:604
char docker_point[NAME_LENGTH]
#define PLAYER_PRIORITY_SHIP
Definition: aigoals.cpp:36
int signature
Definition: ai.h:135
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
#define LOG_SELF_DESTRUCTED
Definition: missionlog.h:39
#define AI_GOAL_ACHIEVABLE
Definition: aigoals.cpp:53
#define MAX_GOAL_PRIORITY
Definition: aigoals.cpp:40
int flags
Definition: ship.h:1556
ai_goal ai_goals[MAX_AI_GOALS]
Definition: ship.h:1558
#define AI_GOAL_NOT_ACHIEVABLE
Definition: aigoals.cpp:54
void ai_remove_ship_goal(ai_info *aip, int index)
Definition: aigoals.cpp:231