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