]> icculus.org git repositories - taylor/freespace2.git/blob - src/ship/aigoals.cpp
warning cleanup
[taylor/freespace2.git] / src / ship / aigoals.cpp
1 /*
2  * $Logfile: /Freespace2/code/Ship/AiGoals.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * File to deal with manipulating AI goals, etc.
8  *
9  * $Log$
10  * Revision 1.3  2002/05/26 22:06:17  relnev
11  * makefile: disable stand_gui for now.
12  *
13  * rest: staticize some globals
14  *
15  * Revision 1.2  2002/05/07 03:16:52  theoddone33
16  * The Great Newline Fix
17  *
18  * Revision 1.1.1.1  2002/05/03 03:28:10  root
19  * Initial import.
20  *
21  * 
22  * 12    7/19/99 12:02p Andsager
23  * Allow AWACS on any ship subsystem. Fix sexp_set_subsystem_strength to
24  * only blow up subsystem if its strength is > 0
25  * 
26  * 11    7/09/99 5:54p Dave
27  * Seperated cruiser types into individual types. Added tons of new
28  * briefing icons. Campaign screen.
29  * 
30  * 10    7/07/99 2:55p Andsager
31  * fix ai_get_subsystem_type to recognize "radara" as an awacs type
32  * subsystem as model_read.
33  * 
34  * 9     6/03/99 8:58p Andsager
35  * Fix bug where player's target is lost.  Alpha wing had clear wing
36  * goals, and this was applied to alpha1.
37  * 
38  * 8     5/27/99 12:14p Andsager
39  * Some fixes for live debris when more than one subsys on ship with live
40  * debris.  Set subsys strength (when 0) blows off subsystem.
41  * sexp_hits_left_subsystem works for SUBSYSTEM_UNKNOWN.
42  * 
43  * 7     4/23/99 12:01p Johnson
44  * Added SIF_HUGE_SHIP
45  * 
46  * 6     3/26/99 4:49p Dave
47  * Made cruisers able to dock with stuff. Made docking points and paths
48  * visible in fred.
49  * 
50  * 5     1/07/99 1:52p Andsager
51  * Initial check in of Sexp_variables
52  * 
53  * 4     12/23/98 2:53p Andsager
54  * Added ship activation and gas collection subsystems, removed bridge
55  * 
56  * 3     11/05/98 5:55p Dave
57  * Big pass at reducing #includes
58  * 
59  * 2     10/07/98 10:53a Dave
60  * Initial checkin.
61  * 
62  * 1     10/07/98 10:51a Dave
63  * 
64  * 173   6/09/98 10:31a Hoffoss
65  * Created index numbers for all xstr() references.  Any new xstr() stuff
66  * added from here on out should be added to the end if the list.  The
67  * current list count can be found in FreeSpace.cpp (search for
68  * XSTR_SIZE).
69  * 
70  * 172   6/01/98 11:43a John
71  * JAS & MK:  Classified all strings for localization.
72  * 
73  * 171   5/21/98 9:57a Mike
74  * Massively improve firing of bombs at big ships.  Improve willingness to
75  * take incoming fire to deliver bomb.  Make a little easier to gain
76  * aspect lock.
77  * 
78  * 170   5/12/98 10:06a Mike
79  * Fix a jillion bugs preventing ships from firing bombs at Lucifer in
80  * sm3-09.
81  * 
82  * 169   5/11/98 11:20a Sandeep
83  * 
84  * 168   5/10/98 12:02a Mike
85  * Only Alpha wing will form on player's wing, not any player wing.
86  * 
87  * 167   4/23/98 1:49a Allender
88  * major rearm/repair fixes for multiplayer.  Fixed respawning of AI ships
89  * to not respawn until 5 seconds after they die.  Send escort information
90  * to ingame joiners
91  * 
92  * 166   4/23/98 12:31a Mike
93  * Fix the sm1-04a Comet:Omega bug.  Was putting a goal on hold if a ship
94  * was docked, but should only have done that if not docked with self.
95  * 
96  * 165   4/22/98 5:00p Allender
97  * new multiplayer dead popup.  big changes to the comm menu system for  *
98  * team vs. team.  Start of debriefing stuff for team vs. team  Make form
99  * on my wing work with individual ships who have high priority 
100  * orders
101  * 
102  * 164   4/18/98 9:53p Mike
103  * Add debug code to track down Comet warpout problems in sm1-04a, then
104  * comment it out for checkin.
105  * 
106  * 163   4/09/98 12:36p Allender
107  * nasty repair problems fixed when ordering it to warp out while
108  * repairing (and on way) and when aborting process while he's completing
109  * the rearm
110  * 
111  * 162   3/31/98 5:19p John
112  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
113  * bunch of debug stuff out of player file.  Made model code be able to
114  * unload models and malloc out only however many models are needed.
115  *  
116  * 
117  * 161   3/19/98 4:43p Allender
118  * allow player ships to follow certain orders
119  * 
120  * 160   3/19/98 2:55p Allender
121  * when ship gets disabled, have him put dock goals on hold
122  * 
123  * 159   3/09/98 9:35p Mike
124  * Suppress warning messages.
125  * 
126  * 158   3/09/98 5:12p Mike
127  * Make sure Pl_objp uses are valid.
128  * Throw asteroids at ships in asteroid field, not "Gal"
129  * Support ships warp out if no goals after 30 seconds.
130  * 
131  * 157   3/07/98 3:50p Lawrance
132  * Add lead indicator for asteroids
133  * 
134  * 156   3/06/98 2:58p Allender
135  * moved assert to more appropriate place
136  * 
137  * 155   3/06/98 11:55a Lawrance
138  * Don't process mission orders for player ships
139  * 
140  * 154   3/05/98 9:35a Allender
141  * don't allow ships to be repaired when departing or dying
142  * 
143  * 153   2/26/98 10:08p Hoffoss
144  * Rewrote state saving and restoring to fix bugs and simplify the code.
145  * 
146  * 152   2/23/98 8:59p Allender
147  * fixed two docking bugs:  1) don't move cargo when ship it's docked with
148  * is undocking.  2) aigoal code was clearing dock goals when it shouldn't
149  * have been
150  * 
151  * 151   2/22/98 4:17p John
152  * More string externalization classification... 190 left to go!
153  * 
154  * 150   2/19/98 12:04a Allender
155  * more multiplayer rearm/dock stuff.  Fix bug in HUD code when finding
156  * support ship reaming player.  show repair as order on Hud extended
157  * target info
158  * 
159  * 149   2/18/98 10:34p Allender
160  * repair/rearm system (for single and multi) about finished.
161  * dock/undock and ai goals packets implemented for multiplayer
162  * 
163  * 148   2/16/98 10:13p Allender
164  * initial work on being able to target weapons (bombs specifically).
165  * Work on getting rearm/repair working under multiplayer
166  * 
167  * 147   2/16/98 4:07p Sandeep
168  * fixed a bug with deleting waypoints
169  * 
170  * 146   2/16/98 3:43p Sandeep
171  * Fixed bug with Ai_warp still expected to have an object reference in a
172  * bit of the code.
173  * 
174  * 145   2/13/98 3:21p Lawrance
175  * Set up allowed goals for escape pods.
176  * 
177  * 144   2/13/98 2:57p Allender
178  * correct code using unitialized variable
179  * 
180  * 143   2/09/98 10:46a Allender
181  * fixed bug with docking where multiple orders to dock with same object
182  * caused strageness
183  * 
184  * 142   2/05/98 12:52p Jim
185  * fix race conditions to get to subsystem index for attacking subsystem
186  * goals
187  * 
188  * 141   2/02/98 4:02p Mike
189  * Allender: Fix bug which caused ships to sometimes undock just as they
190  * were docking.
191  * 
192  * 140   1/30/98 11:00a Allender
193  * tidied up the code to get an index for a new goal.  Made all code (for
194  * both ships and wings) go through this function.
195  * 
196  * 139   1/30/98 10:01a Allender
197  * made large ships able to attack other ships.  Made goal code recognize
198  * when ships removed from wings during ship select
199  * 
200  * 138   1/29/98 12:14p Lawrance
201  * show 'waypoints' as a mission order.
202  * 
203  * 137   1/20/98 9:33a Allender
204  * fixed bug with wing goals from players
205  * 
206  * 136   1/16/98 1:11p Sandeep
207  * fix bug when trying to purge goals with no ship_name
208  * 
209  * 135   1/16/98 11:43a Allender
210  * made it so certain orders (see PURGE_ORDERS) cause other ai goals to
211  * get purged.  This step it to help the AI do the right thing.
212  * 
213  * 134   1/16/98 11:33a Mike
214  * Fix bug in targeting subsystems on protected ships.
215  * 
216  * 133   1/13/98 5:36p Lawrance
217  * Change Ai_goal_text[] to not return anything for waypoints.
218  * 
219  * 132   1/05/98 10:10p Mike
220  * Comment out an obsolete function (discovered while searching for
221  * something else.)
222  * 
223  * 131   1/02/98 1:55p Duncan
224  * added back in case for undocking when checking for goal complete status
225  * 
226  * 130   12/30/97 4:48p Allender
227  * work with ignore my target command.  Added new keyboard hotkey.  Made
228  * it work globally
229  * 
230  * 129   12/26/97 12:15p Mike
231  * Put in debug code for tracking down ships disabling, rather than
232  * destroying, enemies.
233  * 
234  * 128   12/15/97 5:25p Allender
235  * fix problem with docked ships receiving another dock goal.  They now
236  * properly undock
237  * 
238  * 127   12/12/97 5:21p Lawrance
239  * fix some problems with ai mode changing when arriving/departing from
240  * docking bays
241  * 
242  * 126   12/04/97 12:24p Allender
243  * made support ship orders other than rearm be super low priority.
244  * Support ship orders now won't get removed incorrectly either
245  * 
246  * 125   11/26/97 9:55a Allender
247  * minor changed to comm window for rearming.  Fixed some repair bugs --
248  * player's repair was getting aborted by code when he was hit.  Repair
249  * ship wasn't properly removing repair goals
250  * 
251  * 124   11/23/97 6:21p Lawrance
252  * update goal text, used on HUD
253  * 
254  * 123   11/17/97 6:39p Lawrance
255  * add AI_goal_text[] array, used by HUD code to show text description of
256  * order
257  * 
258  * 122   11/09/97 2:21p Mike
259  * Comment out Int3() and email Mark about it.
260  * 
261  * 121   11/05/97 9:30p Mike
262  * Add play dead mode.
263  * Enable undock to complete when dockee moves.
264  * Make ships in waypoint mode react to enemy fire.
265  * Support ships not form on player's wing.
266  * 
267  * 120   11/05/97 4:43p Allender
268  * reworked medal/rank system to read all data from tables.  Made Fred
269  * read medals.tbl.  Changed ai-warp to ai-warp-out which doesn't require
270  * waypoint for activation
271  * 
272  * 119   10/31/97 4:03p Allender
273  * test code to help find rearm/repair problems
274  * 
275  * 118   10/29/97 10:02p Allender
276  * be sure that player starting wings that arrive late also form on the
277  * players wing if there are no goals
278  * 
279  * 117   10/29/97 9:32p Allender
280  * remove undock goal if we can't find docked sihp when docker trying to
281  * undock.  Could be that docked ship was destroyed
282  * 
283  * 116   10/29/97 3:41p Sandeep
284  * Allender put in dock debug code
285  * 
286  * 115   10/28/97 10:30a Allender
287  * rest AIF_FORMATION_OBJECT bit when new order is given to a ship
288  * 
289  * 114   10/24/97 10:40a Allender
290  * player wings with no initial orders now form on players wing by
291  * default.
292  * 
293  * 113   10/23/97 4:41p Allender
294  * lots of new rearm/repair code.  Rearm requests now queue as goals for
295  * support ship.  Warp in of new support ships functional.  Support for
296  * stay-still and play-dead.  
297  * 
298  * 112   10/23/97 4:12p Mike
299  * Support for AIM_STAY_NEAR.
300  * 
301  * 111   10/22/97 1:46p Allender
302  * get ship_name field for ai-stay-still
303  * 
304  * 110   10/22/97 1:44p Allender
305  * more work on stay-still and play-dead
306  * 
307  * 109   10/22/97 11:07a Allender
308  * Hooked in form on my wing into Mikes AI code
309  * 
310  * 108   10/22/97 1:03a Mike
311  * ai-stay-still
312  * form-on-my-wing
313  * fix mysterious code in find_enemy that used goal_objnum instead of
314  * target_objnum.
315  * 
316  * 107   10/12/97 11:23p Mike
317  * About ten fixes/changes in the docking system.
318  * Also, renamed SIF_REARM_REPAIR to SIF_SUPPORT.
319  * 
320  * 106   10/10/97 5:03p Allender
321  * started work on ai-stay-still
322  * 
323  * 105   9/24/97 4:51p Allender
324  * got rid pf default_player_ship_name variable.
325  * 
326  * 104   9/23/97 4:35p Allender
327  * added two function to add "internal" goals to ships and wings.  Used by
328  * AI when it needs to do something special
329  * 
330  * 103   9/09/97 2:42p Allender
331  * fix bug where guarding a wing that hasn't arrived caused goal code to
332  * crash
333  * 
334  * 102   9/09/97 11:28a Johnson
335  * Fixed bug: Code is not Fred-aware.
336  * 
337  * 101   9/08/97 1:04p Allender
338  * put code in ai_post_process_mission() to set orders for ships before
339  * mission starts.  Prevents ships from following orders N seconds after
340  * mission actually starts
341  * 
342  * 100   9/05/97 5:05p Lawrance
343  * memset string to 0 during restore for safety
344  * 
345  * 99    8/18/97 1:16p Allender
346  * added ignore goal into sexpressions
347  * 
348  * 98    8/16/97 3:09p Mike
349  * If telling a ship to attack a protected ship, unprotect that ship.
350  * 
351  * 97    8/16/97 2:40p Mike
352  * Move unmoving ship if it's attacking a large ship and it sees incoming
353  * fire.
354  * Also, don't set protected bit in a ship if someone has attacked a
355  * subsystem.  Only do if someone was told to disarm or disable.
356  * 
357  * 96    8/15/97 11:50a Duncan
358  * Fixed bug with ai functions assuming ai_goal_undock takes a ship
359  * target, which it doesn't.
360  * 
361  * 95    8/15/97 10:05a Hoffoss
362  * One more change to ai_query_goal_valid() to allow for AI_GOAL_NONE.
363  * 
364  * 94    8/15/97 9:59a Hoffoss
365  * Changed ai_query_goal_valid() again.  I can't think of any time you
366  * wouldn't find it easier just to pass in a ship instead of a ship_info
367  * flag structure filtered of all flags that aren't ship type bits.  Since
368  * I'll call this quite a few times, it will make my life easier.
369  * 
370  * 93    8/15/97 9:49a Hoffoss
371  * Changed ai_query_goal_valid() slightly for Fred.  Fred can be more
372  * detailed with error messages should these situations happen, and
373  * recover from them better.
374  * 
375  * 92    8/14/97 10:00p Allender
376  * made ai goals bitfields so that we can have set of orders that certain
377  * ship types are allowed to receive.  Added function for Hoffoss to check
378  * goal vs. ship type validity
379  * 
380  * 91    8/12/97 9:58a Hoffoss
381  * Fixed ai_update_goal_references() and query_referended_in_ai_goals().
382  * 
383  * 90    8/12/97 8:01a Allender
384  * when adding goals to wing structures, replace the oldest entry of the
385  * goals if there are no empty entries
386  * 
387  * 89    8/12/97 1:55a Hoffoss
388  * Made extensive changes to object reference checking and handling for
389  * object deletion call.
390  * 
391  * 88    8/10/97 4:24p Hoffoss
392  * Made initial orders revert back to none if it has invalid data
393  * anywhere.
394  * 
395  * 87    8/08/97 1:30p Allender
396  * added commands (and ai goals) for support ships.  stay near ship (which
397  * could be player or current target), and keep safe distance
398  * 
399  * 86    8/07/97 11:11a Allender
400  * fixed problem with wings completing waypoint goals
401  * 
402  * 85    8/06/97 9:41a Allender
403  * renamed from ai_goal function.  made a function to remove a goal from a
404  * wing (used strictly for waypoints now).  ai-chase-wing and
405  * ai-guard-wing now appear to user as ai-chase and ai-guard.  Tidied up
406  * function which deals with sexpression goals
407  * 
408  * 84    8/06/97 8:06a Lawrance
409  * add more stuff to save/restore
410  * 
411  * 83    8/01/97 11:51a Dave
412  * Changed calls to timer_get_fixed_seconds() to simply Missiontime.
413  * Solves a lot of demo related problems.
414  * 
415  * 82    7/30/97 11:01p Mike
416  * Set submode when setting mode from player order.
417  * Increase distance to circle when ignoring player's target.
418  * 
419  * 81    7/28/97 10:28a Mike
420  * Use forward_interpolate() to prevent weird banking behavior.
421  * 
422  * Suppress a couple annoying mprints and clarify another.
423  * 
424  * 80    7/25/97 12:10p Mike
425  * Better default behavior.
426  * 
427  * 79    7/24/97 4:55p Allender
428  * added ai-evade-ship to fred and to Freespace
429  * 
430  * 78    7/24/97 4:20p Mike
431  * Add goal and Fred hook for evade behavior.
432  * 
433  * 77    7/24/97 2:17p Jasen
434  * Fixed a bug with mission loading.
435  * 
436  * 76    7/24/97 12:10a Mike
437  * Suppress problems when loadign pain.fsm.
438  * 
439  * 75    7/23/97 6:49p Hoffoss
440  * Fixed bug in ai goal adding code.  It was using a pointer that was
441  * temporary.
442  * 
443  * 74    7/23/97 11:25a Allender
444  * more robust sexpression checking.  Fixed problem with some ai goals not
445  * being named properly
446  *
447  * $NoKeywords: $
448  */
449
450 #include "aigoals.h"
451 #include "freespace.h"
452 #include "ai.h"
453 #include "sexp.h"
454 #include "missionlog.h"
455 #include "missionparse.h"
456 #include "model.h"                              // for subsystem types
457 #include "linklist.h"
458 #include "timer.h"
459 #include "player.h"
460 #include "multimsgs.h"
461 #include "multi.h"
462
463 // all ai goals dealt with in this code are goals that are specified through
464 // sexpressions in the mission file.  They are either specified as part of a
465 // ships goals in the #Object section of the mission file, or are created (and
466 // removed) dynamically using the #Events section.  Default goal behaviour and
467 // dynamic goals are not handled here.
468
469 // defines for player issued goal priorities
470 #define PLAYER_PRIORITY_MIN                             90
471 #define PLAYER_PRIORITY_SHIP                            100
472 #define PLAYER_PRIORITY_WING                            95
473 #define PLAYER_PRIORITY_SUPPORT_LOW             10
474
475 // define for which goals cause other goals to get purged
476 #define PURGE_GOALS             (AI_GOAL_IGNORE | AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP)
477
478 // goals given from the player to other ships in the game are also handled in this
479 // code
480
481
482 #define AI_GOAL_ACHIEVABLE                      1
483 #define AI_GOAL_NOT_ACHIEVABLE  2
484 #define AI_GOAL_NOT_KNOWN                       3
485 #define AI_GOAL_SATISFIED                       4
486
487 int     Ai_goal_signature;
488 int     Num_ai_dock_names = 0;
489 char    Ai_dock_names[MAX_AI_DOCK_NAMES][NAME_LENGTH];
490
491 // AL 11-17-97: A text description of the AI goals.  This is used for printing out on the
492 // HUD what a ship's current orders are.  If the AI goal doesn't correspond to something that
493 // ought to be printable, then NULL is used.
494 // JAS: Converted to a function in order to externalize the strings
495 char *Ai_goal_text(int goal)
496 {
497         switch(goal)    {
498         case 1:
499                 return XSTR( "attack ", 474);
500         case 2:
501                 return XSTR( "dock ", 475);
502         case 3:
503                 return XSTR( "waypoints", 476);
504         case 4:
505                 return XSTR( "waypoints", 476);
506         case 6:
507                 return XSTR( "destroy ", 477);
508         case 7:
509                 return XSTR( "form on ", 478);
510         case 8:
511                 return XSTR( "undock ", 479);
512         case 9:
513                 return XSTR( "attack ", 474);
514         case 10:
515                 return XSTR( "guard ", 480);
516         case 11:
517                 return XSTR( "disable ", 481);
518         case 12:
519                 return XSTR( "disarm ", 482);
520         case 15:
521                 return XSTR( "guard ", 480);
522         case 16:
523                 return XSTR( "evade ", 483);
524         case 19:
525                 return XSTR( "rearm ", 484);
526         }
527
528         // Avoid compiler warning
529         return NULL;
530 };
531
532 // function to maybe add the form on my wing goal for a player's starting wing.  Called from below and when a
533 // player wing arrives.
534 void ai_maybe_add_form_goal( wing *wingp )
535 {
536         int j;
537
538         // iterate through the ship_index list of this wing and check for orders.  We will do
539         // this for all ships in the wing instead of on a wing only basis in cases some ships
540         // in the wing actually have different orders than others
541         for ( j = 0; j < wingp->current_count; j++ ) {
542                 ai_info *aip;
543
544                 Assert( wingp->ship_index[j] != -1 );                                           // get Allender
545
546                 aip = &Ai_info[Ships[wingp->ship_index[j]].ai_index];
547                 // don't process Player_ship
548                 if ( aip == Player_ai )
549                         continue;
550                 
551                 // it is sufficient enough to check the first goal entry to see if it has a valid
552                 // goal
553                 if ( aip->goals[0].ai_mode == AI_GOAL_NONE ) {
554                         // need to add a form on my wing goal here.  Ships are always forming on the player's wing.
555                         ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FORM_ON_WING, -1, Player_ship->ship_name, aip );
556                 }
557         }
558 }
559
560 void ai_post_process_mission()
561 {
562         object *objp;
563         int i;
564
565         // Check ships in player starting wings.  Those ships should follow these rules:
566         // (1) if they have no orders, they should get a form on my wing order
567         // (2) if they have an order, they are free to act on it.
568         //
569         // So basically, we are checking for (1)
570         if ( !Fred_running ) {
571                 for ( i = 0; i < 1; i++ ) {     //      MK, 5/9/98: Used to iterate through MAX_PLAYER_WINGS, but this was too many ships forming on player.
572                         if ( Starting_wings[i] != -1 ) {
573                                 wing *wingp;
574
575                                 wingp = &Wings[Starting_wings[i]];
576
577                                 ai_maybe_add_form_goal( wingp );
578
579                         }
580                 }
581         }
582
583         // for every valid ship object, call process_mission_orders to be sure that ships start the
584         // mission following the orders in the mission file right away instead of waiting N seconds
585         // before following them.  Do both the created list and the object list for safety
586         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
587                 if ( objp->type != OBJ_SHIP )
588                         continue;
589                 ai_process_mission_orders( OBJ_INDEX(objp), &Ai_info[Ships[objp->instance].ai_index] );
590         }
591         for ( objp = GET_FIRST(&obj_create_list); objp != END_OF_LIST(&obj_create_list); objp = GET_NEXT(objp) ) {
592                 if ( (objp->type != OBJ_SHIP) || Fred_running )
593                         continue;
594                 ai_process_mission_orders( OBJ_INDEX(objp), &Ai_info[Ships[objp->instance].ai_index] );
595         }
596
597         return;
598 }
599
600 // function which determines is a goal is valid for a particular type of ship
601 int ai_query_goal_valid( int ship, int ai_goal )
602 {
603         int accepted;
604
605         if (ai_goal == AI_GOAL_NONE)
606                 return 1;  // anything can have no orders.
607
608         accepted = 0;
609         switch (Ship_info[Ships[ship].ship_info_index].flags & SIF_ALL_SHIP_TYPES) {
610         case SIF_CARGO:
611                 if (!Fred_running)
612                         Int3();                 // get Hoffoss or Allender -- cargo containers shouldn't have a goal!!!
613                 break;
614
615         case SIF_FIGHTER:
616                 if ( ai_goal & AI_GOAL_ACCEPT_FIGHTER ){
617                         accepted = 1;
618                 }
619                 break;
620         case SIF_BOMBER:
621                 if ( ai_goal & AI_GOAL_ACCEPT_BOMBER ){
622                         accepted = 1;
623                 }
624                 break;
625         case SIF_CRUISER:
626                 if ( ai_goal & AI_GOAL_ACCEPT_CRUISER ){
627                         accepted = 1;
628                 }
629                 break;
630         case SIF_FREIGHTER:
631                 if ( ai_goal & AI_GOAL_ACCEPT_FREIGHTER ){
632                         accepted = 1;
633                 }
634                 break;
635         case SIF_CAPITAL:
636                 if ( ai_goal & AI_GOAL_ACCEPT_CAPITAL ){
637                         accepted = 1;
638                 }
639                 break;
640         case SIF_TRANSPORT:
641                 if ( ai_goal & AI_GOAL_ACCEPT_TRANSPORT ){
642                         accepted = 1;
643                 }
644                 break;
645         case SIF_SUPPORT:
646                 if ( ai_goal & AI_GOAL_ACCEPT_SUPPORT ){
647                         accepted = 1;
648                 }
649                 break;
650         case SIF_ESCAPEPOD:
651                 if ( ai_goal & AI_GOAL_ACCEPT_ESCAPEPOD ){
652                         accepted = 1;
653                 }
654                 break;
655         case SIF_SUPERCAP:
656                 if ( ai_goal & AI_GOAL_ACCEPT_SUPERCAP ){
657                         accepted = 1;
658                 }
659                 break;
660         case SIF_STEALTH:
661                 if ( ai_goal & AI_GOAL_ACCEPT_STEALTH ){
662                         accepted = 1;
663                 }
664                 break;          
665         case SIF_CORVETTE:
666                 if ( ai_goal & AI_GOAL_ACCEPT_CORVETTE ){
667                         accepted = 1;
668                 }
669                 break;
670         case SIF_GAS_MINER:
671                 if ( ai_goal & AI_GOAL_ACCEPT_GAS_MINER ){
672                         accepted = 1;
673                 }
674                 break;
675         case SIF_AWACS:
676                 if ( ai_goal & AI_GOAL_ACCEPT_AWACS ){
677                         accepted = 1;
678                 }
679                 break;
680         case SIF_NO_SHIP_TYPE:
681                 if (!Fred_running){
682                         Int3();                 // HUH?  doesn't make sense
683                 }
684                 break;
685         default:
686                 if (!Fred_running){
687                         Int3();                 // get allender or hoffos -- unknown ship type
688                 }
689                 break;
690         }
691
692         return accepted;
693 }
694
695 // remove an ai goal from it's list.  Uses the active_goal member as the goal to remove
696 void ai_remove_ship_goal( ai_info *aip, int index )
697 {
698         // only need to set the ai_mode for the particular goal to AI_GOAL_NONE
699         // reset ai mode to default behavior.  Might get changed next time through
700         // ai goal code look
701         Assert ( index >= 0 );                  // must have a valid goal
702
703         aip->goals[index].ai_mode = AI_GOAL_NONE;
704         aip->goals[index].signature = -1;
705         aip->goals[index].priority = -1;
706         aip->goals[index].flags = 0;                            // must reset the flags since not doing so will screw up goal sorting.
707         if ( index == aip->active_goal )
708                 aip->active_goal = AI_GOAL_NONE;
709
710         // mwa -- removed this line 8/5/97.  Just because we remove a goal doesn't mean to do the default
711         // behavior.  We will make the call commented out below in a more reasonable location
712         //ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );
713 }
714
715 void ai_clear_ship_goals( ai_info *aip )
716 {
717         int i;
718
719         for (i = 0; i < MAX_AI_GOALS; i++)
720                 ai_remove_ship_goal( aip, i );                  // resets active_goal and default behavior
721
722         aip->active_goal = AI_GOAL_NONE;                                        // for good measure
723
724         // next line moved here on 8/5/97 by MWA
725         // Dont reset player ai (and hence target)
726         if ( !((Player_ship != NULL) && (&Ships[aip->shipnum] == Player_ship)) ) {
727                 ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );
728         }
729 }
730
731 void ai_clear_wing_goals( int wingnum )
732 {
733         int i;
734         wing *wingp = &Wings[wingnum];
735         //p_object *objp;
736
737         // clear the goals for all ships in the wing
738         for (i = 0; i < wingp->current_count; i++) {
739                 int num = wingp->ship_index[i];
740
741                 if ( num > -1 )
742                         ai_clear_ship_goals( &Ai_info[Ships[num].ai_index] );
743
744         }
745
746                 // clear out the goals for the wing now
747         for (i = 0; i < MAX_AI_GOALS; i++) {
748                 wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
749                 wingp->ai_goals[i].signature = -1;
750                 wingp->ai_goals[i].priority = -1;
751         }
752
753
754 }
755
756 // routine which marks a wing goal as being complete.  We get the wingnum and a pointer to the goal
757 // structure of the goal to be removed.  This process is slightly tricky since some member of the wing
758 // might be pursuing a different goal.  We will have to compare based on mode, submode, priority,
759 // and name.. This routine is only currently called from waypoint code!!!
760 void ai_mission_wing_goal_complete( int wingnum, ai_goal *remove_goalp )
761 {
762         int mode, submode, priority, i;
763         char *name;
764         ai_goal *aigp;
765         wing *wingp;
766
767         wingp = &Wings[wingnum];
768
769         // set up locals for faster access.
770         mode = remove_goalp->ai_mode;
771         submode = remove_goalp->ai_submode;
772         priority = remove_goalp->priority;
773         name = remove_goalp->ship_name;
774
775         Assert ( name );                        // should not be NULL!!!!
776
777         // remove the goal from all the ships currently in the wing
778         for (i = 0; i < wingp->current_count; i++ ) {
779                 int num, j;
780                 ai_info *aip;
781
782                 num = wingp->ship_index[i];
783                 Assert ( num >= 0 );
784                 aip = &Ai_info[Ships[num].ai_index];
785                 for ( j = 0; j < MAX_AI_GOALS; j++ ) {
786                         aigp = &(aip->goals[j]);
787
788                         // don't need to worry about these types of goals since they can't possibly be a goal we are looking for.
789                         if ( (aigp->ai_mode == AI_GOAL_NONE) || !aigp->ship_name )
790                                 continue;
791
792                         if ( (aigp->ai_mode == mode) && (aigp->ai_submode == submode) && (aigp->priority == priority) && !stricmp(name, aigp->ship_name) ) {
793                                 ai_remove_ship_goal( aip, j );
794                                 ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );         // do the default behavior
795                                 break;                  // we are all done
796                         }
797                 }
798         }
799
800         // now remove the goal from the wing
801         for (i = 0; i < MAX_AI_GOALS; i++ ) {
802                 aigp = &(wingp->ai_goals[i]);
803                 if ( (aigp->ai_mode == AI_GOAL_NONE) || !aigp->ship_name )
804                         continue;
805
806                 if ( (aigp->ai_mode == mode) && (aigp->ai_submode == submode) && (aigp->priority == priority) && !stricmp(name, aigp->ship_name) ) {
807                         wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
808                         wingp->ai_goals[i].signature = -1;
809                         wingp->ai_goals[i].priority = -1;
810                         break;
811                 }
812         }
813                         
814 }
815
816 // routine which is called with an ai object complete it's goal.  Do some action
817 // based on the goal what was just completed
818
819 void ai_mission_goal_complete( ai_info *aip )
820 {
821         // if the active goal is dynamic or none, just return.  (AI_GOAL_NONE is probably an error, but
822         // I don't think that this is a problem)
823         if ( (aip->active_goal == AI_GOAL_NONE) || (aip->active_goal == AI_ACTIVE_GOAL_DYNAMIC) )
824                 return;
825
826         ai_remove_ship_goal( aip, aip->active_goal );
827         ai_do_default_behavior( &Objects[Ships[aip->shipnum].objnum] );         // do the default behavior
828
829 }
830
831 int ai_get_subsystem_type( char *subsystem )
832 {
833         if ( strstr(subsystem, "engine") ) {
834                 return SUBSYSTEM_ENGINE;
835         } else if ( strstr(subsystem, "radar") ) {
836                 return SUBSYSTEM_RADAR;
837         } else if ( strstr(subsystem, "turret") ) {
838                 return SUBSYSTEM_TURRET;
839         } else if ( strstr(subsystem, "navigation") ) {
840                 return SUBSYSTEM_NAVIGATION;
841         } else if ( !strnicmp(subsystem, NOX("communication"), 13) ) {
842                 return SUBSYSTEM_COMMUNICATION;
843         } else if ( !strnicmp(subsystem, NOX("weapons"), 7) )  {
844                 return SUBSYSTEM_WEAPONS;
845         } else if ( !strnicmp(subsystem, NOX("sensors"), 7) )  {
846                 return SUBSYSTEM_SENSORS;
847         } else if ( !strnicmp(subsystem, NOX("solar"), 5) )  {
848                 return SUBSYSTEM_SOLAR;
849         } else if ( !strnicmp(subsystem, NOX("gas"), 3) )  {
850                 return SUBSYSTEM_GAS_COLLECT;
851         } else if ( !strnicmp(subsystem, NOX("activator"), 9) )  {
852                 return SUBSYSTEM_ACTIVATION;
853         } else {                                                                        // If unrecognized type, set to engine so artist can continue working...
854                 if (!Fred_running) {
855 //                      Int3();                                                 // illegal subsystem type -- find allender
856                 }
857
858                 return SUBSYSTEM_UNKNOWN;
859         }
860 }
861
862 // function to prune out goals which are no longer valid, based on a goal pointer passed in.
863 // for instance, if we get passed a goal of "disable X", then any goals in the given goal array
864 // which are destroy, etc, should get removed.  goal list is the list of goals to purge.  It is
865 // always MAX_AI_GOALS in length.  This function will only get called when the goal which causes
866 // purging becomes valid.
867 void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list )
868 {
869         int i;
870         ai_goal *purge_goal;
871         char *name;
872         int mode, ship_index, wingnum;
873
874         // get locals for easer access
875         name = aigp->ship_name;
876         mode = aigp->ai_mode;
877
878         // these goals cannot be associated to wings, but can to a ship in a wing.  So, we should find out
879         // if the ship is in a wing so we can purge goals which might operate on that wing
880         ship_index = ship_name_lookup(name);
881         if ( ship_index == -1 ) {
882                 Int3();                                         // get allender -- this is sort of odd
883                 return;
884         }
885         wingnum = Ships[ship_index].wingnum;
886
887         purge_goal = goal_list;
888         for ( i = 0; i < MAX_AI_GOALS; purge_goal++, i++ ) {
889                 int purge_ai_mode, purge_wing;
890
891                 purge_ai_mode = purge_goal->ai_mode;
892
893                 // don't need to process AI_GOAL_NONE
894                 if ( purge_ai_mode == AI_GOAL_NONE )
895                         continue;
896
897                 // goals must operate on something to be purged.
898                 if ( purge_goal->ship_name == NULL )
899                         continue;
900
901                 // determine if the purge goal is acting either on the ship or the ship's wing.
902                 purge_wing = wing_name_lookup( purge_goal->ship_name, 1 );
903
904                 // if the target of the purge goal is a ship (purge_wing will be -1), then if the names
905                 // don't match, we can continue;  if the wing is valid, don't process if the wing numbers
906                 // are different.
907                 if ( purge_wing == -1 ) {
908                         if ( stricmp(purge_goal->ship_name, name ) )
909                                 continue;
910                 } else if ( purge_wing != wingnum )
911                         continue;
912
913                 switch( mode ) {
914                 // ignore goals should get rid of any kind of attack goal
915                 case AI_GOAL_IGNORE:
916                         if ( purge_ai_mode & (AI_GOAL_DISABLE_SHIP | AI_GOAL_DISARM_SHIP | AI_GOAL_CHASE | AI_GOAL_CHASE_WING | AI_GOAL_DESTROY_SUBSYSTEM) )
917                                 purge_goal->flags |= AIGF_PURGE;
918                         break;
919
920                 // disarm/disable goals should remove any general attack
921                 case AI_GOAL_DISABLE_SHIP:
922                 case AI_GOAL_DISARM_SHIP:
923                         if ( purge_ai_mode & (AI_GOAL_CHASE | AI_GOAL_CHASE_WING) )
924                                 purge_goal->flags |= AIGF_PURGE;
925                         break;
926                 }
927         }
928 }
929
930 // function to purge the goals of all ships in the game based on the incoming goal structure
931 void ai_goal_purge_all_invalid_goals( ai_goal *aigp )
932 {
933         int mode, i;
934         ship_obj *sop;
935
936         mode = aigp->ai_mode;
937
938         // only purge goals if a new goal is one of the types in next statement
939         if ( !(mode & PURGE_GOALS) )
940                 return;
941
942         for ( sop = GET_FIRST(&Ship_obj_list); sop != END_OF_LIST(&Ship_obj_list); sop = GET_NEXT(sop) ) {
943                 ship *shipp;
944
945                 shipp = &Ships[Objects[sop->objnum].instance];
946                 ai_goal_purge_invalid_goals( aigp, Ai_info[shipp->ai_index].goals );
947         }
948
949         // we must do the same for the wing goals
950         for (i = 0; i < num_wings; i++ )
951                 ai_goal_purge_invalid_goals( aigp, Wings[i].ai_goals );
952 }
953
954 // function to fix up dock point references for objects.
955 // passed are the pointer to goal we are working with.  aip if the ai_info pointer
956 // of the ship with the order.  aigp is a pointer to the goal (of aip) of which we are
957 // fixing up the docking points
958 void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
959 {
960         int shipnum, dockee_index, docker_index;
961
962         Assert ( aip->shipnum != -1 );
963         shipnum = ship_name_lookup( aigp->ship_name );
964         docker_index = -1;
965         dockee_index = -1;
966
967         // look for docking points of the appriopriate type.  Use cargo docks for cargo ships.
968         // use 
969         if ( Ship_info[Ships[shipnum].ship_info_index].flags & SIF_CARGO ) {
970                 docker_index = model_find_dock_index(Ships[aip->shipnum].modelnum, DOCK_TYPE_CARGO );
971                 dockee_index = model_find_dock_index(Ships[shipnum].modelnum, DOCK_TYPE_CARGO );
972         } else if ( Ship_info[Ships[aip->shipnum].ship_info_index].flags & SIF_SUPPORT ) {
973                 docker_index = model_find_dock_index( Ships[aip->shipnum].modelnum, DOCK_TYPE_REARM );
974                 dockee_index = model_find_dock_index( Ships[shipnum].modelnum, DOCK_TYPE_REARM );
975         }
976
977         // if we didn't find dockpoints above, then we should just look for generic docking points
978         if ( docker_index == -1 )
979                 docker_index = model_find_dock_index(Ships[aip->shipnum].modelnum, DOCK_TYPE_GENERIC );
980         if ( dockee_index == -1 )
981                 dockee_index = model_find_dock_index(Ships[shipnum].modelnum, DOCK_TYPE_GENERIC );
982                 
983         aigp->docker.index = docker_index;
984         aigp->dockee.index = dockee_index;
985         aigp->flags &= ~(AIGF_DOCKER_NAME_VALID | AIGF_DOCKEE_NAME_VALID);
986 }
987
988 // these functions deal with adding goals sent from the player.  They are slightly different
989 // from the mission goals (i.e. those goals which come from events) in that we don't
990 // use sexpressions for goals from the player...so we enumerate all the parameters
991
992 void ai_add_goal_sub_player(int type, int mode, int submode, char *shipname, ai_goal *aigp )
993 {
994         Assert ( (type == AIG_TYPE_PLAYER_WING) || (type == AIG_TYPE_PLAYER_SHIP) );
995
996         aigp->time = Missiontime;
997         aigp->type = type;                                                                                      // from player for sure -- could be to ship or to wing
998         aigp->ai_mode = mode;                                                                           // major mode for this goal
999         aigp->ai_submode = submode;                                                             // could mean different things depending on mode
1000
1001         if ( mode == AI_GOAL_WARP )
1002                 aigp->wp_index = submode;
1003
1004         if ( mode == AI_GOAL_CHASE_WEAPON ) {
1005                 aigp->wp_index = submode;                                                               // submode contains the instance of the weapon
1006                 aigp->weapon_signature = Objects[Weapons[submode].objnum].signature;
1007         }
1008
1009         if ( shipname != NULL )
1010                 aigp->ship_name = ai_get_goal_ship_name( shipname, &aigp->ship_name_index );
1011         else
1012                 aigp->ship_name = NULL;
1013
1014         // special case certain orders from player so that ships continue to do the right thing
1015
1016         // make priority for these two support ship orders low so that they will prefer repairing
1017         // a ship over staying near a ship.
1018         if ( (mode == AI_GOAL_STAY_NEAR_SHIP) || (mode == AI_GOAL_KEEP_SAFE_DISTANCE) )
1019                 aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;
1020
1021         else if ( aigp->type == AIG_TYPE_PLAYER_WING )
1022                 aigp->priority = PLAYER_PRIORITY_WING;                  // player wing goals not as high as ship goals
1023         else
1024                 aigp->priority = PLAYER_PRIORITY_SHIP;
1025 }
1026
1027 int ai_goal_find_empty_slot( ai_goal *goals )
1028 {
1029         int gindex, empty_index, oldest_index;
1030
1031         empty_index = -1;
1032         oldest_index = 0;
1033         for ( gindex = 0; gindex < MAX_AI_GOALS; gindex++ ) {
1034                 if ( goals[gindex].time < goals[oldest_index].time )
1035                         oldest_index = gindex;
1036
1037                 if ( (empty_index == -1) && (goals[gindex].ai_mode == AI_GOAL_NONE) )                   // get the index for this goal
1038                         empty_index = gindex;
1039         }
1040
1041         // if we didn't find an empty slot, find the oldest goal and use it's slot
1042         if ( empty_index == -1 )
1043                 empty_index = oldest_index;
1044
1045         Assert ( empty_index < MAX_AI_GOALS );
1046
1047         return empty_index;
1048 }
1049
1050 // adds a goal from a player to the given ship's ai_info structure.  'type' tells us if goal
1051 // is issued to ship or wing (from player),  mode is AI_GOAL_*. submode is the submode the
1052 // ship should go into.  shipname is the object of the action.  aip is the ai_info pointer
1053 // of the ship receiving the order
1054 void ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip )
1055 {
1056         int empty_index;
1057         ai_goal *aigp;
1058
1059         empty_index = ai_goal_find_empty_slot( aip->goals );
1060
1061         // get a pointer to the goal structure
1062         aigp = &aip->goals[empty_index];
1063         ai_add_goal_sub_player( type, mode, submode, shipname, aigp );
1064
1065         // if the goal is to dock, then we must determine which dock points on the two ships to use.
1066         // If the target of the dock is a cargo type container, then we should use DOCK_TYPE_CARGO
1067         // on both ships.  Code is here instead of in ai_add_goal_sub_player() since a dock goal
1068         // should only occur to a specific ship.
1069
1070         if ( (mode == AI_GOAL_REARM_REPAIR) || ((mode == AI_GOAL_DOCK) && (submode == AIS_DOCK_0)) ) {
1071                 ai_goal_fixup_dockpoints( aip, aigp );
1072         }
1073
1074         aigp->signature = Ai_goal_signature++;
1075
1076 }
1077
1078 // adds a goal from the player to the given wing (which in turn will add it to the proper
1079 // ships in the wing
1080 void ai_add_wing_goal_player( int type, int mode, int submode, char *shipname, int wingnum )
1081 {
1082         int i, empty_index;
1083         wing *wingp = &Wings[wingnum];
1084
1085         // add the ai goal for any ship that is currently arrived in the game.
1086         if ( !Fred_running ) {                                                                          // only add goals to ships if fred isn't running
1087                 for (i = 0; i < wingp->current_count; i++) {
1088                         int num = wingp->ship_index[i];
1089                         if ( num == -1 )                        // ship must have been destroyed or departed
1090                                 continue;
1091                         ai_add_ship_goal_player( type, mode, submode, shipname, &Ai_info[Ships[num].ai_index] );
1092                 }
1093         }
1094
1095         // add the sexpression index into the wing's list of goal sexpressions if
1096         // there are more waves to come.  We use the same method here as when adding a goal to
1097         // a ship -- find the first empty entry.  If none exists, take the oldest entry and replace it.
1098         empty_index = ai_goal_find_empty_slot( wingp->ai_goals );
1099         ai_add_goal_sub_player( type, mode, submode, shipname, &wingp->ai_goals[empty_index] );
1100 }
1101
1102
1103 // common routine to add a sexpression mission goal to the appropriate goal structure.
1104 void ai_add_goal_sub_sexp( int sexp, int type, ai_goal *aigp )
1105 {
1106         int node, dummy, op;
1107         char *text;
1108
1109         Assert ( Sexp_nodes[sexp].first != -1 );
1110         node = Sexp_nodes[sexp].first;
1111         text = CTEXT(node);
1112
1113         aigp->signature = Ai_goal_signature++;
1114
1115         aigp->time = Missiontime;
1116         aigp->type = type;
1117         aigp->flags = 0;
1118
1119         op = find_operator( text );
1120
1121         switch (op) {
1122
1123         case OP_AI_WAYPOINTS_ONCE:
1124         case OP_AI_WAYPOINTS: {
1125                 int ref_type;
1126
1127                 ref_type = Sexp_nodes[CDR(node)].subtype;
1128                 if (ref_type == SEXP_ATOM_STRING) {  // referenced by name
1129                         // save the waypoint path name -- the index will get resolved when the goal is checked
1130                         // for acheivability.
1131                         aigp->ship_name = ai_get_goal_ship_name(CTEXT(CDR(node)), &aigp->ship_name_index);  // waypoint path name;
1132                         aigp->wp_index = -1;
1133
1134                 } else
1135                         Int3();
1136
1137                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1138                 aigp->ai_mode = AI_GOAL_WAYPOINTS;
1139                 if ( op == OP_AI_WAYPOINTS_ONCE )
1140                         aigp->ai_mode = AI_GOAL_WAYPOINTS_ONCE;
1141                 break;
1142         }
1143
1144         case OP_AI_DESTROY_SUBSYS:
1145                 aigp->ai_mode = AI_GOAL_DESTROY_SUBSYSTEM;
1146                 aigp->ship_name = ai_get_goal_ship_name( CTEXT(CDR(node)), &aigp->ship_name_index );
1147                 // store the name of the subsystem in the docker_name field for now -- this field must
1148                 // get fixed up when the goal is valid since we need to locate the subsystem on the ship's
1149                 // model.
1150                 aigp->docker.name = ai_get_goal_ship_name(CTEXT(CDR(CDR(node))), &dummy);
1151                 aigp->flags |= AIGF_SUBSYS_NAME_VALID;
1152                 aigp->priority = atoi( CTEXT(CDR(CDR(CDR(node)))) );
1153                 break;
1154
1155         case OP_AI_DISABLE_SHIP:
1156                 aigp->ai_mode = AI_GOAL_DISABLE_SHIP;
1157                 aigp->ship_name = ai_get_goal_ship_name( CTEXT(CDR(node)), &aigp->ship_name_index );
1158                 aigp->ai_submode = -SUBSYSTEM_ENGINE;
1159                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1160                 break;
1161
1162         case OP_AI_DISARM_SHIP:
1163                 aigp->ai_mode = AI_GOAL_DISARM_SHIP;
1164                 aigp->ship_name = ai_get_goal_ship_name( CTEXT(CDR(node)), &aigp->ship_name_index );
1165                 aigp->ai_submode = -SUBSYSTEM_TURRET;
1166                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1167                 break;
1168
1169         case OP_AI_WARP_OUT:
1170                 aigp->ai_mode = AI_GOAL_WARP;
1171                 aigp->priority = atoi( CTEXT(CDR(node)) );
1172                 break;
1173
1174                 // the following goal is obsolete, but here for compatibility
1175         case OP_AI_WARP:
1176                 aigp->ai_mode = AI_GOAL_WARP;
1177                 aigp->ship_name = ai_get_goal_ship_name(CTEXT(CDR(node)), &aigp->ship_name_index);  // waypoint path name;
1178                 //aigp->wp_index = atoi( CTEXT(CDR(node)) );            // this is the index into the warp points
1179                 aigp->wp_index = -1;
1180                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1181                 break;
1182
1183         case OP_AI_UNDOCK:
1184                 aigp->ship_name = NULL;
1185                 aigp->priority = atoi( CTEXT(CDR(node)) );
1186                 aigp->ai_mode = AI_GOAL_UNDOCK;
1187                 aigp->ai_submode = AIS_UNDOCK_0;
1188                 break;
1189
1190         case OP_AI_STAY_STILL:
1191                 aigp->ai_mode = AI_GOAL_STAY_STILL;
1192                 aigp->ship_name = ai_get_goal_ship_name(CTEXT(CDR(node)), &aigp->ship_name_index);  // waypoint path name;
1193                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1194                 break;
1195
1196         case OP_AI_DOCK:
1197                 aigp->ship_name = ai_get_goal_ship_name( CTEXT(CDR(node)), &aigp->ship_name_index );
1198                 aigp->docker.name = ai_add_dock_name(CTEXT(CDR(CDR(node))));
1199                 aigp->dockee.name = ai_add_dock_name(CTEXT(CDR(CDR(CDR(node)))));
1200                 aigp->flags |= ( AIGF_DOCKER_NAME_VALID | AIGF_DOCKEE_NAME_VALID );
1201                 aigp->priority = atoi( CTEXT(CDR(CDR(CDR(CDR(node))))) );
1202
1203                 aigp->ai_mode = AI_GOAL_DOCK;
1204                 aigp->ai_submode = AIS_DOCK_0;          // be sure to set the submode
1205                 break;
1206
1207         case OP_AI_CHASE_ANY:
1208                 aigp->priority = atoi( CTEXT(CDR(node)) );
1209                 aigp->ai_mode = AI_GOAL_CHASE_ANY;
1210                 break;
1211
1212         case OP_AI_PLAY_DEAD:
1213                 aigp->priority = atoi( CTEXT(CDR(node)) );
1214                 aigp->ai_mode = AI_GOAL_PLAY_DEAD;
1215                 break;
1216
1217         case OP_AI_KEEP_SAFE_DISTANCE:
1218                 aigp->priority = atoi( CTEXT(CDR(node)) );
1219                 aigp->ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE;
1220                 break;
1221
1222         case OP_AI_CHASE:
1223         case OP_AI_GUARD:
1224         case OP_AI_GUARD_WING:
1225         case OP_AI_CHASE_WING:
1226         case OP_AI_EVADE_SHIP:
1227         case OP_AI_STAY_NEAR_SHIP:
1228         case OP_AI_IGNORE:
1229                 aigp->ship_name = ai_get_goal_ship_name( CTEXT(CDR(node)), &aigp->ship_name_index );
1230                 aigp->priority = atoi( CTEXT(CDR(CDR(node))) );
1231
1232                 if ( op == OP_AI_CHASE ) {
1233                         aigp->ai_mode = AI_GOAL_CHASE;
1234
1235                         // in the case of ai_chase (and ai_guard) we must do a wing_name_lookup on the name
1236                         // passed here to see if we could be chasing a wing.  Hoffoss and I have consolidated
1237                         // sexpression operators which makes this step necessary
1238                         if ( wing_name_lookup(aigp->ship_name, 1) != -1 )
1239                                 aigp->ai_mode = AI_GOAL_CHASE_WING;
1240
1241                 } else if ( op == OP_AI_GUARD ) {
1242                         aigp->ai_mode = AI_GOAL_GUARD;
1243                         if ( wing_name_lookup(aigp->ship_name, 1) != -1 )
1244                                 aigp->ai_mode = AI_GOAL_GUARD_WING;
1245
1246                 } else if ( op == OP_AI_EVADE_SHIP ) {
1247                         aigp->ai_mode = AI_GOAL_EVADE_SHIP;
1248
1249                 } else if ( op == OP_AI_GUARD_WING ) {
1250                         aigp->ai_mode = AI_GOAL_GUARD_WING;
1251                 } else if ( op == OP_AI_CHASE_WING ) {
1252                         aigp->ai_mode = AI_GOAL_CHASE_WING;
1253                 } else if ( op == OP_AI_STAY_NEAR_SHIP ) {
1254                         aigp->ai_mode = AI_GOAL_STAY_NEAR_SHIP;
1255                 } else if ( op == OP_AI_IGNORE ) {
1256                         aigp->ai_mode = AI_GOAL_IGNORE;
1257                 } else
1258                         Int3();         // this is impossible
1259
1260                 break;
1261
1262         default:
1263                 Int3();                 // get ALLENDER -- invalid ai-goal specified for ai object!!!!
1264         }
1265
1266         if ( aigp->priority >= PLAYER_PRIORITY_MIN ) {
1267                 nprintf (("AI", "bashing sexpression priority of goal %s from %d to %d.\n", text, aigp->priority, PLAYER_PRIORITY_MIN-1));
1268                 aigp->priority = PLAYER_PRIORITY_MIN-1;
1269         }
1270 }
1271
1272 // adds an ai goal for an individual ship
1273 // type determines who has issues this ship a goal (i.e. the player/mission event/etc)
1274 void ai_add_ship_goal_sexp( int sexp, int type, ai_info *aip )
1275 {
1276         int gindex;
1277
1278         gindex = ai_goal_find_empty_slot( aip->goals );
1279         ai_add_goal_sub_sexp( sexp, type, &aip->goals[gindex] );
1280 }
1281
1282 // code to add ai goals to wings.
1283 void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
1284 {
1285         int i;
1286         wing *wingp = &Wings[wingnum];
1287
1288         // add the ai goal for any ship that is currently arrived in the game (only if fred isn't running
1289         if ( !Fred_running ) {
1290                 for (i = 0; i < wingp->current_count; i++) {
1291                         int num = wingp->ship_index[i];
1292                         if ( num == -1 )                        // ship must have been destroyed or departed
1293                                 continue;
1294                         ai_add_ship_goal_sexp( sexp, type, &Ai_info[Ships[num].ai_index] );
1295                 }
1296         }
1297
1298         // add the sexpression index into the wing's list of goal sexpressions if
1299         // there are more waves to come
1300         if ((wingp->num_waves - wingp->current_wave > 0) || Fred_running) {
1301                 int gindex;
1302
1303                 gindex = ai_goal_find_empty_slot( wingp->ai_goals );
1304                 ai_add_goal_sub_sexp( sexp, type, &wingp->ai_goals[gindex] );
1305         }
1306 }
1307
1308 // function for internal code to add a goal to a ship.  Needed when the AI finds itself in a situation
1309 // that it must get out of by issuing itself an order.
1310 //
1311 // objp is the object getting the goal
1312 // goal_type is one of AI_GOAL_*
1313 // other_name is a character string objp might act on (for docking, this is a shipname, for guarding
1314 // this name can be a shipname or a wingname)
1315 // docker_point and dockee_point are used for the AI_GOAL_DOCK command to tell two ships where to dock
1316 // immediate means to process this order right away
1317 void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate )
1318 {
1319         int gindex;
1320         ai_goal *aigp;
1321
1322         // find an empty slot to put this goal in.
1323         gindex = ai_goal_find_empty_slot( aip->goals );
1324
1325         aigp = &(aip->goals[gindex]);
1326
1327         aigp->signature = Ai_goal_signature++;
1328
1329         aigp->time = Missiontime;
1330         aigp->type = AIG_TYPE_DYNAMIC;
1331         aigp->flags = AIGF_GOAL_OVERRIDE;
1332
1333         switch ( goal_type ) {
1334         case AI_GOAL_DOCK:
1335                 aigp->ship_name = name;
1336                 aigp->docker.index = docker_point;
1337                 aigp->dockee.index = dockee_point;
1338                 aigp->priority = 100;
1339
1340                 aigp->ai_mode = AI_GOAL_DOCK;
1341                 aigp->ai_submode = AIS_DOCK_0;          // be sure to set the submode
1342                 break;
1343
1344         case AI_GOAL_UNDOCK:
1345                 aigp->ship_name = NULL;
1346                 aigp->priority = 100;
1347                 aigp->ai_mode = AI_GOAL_UNDOCK;
1348                 aigp->ai_submode = AIS_UNDOCK_0;
1349                 break;
1350
1351         case AI_GOAL_GUARD:
1352                 aigp->ai_mode = AI_GOAL_GUARD;
1353                 if ( wing_name_lookup(name, 1) != -1 )
1354                         aigp->ai_mode = AI_GOAL_GUARD_WING;
1355                 break;
1356
1357         case AI_GOAL_REARM_REPAIR:
1358                 aigp->ai_mode = AI_GOAL_REARM_REPAIR;
1359                 aigp->ai_submode = 0;
1360                 aigp->ship_name = name;
1361                 aigp->priority = PLAYER_PRIORITY_MIN-1;         // make the priority always less than what the player's is
1362                 aigp->flags &= ~AIGF_GOAL_OVERRIDE;                             // don't override this goal.  rearm repair requests should happen in order
1363                 ai_goal_fixup_dockpoints( aip, aigp );
1364                 break;
1365
1366         default:
1367                 Int3();         // unsupported internal goal -- see Mike K or Mark A.
1368                 break;
1369         }
1370
1371
1372         // process the orders immediately so that these goals take effect right away
1373         if ( immediate )
1374                 ai_process_mission_orders( Ships[aip->shipnum].objnum, aip );
1375 }
1376
1377 // function to add an internal goal to a wing.  Mike K says that the goal doesn't need to persist
1378 // across waves of the wing so we merely need to add the goal to each ship in the wing.  Certain
1379 // goal are simply not valid for wings (like dock, undock).  Immediate parameter gets passed to add_ship_goal
1380 // to say whether or not we should process this goal right away
1381 void ai_add_goal_wing_internal( wing *wingp, int goal_type, char *name, int immediate )
1382 {
1383         int i;
1384
1385         // be sure we are not trying to issue dock or undock goals to wings
1386         Assert ( (goal_type != AI_GOAL_DOCK) || (goal_type != AI_GOAL_UNDOCK) );
1387
1388         for (i = 0; i < wingp->current_count; i++) {
1389                 int num = wingp->ship_index[i];
1390                 if ( num == -1 )                        // ship must have been destroyed or departed
1391                         continue;
1392                 ai_add_goal_ship_internal(  &Ai_info[Ships[num].ai_index], goal_type, name, -1, -1, immediate);
1393         }
1394 }
1395
1396 // this function copies goals from a wing to an ai_info * from a ship.
1397 void ai_copy_mission_wing_goal( ai_goal *aigp, ai_info *aip )
1398 {
1399         int j;
1400
1401         for ( j = 0; j < MAX_AI_GOALS; j++ ) {
1402                 if ( aip->goals[j].ai_mode == AI_GOAL_NONE )
1403                         break;
1404         }
1405         Assert ( j < MAX_AI_GOALS );
1406         aip->goals[j] = *aigp;
1407 }
1408
1409
1410 #define SHIP_STATUS_GONE                                1
1411 #define SHIP_STATUS_NOT_ARRIVED         2
1412 #define SHIP_STATUS_ARRIVED                     3
1413 #define SHIP_STATUS_UNKNOWN                     4
1414
1415 // function to determine if an ai goal is achieveable or not.  Will return
1416 // one of the AI_GOAL_* values.  Also determines is a goal was successful.
1417
1418 int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
1419 {
1420         int status;
1421         char *ai_shipname;
1422         int return_val;
1423         object *objp;
1424         ai_info *aip;
1425
1426         //  these orders are always achievable.
1427         if ( (aigp->ai_mode == AI_GOAL_KEEP_SAFE_DISTANCE) || (aigp->ai_mode == AI_GOAL_WARP)
1428                 || (aigp->ai_mode == AI_GOAL_CHASE_ANY) || (aigp->ai_mode == AI_GOAL_STAY_STILL)
1429                 || (aigp->ai_mode == AI_GOAL_PLAY_DEAD) )
1430                 return AI_GOAL_ACHIEVABLE;
1431
1432         // form on my wing is always achievable, but need to set the override bit so that it
1433         // always gets executed next
1434         if ( aigp->ai_mode == AI_GOAL_FORM_ON_WING ) {
1435                 aigp->flags |= AIGF_GOAL_OVERRIDE;
1436                 return AI_GOAL_ACHIEVABLE;
1437         }
1438
1439         // check to see if we have a valid index.  If not, then try to set one up.  If that
1440         // fails, then we must pitch this order
1441         if ( (aigp->ai_mode == AI_GOAL_WAYPOINTS_ONCE) || (aigp->ai_mode == AI_GOAL_WAYPOINTS) ) {
1442                 if ( aigp->wp_index == -1 ) {
1443                         int i;
1444
1445                         for (i = 0; i < Num_waypoint_lists; i++) {
1446                                 if (!stricmp(aigp->ship_name, Waypoint_lists[i].name)) {
1447                                         aigp->wp_index = i;
1448                                         break;
1449                                 }
1450                         }
1451                         if ( i == Num_waypoint_lists ) {
1452                                 Warning(LOCATION, "Unknown waypoint %s.  not found in mission file.  Killing ai goal", aigp->ship_name );
1453                                 return AI_GOAL_NOT_ACHIEVABLE;
1454                         }
1455                 }
1456                 return AI_GOAL_ACHIEVABLE;
1457         }
1458
1459         objp = &Objects[objnum];
1460         Assert( objp->instance != -1 );
1461         ai_shipname = Ships[objp->instance].ship_name;
1462         aip = &Ai_info[Ships[objp->instance].ai_index];
1463
1464         return_val = AI_GOAL_SATISFIED;
1465
1466         // next, determine if the goal has been completed successfully
1467         switch ( aigp->ai_mode ) {
1468
1469         case AI_GOAL_DOCK:
1470         case AI_GOAL_CHASE_WING:
1471         case AI_GOAL_UNDOCK:
1472                 //status = mission_log_get_time( LOG_SHIP_DOCK, ai_shipname, aigp->ship_name, NULL);
1473                 //status = mission_log_get_time( LOG_SHIP_UNDOCK, ai_shipname, aigp->ship_name, NULL );
1474                 //MWA 3/20/97 -- cannot short circuit a dock or undock goal already succeeded -- we must
1475                 // rely on the goal removal code to just remove this goal.  This is because docking/undock
1476                 // can happen > 1 time per mission per pair of ships.  The above checks will find only
1477                 // if the ships docked or undocked at all, which is not what we want.
1478                 status = 0;
1479                 break;
1480         case AI_GOAL_DESTROY_SUBSYSTEM: {
1481                 int shipnum;
1482                 ship_subsys *ssp;
1483
1484                 // shipnum could be -1 depending on if the ship hasn't arrived or died.  only look for subsystem
1485                 // destroyed when shipnum is valid
1486                 shipnum = ship_name_lookup( aigp->ship_name );
1487
1488                 // can't determine the status of this goal if ship not valid or the subsystem
1489                 // name *is* still valid (meaning we haven't found a valid index yet).
1490                 if ( (shipnum == -1) || (aigp->flags & AIGF_SUBSYS_NAME_VALID) ) {
1491                         status = 0;
1492                         break;
1493                 }
1494
1495                 // if the ship is not in the mission or the subsystem name is still being stored, mark the status
1496                 // as 0 so we can continue.  (The subsystem name must be turned into an index into the ship's subsystems
1497                 // for this goal to be valid).
1498                 Assert ( aigp->ai_submode >= 0 );
1499                 ssp = ship_get_indexed_subsys( &Ships[shipnum], aigp->ai_submode );
1500                 status = mission_log_get_time( LOG_SHIP_SUBSYS_DESTROYED, aigp->ship_name, ssp->system_info->name, NULL );
1501
1502                 break;
1503         }
1504         case AI_GOAL_DISABLE_SHIP:
1505                 status = mission_log_get_time( LOG_SHIP_DISABLED, aigp->ship_name, NULL, NULL );
1506                 break;
1507         case AI_GOAL_DISARM_SHIP:
1508                 status = mission_log_get_time( LOG_SHIP_DISARMED, aigp->ship_name, NULL, NULL );
1509                 break;
1510
1511                 // to guard or ignore a ship, the goal cannot continue if the ship being guarded is either destroyed
1512                 // or has departed.
1513         case AI_GOAL_GUARD:
1514         case AI_GOAL_IGNORE:
1515         case AI_GOAL_EVADE_SHIP:
1516         case AI_GOAL_CHASE:
1517         case AI_GOAL_STAY_NEAR_SHIP:
1518         case AI_GOAL_REARM_REPAIR: {
1519                 int shipnum;
1520
1521                 // MWA -- 4/22/98.  Check for the ship actually being in the mission before
1522                 // checking departure and destroyed.  In multiplayer, since ships can respawn,
1523                 // they get log entries for being destroyed even though they have respawned.
1524                 shipnum = ship_name_lookup( aigp->ship_name );
1525                 if ( shipnum == -1 ) {
1526                         status = mission_log_get_time( LOG_SHIP_DEPART, aigp->ship_name, NULL, NULL);
1527                         if ( !status ) {
1528                                 status = mission_log_get_time( LOG_SHIP_DESTROYED, aigp->ship_name, NULL, NULL);
1529                                 if ( status )
1530                                         return_val = AI_GOAL_NOT_ACHIEVABLE;
1531                         }
1532                 } else {
1533                         status = 0;
1534                 }
1535                 break;
1536         }
1537
1538         case AI_GOAL_GUARD_WING:
1539                 status = mission_log_get_time( LOG_WING_DEPART, aigp->ship_name, NULL, NULL );
1540                 if ( !status ) {
1541                         status = mission_log_get_time( LOG_WING_DESTROYED, aigp->ship_name, NULL, NULL);
1542                         if ( status )
1543                                 return_val = AI_GOAL_NOT_ACHIEVABLE;
1544                 }
1545                 break;
1546
1547                 // the following case statement returns control to caller on all paths!!!!
1548         case AI_GOAL_CHASE_WEAPON:
1549                 // for chase weapon, we simply need to look at the weapon instance that we are trying to
1550                 // attack and see if the object still exists, and has the same signature that we expect.
1551                 if ( Weapons[aigp->wp_index].objnum == -1 )
1552                         return AI_GOAL_NOT_ACHIEVABLE;
1553
1554                 // if the signatures don't match, then goal isn't achievable.
1555                 if ( Objects[Weapons[aigp->wp_index].objnum].signature != aigp->weapon_signature )
1556                         return AI_GOAL_NOT_ACHIEVABLE;
1557
1558                 // otherwise, we should be good to go
1559                 return AI_GOAL_ACHIEVABLE;
1560
1561                 break;
1562
1563         default:
1564                 Int3();
1565                 status = 0;
1566                 break;
1567         }
1568
1569         // if status is true, then the mission log event was found and the goal was satisfied.  return
1570         // AI_GOAL_SATISFIED which should allow this ai object to move onto the next order
1571         if ( status )
1572                 return return_val;
1573
1574         // determine the status of the shipname that this object is acting on.  There are a couple of
1575         // special cases to deal with.  Both the chase wing and undock commands will return from within
1576         // the if statement.
1577         if ( (aigp->ai_mode == AI_GOAL_CHASE_WING) || (aigp->ai_mode == AI_GOAL_GUARD_WING) ) {
1578                 int num = wing_name_lookup( aigp->ship_name );
1579                 wing *wingp = &Wings[num];
1580
1581                 if ( wingp->flags & WF_WING_GONE )
1582                         return AI_GOAL_NOT_ACHIEVABLE;
1583                 else if ( wingp->total_arrived_count == 0 )
1584                         return AI_GOAL_NOT_KNOWN;
1585                 else
1586                         return AI_GOAL_ACHIEVABLE;
1587         } else if ( aigp->ai_mode == AI_GOAL_UNDOCK ) {
1588                         return AI_GOAL_ACHIEVABLE;
1589         } else {
1590                 if ( ship_name_lookup( aigp->ship_name ) != -1 )
1591                         status = SHIP_STATUS_ARRIVED;
1592                 else if ( !mission_parse_ship_arrived(aigp->ship_name) )
1593                         status = SHIP_STATUS_NOT_ARRIVED;
1594                 else if ( ship_find_exited_ship_by_name(aigp->ship_name) != -1 )
1595                         status = SHIP_STATUS_GONE;
1596                 else {
1597                         Int3();         // get ALLENDER
1598                         status = SHIP_STATUS_UNKNOWN;
1599                 }
1600         }
1601
1602         // if the goal is an ignore/disable/disarm goal, then 
1603         if ( (status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode & PURGE_GOALS) && !(aigp->flags & AIGF_GOALS_PURGED) ) {
1604                 ai_goal_purge_all_invalid_goals( aigp );
1605                 aigp->flags |= AIGF_GOALS_PURGED;
1606         }
1607                 
1608
1609         // if we are docking, validate the docking indices on both ships.  We might have to change names to indices.
1610         // only enter this calculation if the ship we are docking with has arrived.  If the ship is gone, then
1611         // this goal will get removed.
1612         if ( (aigp->ai_mode == AI_GOAL_DOCK) && (status == SHIP_STATUS_ARRIVED) ) {
1613                 int index, modelnum, shipnum;
1614                 char docker_name[NAME_LENGTH], dockee_name[NAME_LENGTH];
1615
1616                 // debug code to save off the name of the dockpoints (if they exist).
1617                 docker_name[0] = dockee_name[0] = '\0';
1618                 if ( aigp->flags & AIGF_DOCKER_NAME_VALID ) {
1619                         strcpy(docker_name, aigp->docker.name);
1620                         modelnum = Ships[objp->instance].modelnum;
1621                         index = model_find_dock_name_index(modelnum, aigp->docker.name);
1622                         aigp->docker.index = index;
1623                         aigp->flags &= ~AIGF_DOCKER_NAME_VALID;
1624                 }
1625                 if ( aigp->flags & AIGF_DOCKEE_NAME_VALID ) {
1626                         shipnum = ship_name_lookup(aigp->ship_name);
1627                         if ( shipnum != -1 ) {
1628                                 strcpy(dockee_name, aigp->dockee.name);
1629                                 modelnum = Ships[shipnum].modelnum;
1630                                 index = model_find_dock_name_index(modelnum, aigp->dockee.name);
1631                                 aigp->dockee.index = index;
1632                                 aigp->flags &= ~AIGF_DOCKEE_NAME_VALID;
1633                         } else
1634                                 aigp->dockee.index = -1;                // this will force code into if statement below making goal not achievable.
1635                 }
1636                 if ( (aigp->dockee.index == -1) || (aigp->docker.index == -1) ) {
1637                         Int3();                 // for now, allender wants to know about these things!!!!
1638                         return AI_GOAL_NOT_ACHIEVABLE;
1639                 }
1640
1641                 // we must also determine if this ship which is supposed to dock with something is currently
1642                 // docked with something else.  If so, then return the ON_HOLD until it is not docked anymore
1643                 shipnum = ship_name_lookup(aigp->ship_name);
1644                 Assert( shipnum != -1 );
1645
1646                 // if ship is disabled, dont' know if it can dock or not
1647                 if ( Ships[objp->instance].flags & SF_DISABLED )
1648                         return AI_GOAL_NOT_KNOWN;
1649
1650                 // if the ship that I am supposed to dock with is docked with something else, then I need to put my
1651                 // goal on hold
1652                 //      [MK, 4/23/98: With Mark, we believe this fixes the problem of Comet refusing to warp out after docking with Omega.
1653                 //      This bug occurred only when mission goals were validated in the frame in which Comet docked, which happened about
1654                 // once in 10-20 tries.]
1655                 if ( Ai_info[Ships[shipnum].ai_index].ai_flags & AIF_DOCKED )
1656                         if (aip->dock_objnum != Ships[shipnum].objnum)
1657                                 return AI_GOAL_NOT_KNOWN;
1658
1659                 // if this ship is docked and needs to get docked with something else, then undock this
1660                 // ship
1661                 if ( aip->ai_flags & AIF_DOCKED ) {
1662
1663                         // if we are trying to dock with a different ship, then force this ship to undock
1664                         if ( aip->dock_objnum != Ships[shipnum].objnum ) {
1665                                 // if this goal isn't on hold yet, then issue the undock goal and return NOT_KNOWN
1666                                 // which will then place the goal on hold until the undocking is complete.
1667                                 if ( !(aigp->flags & AIGF_GOAL_ON_HOLD) )
1668                                         ai_add_goal_ship_internal( aip, AI_GOAL_UNDOCK, NULL, -1, -1, 0 );
1669
1670                                 return AI_GOAL_NOT_KNOWN;
1671                         } else {
1672                                 // if this ship is already docked with the guy this order tells him to dock with,
1673                                 // then mark the goal as satisfied.
1674                                 // MWA 2/23/98 -- don't return anything.  Since this item is a goal, the ai_dock code
1675                                 // should remove the goal!!!!
1676                                 //return AI_GOAL_SATISFIED;
1677                         }
1678                 }
1679
1680         } else if ( (aigp->ai_mode == AI_GOAL_DESTROY_SUBSYSTEM) && (status == SHIP_STATUS_ARRIVED) ) {
1681                 // if the ship has arrived, and the goal is destroy subsystem, then check to see that we
1682                 // have fixed up the subsystem name (of the subsystem to destroy) into an index into
1683                 // the ship's subsystem list
1684                 if ( aigp->flags & AIGF_SUBSYS_NAME_VALID ) {
1685                         int shipnum;                    
1686
1687                         shipnum = ship_name_lookup( aigp->ship_name );
1688                         if ( shipnum != -1 ) {
1689                                 aigp->ai_submode = ship_get_subsys_index( &Ships[shipnum], aigp->docker.name );
1690                                 aigp->flags &= ~AIGF_SUBSYS_NAME_VALID;
1691                         } else {
1692                                 Int3();
1693                                 return AI_GOAL_NOT_ACHIEVABLE;                  // force this goal to be invalid
1694                         }
1695                 }
1696         } else if ( (aigp->ai_mode == AI_GOAL_IGNORE) && (status == SHIP_STATUS_ARRIVED) ) {
1697                 int shipnum;
1698                 object *ignored;
1699
1700                 // for ignoring a ship, call the ai_ignore object function, then declare the goal satisfied
1701                 shipnum = ship_name_lookup( aigp->ship_name );
1702                 Assert( shipnum != -1 );                // should be true because of above status
1703                 ignored = &Objects[Ships[shipnum].objnum];
1704                 ai_ignore_object(objp, ignored, 100);
1705                 return AI_GOAL_SATISFIED;
1706         }
1707
1708         switch ( aigp->ai_mode ) {
1709
1710         case AI_GOAL_CHASE:
1711         case AI_GOAL_DOCK:
1712         case AI_GOAL_DESTROY_SUBSYSTEM:
1713         case AI_GOAL_UNDOCK:
1714         case AI_GOAL_GUARD:
1715         case AI_GOAL_GUARD_WING:
1716         case AI_GOAL_DISABLE_SHIP:
1717         case AI_GOAL_DISARM_SHIP:
1718         case AI_GOAL_IGNORE:
1719         case AI_GOAL_EVADE_SHIP:
1720         case AI_GOAL_STAY_NEAR_SHIP:
1721                 if ( status == SHIP_STATUS_ARRIVED )
1722                         return AI_GOAL_ACHIEVABLE;
1723                 else if ( status == SHIP_STATUS_NOT_ARRIVED )
1724                         return AI_GOAL_NOT_KNOWN;
1725                 else if ( status == SHIP_STATUS_GONE )
1726                         return AI_GOAL_NOT_ACHIEVABLE;
1727                 else if ( status == SHIP_STATUS_UNKNOWN )
1728                         return AI_GOAL_NOT_KNOWN;
1729                         Int3();         // get allender -- bad logic
1730                 break;
1731
1732         // for rearm repair ships, a goal is only achievable if the support ship isn't repairing anything
1733         // else at the time, or is set to repair the ship for this goal.  All other goals should be placed
1734         // on hold by returning GOAL_NOT_KNOWN.
1735         case AI_GOAL_REARM_REPAIR: {
1736                 int shipnum;
1737
1738                 // short circuit a couple of cases.  Ship not arrived shouldn't happen.  Ship gone means
1739                 // we mark the goal as not achievable.
1740                 if ( status == SHIP_STATUS_NOT_ARRIVED ) {
1741                         Int3();                                                                         // get Allender.  this shouldn't happen!!!
1742                         return AI_GOAL_NOT_ACHIEVABLE;
1743                 }
1744
1745                 if ( status == SHIP_STATUS_GONE )
1746                         return AI_GOAL_NOT_ACHIEVABLE;
1747
1748                 Assert( aigp->ship_name );
1749                 shipnum = ship_name_lookup( aigp->ship_name );
1750
1751                 // if desitnation currently being repaired, then goal is stil active
1752                 if ( Ai_info[Ships[shipnum].ai_index].ai_flags & AIF_BEING_REPAIRED )
1753                         return AI_GOAL_ACHIEVABLE;
1754
1755                 // if the destination ship is dying or departing (but not completed yet), the mark goal as
1756                 // not achievable.
1757                 if ( Ships[shipnum].flags & (SF_DYING | SF_DEPARTING) )
1758                         return AI_GOAL_NOT_ACHIEVABLE;
1759
1760                 // if the destination object is no longer awaiting repair, then remove the item
1761                 if ( !(Ai_info[Ships[shipnum].ai_index].ai_flags & AIF_AWAITING_REPAIR) )
1762                         return AI_GOAL_NOT_ACHIEVABLE;
1763
1764                 // not repairing anything means that he can do this goal!!!
1765                 if ( !(aip->ai_flags  & AIF_REPAIRING) )
1766                         return AI_GOAL_ACHIEVABLE;
1767
1768                 // test code!!!
1769                 if ( aip->goal_objnum == -1 ) {
1770                         // -- MK, 11/9/97 -- I was always hitting this: Int3();
1771                         return AI_GOAL_ACHIEVABLE;
1772                 }
1773
1774                 // if he is repairing something, he can satisfy his repair goal (his goal_objnum)
1775                 // return GOAL_NOT_KNOWN which is kind of a hack which puts the goal on hold until it can be
1776                 // satisfied.  
1777                 if ( aip->goal_objnum != Ships[shipnum].objnum )
1778                         return AI_GOAL_NOT_KNOWN;
1779
1780                 return AI_GOAL_ACHIEVABLE;
1781         }
1782
1783         default:
1784                 Int3();                 // invalid case in switch:
1785         }
1786
1787         return AI_GOAL_NOT_KNOWN;
1788 }
1789
1790 //      Compare function for system qsort() for sorting ai_goals based on priority.
1791 //      Return values set to sort array in _decreasing_ order.
1792 int ai_goal_priority_compare(const void *a, const void *b)
1793 {
1794         ai_goal *ga, *gb;
1795
1796         ga = (ai_goal *) a;
1797         gb = (ai_goal *) b;
1798
1799         // first, sort based on whether or not the ON_HOLD flag is set for the goal.
1800         // If the flag is set, don't push the goal higher in the list even if priority
1801         // is higher since goal cannot currently be achieved.
1802
1803         if ( (ga->flags & AIGF_GOAL_ON_HOLD) && !(gb->flags & AIGF_GOAL_ON_HOLD) )
1804                 return 1;
1805         else if ( !(ga->flags & AIGF_GOAL_ON_HOLD) && (gb->flags & AIGF_GOAL_ON_HOLD) )
1806                 return -1;
1807
1808         // check whether or not the goal override flag is set.  If it is set, then push this goal higher
1809         // in the list
1810
1811         else if ( (ga->flags & AIGF_GOAL_OVERRIDE) && !(gb->flags & AIGF_GOAL_OVERRIDE) )
1812                 return -1;
1813         else if ( !(ga->flags & AIGF_GOAL_OVERRIDE) && (gb->flags & AIGF_GOAL_OVERRIDE) )
1814                 return 1;
1815
1816         // now normal priority processing
1817
1818         if (ga->priority > gb->priority)
1819                 return -1;
1820         else if ( ga->priority < gb->priority )
1821                 return 1;
1822         else {
1823                 if ( ga->time > gb->time )
1824                         return -1;
1825                 else // if ( ga->time < gb->time )                      // this way prevents element swapping if times happen to be equal (which they should not)
1826                         return 1;
1827         }
1828 }
1829
1830 //      Prioritize goal list.
1831 //      First sort on priority.
1832 //      Then sort on time for goals of equivalent priority.
1833 //      objnum  The object number to act upon.  Redundant with *aip.
1834 //      *aip            The AI info to act upon.  Goals are stored at aip->goals
1835 void prioritize_goals(int objnum, ai_info *aip)
1836 {
1837
1838         //      First sort based on priority field.
1839         qsort(aip->goals, MAX_AI_GOALS, sizeof(ai_goal), ai_goal_priority_compare);
1840
1841 }
1842
1843 //      Scan the list of goals at aip->goals.
1844 //      Remove obsolete goals.
1845 //      objnum  Object of interest.  Redundant with *aip.
1846 //      *aip            contains goals at aip->goals.
1847 void validate_mission_goals(int objnum, ai_info *aip)
1848 {
1849         int     i;
1850         
1851         // loop through all of the goals to determine which goal should be followed.
1852         // This determination will be based on priority, and the time at which it was issued.
1853         for ( i = 0; i < MAX_AI_GOALS; i++ ) {
1854                 int             state;
1855                 ai_goal *aigp;
1856
1857                 aigp = &aip->goals[i];
1858
1859                 // quick check to see if this goal is valid or not, or if we are trying to process the
1860                 // current goal
1861                 if (aigp->ai_mode == AI_GOAL_NONE)
1862                         continue;
1863
1864                 // purge any goals which should get purged
1865                 if ( aigp->flags & AIGF_PURGE ) {
1866                         ai_remove_ship_goal( aip, i );
1867                         continue;
1868                 }
1869
1870                 state = ai_mission_goal_achievable( objnum, aigp );
1871
1872                 // if this order is no longer a valid one, remove it
1873                 if ( (state == AI_GOAL_NOT_ACHIEVABLE) || (state == AI_GOAL_SATISFIED) ) {
1874                         ai_remove_ship_goal( aip, i );
1875                         continue;
1876                 }
1877
1878                 // if the status is achievable, and the on_hold flag is set, clear the flagb
1879                 if ( (state == AI_GOAL_ACHIEVABLE) && (aigp->flags & AIGF_GOAL_ON_HOLD) )
1880                         aigp->flags &= ~AIGF_GOAL_ON_HOLD;
1881
1882                 // if the goal is not known, then set the ON_HOLD flag so that it doesn't get counted as
1883                 // a goal to be pursued
1884                 if ( state == AI_GOAL_NOT_KNOWN )
1885                         aigp->flags |= AIGF_GOAL_ON_HOLD;               // put this goal on hold until it becomes true
1886         }
1887
1888         // if we had an active goal, and that goal is now in hold, make the mode AIM_NONE.  If a new valid
1889         // goal is produced after prioritizing, then the mode will get reset immediately.  Otherwise, setting
1890         // the mode to none will force ship to do default behavior.
1891         if ( (aip->goals[0].ai_mode != AI_GOAL_NONE) && (aip->goals[0].flags & AIGF_GOAL_ON_HOLD) )
1892                 aip->mode = AIM_NONE;
1893
1894         // if the active goal is a rearm/repair goal, the put all other valid goals (which are not repair goals)
1895         // on hold
1896         if ( (aip->goals[0].ai_mode == AI_GOAL_REARM_REPAIR) && (aip->ai_flags & AIF_DOCKED) ) {
1897                 for ( i = 1; i < MAX_AI_GOALS; i++ ) {
1898                         if ( (aip->goals[i].ai_mode == AI_GOAL_NONE) || (aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR) )
1899                                 continue;
1900                         aip->goals[i].flags |= AIGF_GOAL_ON_HOLD;
1901                 }
1902         }
1903 }
1904
1905 //XSTR:OFF
1906 static char *Goal_text[5] = {
1907 "EVENT_SHIP",
1908 "EVENT_WING",
1909 "PLAYER_SHIP",
1910 "PLAYER_WING",
1911 "DYNAMIC",
1912 };
1913 //XSTR:ON
1914
1915 extern char *Mode_text[MAX_AI_BEHAVIORS];
1916
1917 // code to process ai "orders".  Orders include those determined from the mission file and those
1918 // given by the player to a ship that is under his control.  This function gets called for every
1919 // AI object every N seconds through the ai loop.
1920 void ai_process_mission_orders( int objnum, ai_info *aip )
1921 {
1922         object  *objp = &Objects[objnum];
1923         object  *other_obj;
1924         ai_goal *current_goal;
1925         int             wingnum, shipnum;
1926         int             original_signature;
1927
1928 /*      if (!stricmp(Ships[objp->instance].ship_name, "gtt comet")) {
1929                 for (int i=0; i<MAX_AI_GOALS; i++) {
1930                         if (aip->goals[i].signature != -1) {
1931                                 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));
1932                         }
1933                 }
1934                 nprintf(("AI", "\n"));
1935         }
1936 */
1937
1938         // AL 12-12-97: If a ship is entering/leaving a docking bay, wait until path
1939         //                                       following is finished before pursuing goals.
1940         if ( aip->mode == AIM_BAY_EMERGE || aip->mode == AIM_BAY_DEPART ) {
1941                 return;
1942         }
1943
1944         //      Goal #0 is always the active goal, as we maintain a sorted list.
1945         //      Get the signature to see if sorting it again changes it.
1946         original_signature = aip->goals[0].signature;
1947
1948         validate_mission_goals(objnum, aip);
1949
1950         //      Sort the goal array by priority and other factors.
1951         prioritize_goals(objnum, aip);
1952
1953         //      Make sure there's a goal to pursue, else return.
1954         if (aip->goals[0].signature == -1) {
1955                 if (aip->mode == AIM_NONE)
1956                         ai_do_default_behavior(objp);
1957                 return;
1958         }
1959
1960         //      If goal didn't change, return.
1961         if ((aip->active_goal != -1) && (aip->goals[0].signature == original_signature))
1962                 return;
1963
1964         // if the first goal in the list has the ON_HOLD flag, set, there is no current valid goal
1965         // to pursue.
1966         if ( aip->goals[0].flags & AIGF_GOAL_ON_HOLD )
1967                 return;
1968
1969         //      Kind of a hack for now.  active_goal means the goal currently being pursued.
1970         //      It will always be #0 since the list is prioritized.
1971         aip->active_goal = 0;
1972
1973         //nprintf(("AI", "New goal for %s = %i\n", Ships[objp->instance].ship_name, aip->goals[0].ai_mode));
1974
1975         current_goal = &aip->goals[0];
1976
1977         if ( MULTIPLAYER_MASTER ){
1978                 send_ai_info_update_packet( objp, AI_UPDATE_ORDERS );
1979         }
1980
1981         // if this object was flying in formation off of another object, remove the flag that tells him
1982         // to do this.  The form-on-my-wing command is removed from the goal list as soon as it is called, so
1983         // we are safe removing this bit here.
1984         aip->ai_flags &= ~AIF_FORMATION_OBJECT;
1985
1986         // AL 3-7-98: If this is a player ship, and the goal is not a formation goal, then do a quick out
1987         if ( (objp->flags & OF_PLAYER_SHIP) && (current_goal->ai_mode != AI_GOAL_FORM_ON_WING) ) {
1988                 return;
1989         }       
1990
1991         switch ( current_goal->ai_mode ) {
1992
1993         case AI_GOAL_CHASE:
1994                 if ( current_goal->ship_name ) {
1995                         shipnum = ship_name_lookup( current_goal->ship_name );
1996                         Assert (shipnum != -1 );                        // shouldn't get here if this is false!!!!
1997                         other_obj = &Objects[Ships[shipnum].objnum];
1998                 } else
1999                         other_obj = NULL;                                               // we get this case when we tell ship to engage enemy!
2000
2001                 //      Mike -- debug code!
2002                 //      If a ship has a subobject on it, attack that instead of the main ship!
2003                 ai_attack_object( objp, other_obj, current_goal->priority, NULL);
2004                 break;
2005
2006         case AI_GOAL_CHASE_WEAPON:
2007                 Assert( Weapons[current_goal->wp_index].objnum != -1 );
2008                 other_obj = &Objects[Weapons[current_goal->wp_index].objnum];
2009                 ai_attack_object( objp, other_obj, current_goal->priority, NULL );
2010                 break;
2011
2012         case AI_GOAL_GUARD:
2013                 shipnum = ship_name_lookup( current_goal->ship_name );
2014                 Assert (shipnum != -1 );                        // shouldn't get here if this is false!!!!
2015                 other_obj = &Objects[Ships[shipnum].objnum];
2016                 // shipnum and other_obj are the shipnumber and object pointer of the object that you should
2017                 // guard.
2018                 if (objp != other_obj) {
2019                         ai_set_guard_object(objp, other_obj);
2020                         aip->submode_start_time = Missiontime;
2021                 } else {
2022                         mprintf(("Warning: Ship %s told to guard itself.  Goal ignored.\n", Ships[objp->instance].ship_name));
2023                 }
2024                 // -- What the hell is this doing here?? -- MK, 7/30/97 -- ai_do_default_behavior( objp );
2025                 break;
2026
2027         case AI_GOAL_GUARD_WING:
2028                 wingnum = wing_name_lookup( current_goal->ship_name );
2029                 Assert (wingnum != -1 );                        // shouldn't get here if this is false!!!!
2030                 ai_set_guard_wing(objp, wingnum);
2031                 aip->submode_start_time = Missiontime;
2032                 break;
2033
2034         case AI_GOAL_WAYPOINTS:                         // do nothing for waypoints
2035         case AI_GOAL_WAYPOINTS_ONCE: {
2036                 int flags = 0;
2037
2038                 if ( current_goal->ai_mode == AI_GOAL_WAYPOINTS)
2039                         flags |= WPF_REPEAT;
2040                 ai_start_waypoints(objp, current_goal->wp_index, flags);
2041                 break;
2042         }
2043
2044         case AI_GOAL_DOCK: {
2045                 shipnum = ship_name_lookup( current_goal->ship_name );
2046                 Assert (shipnum != -1 );                        // shouldn't get here if this is false!!!!
2047                 other_obj = &Objects[Ships[shipnum].objnum];
2048
2049                 // be sure that we have indices for docking points here!  If we ever had names, they should
2050                 // get fixed up in goal_achievable so that the points can be checked there for validity
2051                 Assert ( !(current_goal->flags & AIGF_DOCKER_NAME_VALID) );
2052                 Assert ( !(current_goal->flags & AIGF_DOCKEE_NAME_VALID) );
2053                 ai_dock_with_object( objp, other_obj, current_goal->priority, AIDO_DOCK, current_goal->docker.index, current_goal->dockee.index );
2054                 aip->submode_start_time = Missiontime;
2055                 break;
2056         }
2057
2058         case AI_GOAL_UNDOCK:
2059                 // try to find the object which which this object is docked with.  Use that object as the
2060                 // "other object" for the undocking proceedure.  If "other object" isn't found, then the undock
2061                 // goal cannot continue.  Spit out a warning and remove the goal.
2062                 other_obj = ai_find_docked_object( objp );
2063                 if ( other_obj == NULL ) {
2064                         //Int3();
2065                         // assume that the guy he was docked with doesn't exist anymore.  (i.e. a cargo containuer
2066                         // can get destroyed while docked with a freighter.)  We should just remove this goal and
2067                         // let this ship pick up it's next goal.
2068                         ai_mission_goal_complete( aip );                // mark as complete, so we can remove it and move on!!!
2069                         break;
2070                 }
2071                 ai_dock_with_object( objp, other_obj, current_goal->priority, AIDO_UNDOCK, 0, 0 );
2072                 aip->submode_start_time = Missiontime;
2073                 break;
2074
2075
2076                 // when destroying a subsystem, we can destroy a specific instance of a subsystem
2077                 // or all instances of a type of subsystem (i.e. a specific engine or all engines).
2078                 // the ai_submode value is > 0 for a specific instance of subsystem and < 0 for all
2079                 // instances of a specific type
2080         case AI_GOAL_DESTROY_SUBSYSTEM:
2081         case AI_GOAL_DISABLE_SHIP:
2082         case AI_GOAL_DISARM_SHIP: {
2083                 shipnum = ship_name_lookup( current_goal->ship_name );
2084                 other_obj = &Objects[Ships[shipnum].objnum];
2085                 ai_attack_object( objp, other_obj, current_goal->priority, NULL);
2086                 ai_set_attack_subsystem( objp, current_goal->ai_submode );              // submode stored the subsystem type
2087                 if (current_goal->ai_mode != AI_GOAL_DESTROY_SUBSYSTEM) {
2088                         if (aip->target_objnum != -1) {
2089                                 //      Only protect if _not_ a capital ship.  We don't want the Lucifer accidentally getting protected.
2090                                 if (!(Ship_info[Ships[shipnum].ship_info_index].flags & SIF_HUGE_SHIP))
2091                                         Objects[aip->target_objnum].flags |= OF_PROTECTED;
2092                         }
2093                 } else  //      Just in case this ship had been protected, unprotect it.
2094                         if (aip->target_objnum != -1)
2095                                 Objects[aip->target_objnum].flags &= ~OF_PROTECTED;
2096
2097                 break;
2098                                                                           }
2099
2100         case AI_GOAL_CHASE_WING:
2101                 wingnum = wing_name_lookup( current_goal->ship_name );
2102                 ai_attack_wing(objp, wingnum, current_goal->priority);
2103                 break;
2104
2105         case AI_GOAL_CHASE_ANY:
2106                 ai_attack_object( objp, NULL, current_goal->priority, NULL );
2107                 break;
2108
2109         case AI_GOAL_WARP: {
2110                 int index;
2111
2112                 index = current_goal->wp_index;
2113                 ai_set_mode_warp_out( objp, aip );
2114                 break;
2115         }
2116
2117         case AI_GOAL_EVADE_SHIP:
2118                 shipnum = ship_name_lookup( current_goal->ship_name );
2119                 other_obj = &Objects[Ships[shipnum].objnum];
2120                 ai_evade_object( objp, other_obj, current_goal->priority );
2121                 break;
2122
2123         case AI_GOAL_STAY_STILL:
2124                 // for now, ignore any other parameters!!!!
2125                 // clear out the object's goals.  Seems to me that if a ship is staying still for a purpose
2126                 // then we need to clear everything out since there is not a real way to get rid of this goal
2127                 // clearing out goals is okay here since we are now what mode to set this AI object to.
2128                 ai_clear_ship_goals( aip );
2129                 ai_stay_still( objp, NULL );
2130                 break;
2131
2132         case AI_GOAL_PLAY_DEAD:
2133                 // if a ship is playing dead, MWA says that it shouldn't try to do anything else.
2134                 // clearing out goals is okay here since we are now what mode to set this AI object to.
2135                 ai_clear_ship_goals( aip );
2136                 aip->mode = AIM_PLAY_DEAD;
2137                 aip->submode = -1;
2138                 break;
2139
2140         case AI_GOAL_FORM_ON_WING:
2141                 // for form on wing, we need to clear out all goals for this ship, and then call the form
2142                 // on wing AI code
2143                 // clearing out goals is okay here since we are now what mode to set this AI object to.
2144                 ai_clear_ship_goals( aip );
2145                 shipnum = ship_name_lookup( current_goal->ship_name );
2146                 other_obj = &Objects[Ships[shipnum].objnum];
2147                 ai_form_on_wing( objp, other_obj );
2148                 break;
2149
2150 // labels for support ship commands
2151
2152         case AI_GOAL_STAY_NEAR_SHIP: {
2153                 shipnum = ship_name_lookup( current_goal->ship_name );
2154                 other_obj = &Objects[Ships[shipnum].objnum];
2155                 // todo MK:  hook to keep support ship near other_obj -- other_obj could be the player object!!!
2156                 float   dist = 300.0f;          //      How far away to stay from ship.  Should be set in SEXP?
2157                 ai_do_stay_near(objp, other_obj, dist);
2158                 break;
2159                                                                                   }
2160
2161         case AI_GOAL_KEEP_SAFE_DISTANCE:
2162                 // todo MK: hook to keep support ship at a safe distance
2163                 break;
2164
2165         case AI_GOAL_REARM_REPAIR:
2166                 shipnum = ship_name_lookup( current_goal->ship_name );
2167                 other_obj = &Objects[Ships[shipnum].objnum];
2168                 ai_rearm_repair( objp, other_obj, current_goal->priority, current_goal->docker.index, current_goal->dockee.index );
2169                 break;
2170
2171         default:
2172                 Int3();
2173                 break;
2174         }
2175
2176 }
2177
2178 void ai_update_goal_references(ai_goal *goals, int type, char *old_name, char *new_name)
2179 {
2180         int i, mode, flag, dummy;
2181
2182         for (i=0; i<MAX_AI_GOALS; i++)  // loop through all the goals in the Ai_info entry
2183         {
2184                 mode = goals[i].ai_mode;
2185                 flag = 0;
2186                 switch (type)
2187                 {
2188                         case REF_TYPE_SHIP:
2189                         case REF_TYPE_PLAYER:
2190                                 switch (mode)
2191                                 {
2192                                         case AI_GOAL_CHASE:
2193                                         case AI_GOAL_DOCK:
2194                                         case AI_GOAL_DESTROY_SUBSYSTEM:
2195                                         case AI_GOAL_GUARD:
2196                                         case AI_GOAL_DISABLE_SHIP:
2197                                         case AI_GOAL_DISARM_SHIP:
2198                                         case AI_GOAL_IGNORE:
2199                                         case AI_GOAL_EVADE_SHIP:
2200                                         case AI_GOAL_STAY_NEAR_SHIP:
2201                                                 flag = 1;
2202                                 }
2203                                 break;
2204
2205                         case REF_TYPE_WING:
2206                                 switch (mode)
2207                                 {
2208                                         case AI_GOAL_CHASE_WING:
2209                                         case AI_GOAL_GUARD_WING:
2210                                                 flag = 1;
2211                                 }
2212                                 break;
2213
2214                         case REF_TYPE_WAYPOINT:
2215                                 switch (mode)
2216                                 {
2217                                         case AI_GOAL_WAYPOINTS:
2218                                         case AI_GOAL_WAYPOINTS_ONCE:
2219                                                 flag = 1;
2220                                 }
2221                                 break;
2222
2223                         case REF_TYPE_PATH:
2224                                 switch (mode)
2225                                 {
2226                                         case AI_GOAL_WAYPOINTS:
2227                                         case AI_GOAL_WAYPOINTS_ONCE:
2228                                         
2229                                                 flag = 1;
2230                                 }
2231                                 break;
2232                 }
2233
2234                 if (flag)  // is this a valid goal to parse for this conversion?
2235                         if (!stricmp(goals[i].ship_name, old_name)) {
2236                                 if (*new_name == '<')  // target was just deleted..
2237                                         goals[i].ai_mode = AI_GOAL_NONE;
2238                                 else
2239                                         goals[i].ship_name = ai_get_goal_ship_name(new_name, &dummy);
2240                         }
2241         }
2242 }
2243
2244 int query_referenced_in_ai_goals(ai_goal *goals, int type, char *name)
2245 {
2246         int i, mode, flag;
2247
2248         for (i=0; i<MAX_AI_GOALS; i++)  // loop through all the goals in the Ai_info entry
2249         {
2250                 mode = goals[i].ai_mode;
2251                 flag = 0;
2252                 switch (type)
2253                 {
2254                         case REF_TYPE_SHIP:
2255                                 switch (mode)
2256                                 {
2257                                         case AI_GOAL_CHASE:
2258                                         case AI_GOAL_DOCK:
2259                                         case AI_GOAL_DESTROY_SUBSYSTEM:
2260                                         case AI_GOAL_GUARD:
2261                                         case AI_GOAL_DISABLE_SHIP:
2262                                         case AI_GOAL_DISARM_SHIP:
2263                                         case AI_GOAL_IGNORE:
2264                                         case AI_GOAL_EVADE_SHIP:
2265                                         case AI_GOAL_STAY_NEAR_SHIP:
2266                                                 flag = 1;
2267                                 }
2268                                 break;
2269
2270                         case REF_TYPE_WING:
2271                                 switch (mode)
2272                                 {
2273                                         case AI_GOAL_CHASE_WING:
2274                                         case AI_GOAL_GUARD_WING:
2275                                                 flag = 1;
2276                                 }
2277                                 break;
2278
2279                         case REF_TYPE_WAYPOINT:
2280                                 switch (mode)
2281                                 {
2282                                         case AI_GOAL_WAYPOINTS:
2283                                         case AI_GOAL_WAYPOINTS_ONCE:
2284                                                 flag = 1;
2285                                 }
2286                                 break;
2287
2288                         case REF_TYPE_PATH:
2289                                 switch (mode)
2290                                 {
2291                                         case AI_GOAL_WAYPOINTS:
2292                                         case AI_GOAL_WAYPOINTS_ONCE:
2293                                                 flag = 1;
2294                                 }
2295                                 break;
2296                 }
2297
2298                 if (flag)  // is this a valid goal to parse for this conversion?
2299                 {
2300                         if (!stricmp(goals[i].ship_name, name))
2301                                 return 1;
2302                 }
2303         }
2304
2305         return 0;
2306 }
2307
2308 char *ai_add_dock_name(char *str)
2309 {
2310         char *ptr;
2311         int i;
2312
2313         Assert(strlen(str) < NAME_LENGTH - 1);
2314         for (i=0; i<Num_ai_dock_names; i++)
2315                 if (!stricmp(Ai_dock_names[i], str))
2316                         return Ai_dock_names[i];
2317
2318         Assert(Num_ai_dock_names < MAX_AI_DOCK_NAMES);
2319         ptr = Ai_dock_names[Num_ai_dock_names++];
2320         strcpy(ptr, str);
2321         return ptr;
2322 }