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