]> icculus.org git repositories - taylor/freespace2.git/blob - src/ship/ship.cpp
safer strings using SDL string functions
[taylor/freespace2.git] / src / ship / ship.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/Ship.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Ship (and other object) handling functions
16  *
17  * $Log$
18  * Revision 1.10  2006/04/26 19:47:57  taylor
19  * FS1 keeps single-database and multi-database techroom entries separate so do it here too
20  *
21  * Revision 1.9  2004/09/20 01:31:44  theoddone33
22  * GCC 3.4 fixes.
23  *
24  * Revision 1.8  2004/07/04 11:39:06  taylor
25  * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
26  *
27  * Revision 1.7  2003/06/11 18:30:33  taylor
28  * plug memory leaks
29  *
30  * Revision 1.6  2003/05/25 02:30:44  taylor
31  * Freespace 1 support
32  *
33  * Revision 1.5  2002/06/17 06:33:11  relnev
34  * ryan's struct patch for gcc 2.95
35  *
36  * Revision 1.4  2002/06/09 04:41:26  relnev
37  * added copyright header
38  *
39  * Revision 1.3  2002/06/02 00:31:36  relnev
40  * implemented osregistry
41  *
42  * Revision 1.2  2002/05/03 13:34:34  theoddone33
43  * More stuff compiles
44  *
45  * Revision 1.1.1.1  2002/05/03 03:28:10  root
46  * Initial import.
47  *
48  * 
49  * 144   10/13/99 3:43p Jefff
50  * fixed unnumbered XSTRs
51  * 
52  * 143   9/14/99 3:26a Dave
53  * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
54  * respawn-too-early problem. Made a few crash points safe.
55  * 
56  * 142   9/11/99 4:02p Dave
57  * Don't page in model textures when doing ship_model_change() in fred.
58  * 
59  * 141   9/10/99 9:44p Dave
60  * Bumped version # up. Make server reliable connects not have such a huge
61  * timeout. 
62  * 
63  * 140   9/06/99 3:30p Mikek
64  * Added system to restrict weapon choices for dogfight missions.
65  * 
66  * 139   9/01/99 10:15a Dave
67  * 
68  * 138   9/01/99 8:43a Andsager
69  * supress WARNING from no_fred ships flag
70  * 
71  * 137   8/26/99 8:52p Dave
72  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
73  * 
74  * 136   8/26/99 6:08p Andsager
75  * Add debug code for lethality and number of turrets targeting player.
76  * 
77  * 135   8/26/99 5:14p Andsager
78  * 
79  * 134   8/26/99 9:45a Dave
80  * First pass at easter eggs and cheats.
81  * 
82  * 133   8/24/99 4:25p Andsager
83  * Add ship-vanish sexp
84  * 
85  * 132   8/23/99 11:59a Andsager
86  * Force choice of big fireball when Knossos destroyed.  Allow logging of
87  * ship destroyed when no killer_name (ie, from debug).
88  * 
89  * 131   8/23/99 11:09a Andsager
90  * Round 2 of Knossos explosion
91  * 
92  * 130   8/20/99 5:09p Andsager
93  * Second pass on Knossos device explosion
94  * 
95  * 129   8/18/99 10:59p Andsager
96  * Enable "b" key to target bombers.
97  * 
98  * 128   8/18/99 12:09p Andsager
99  * Add debug if message has no anim for message.  Make messages come from
100  * wing leader.
101  * 
102  * 127   8/16/99 10:04p Andsager
103  * Add special-warp-dist and special-warpout-name sexp for Knossos device
104  * warpout.
105  * 
106  * 126   8/16/99 4:06p Dave
107  * Big honking checkin.
108  * 
109  * 125   8/16/99 2:01p Andsager
110  * Knossos warp-in warp-out.
111  * 
112  * 124   8/13/99 10:49a Andsager
113  * Knossos and HUGE ship warp out.  HUGE ship warp in.  Stealth search
114  * modes dont collide big ships.
115  * 
116  * 123   8/05/99 6:19p Dave
117  * New demo checksums.
118  * 
119  * 122   8/05/99 12:57a Andsager
120  * the insanity of it all!
121  * 
122  * 121   8/03/99 11:13a Andsager
123  * Bump up number of ship_subsystems for demo
124  * 
125  * 120   8/02/99 10:39p Dave
126  * Added colored shields. OoOoOoooOoo
127  * 
128  * 119   7/29/99 10:47p Dave
129  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
130  * 
131  * 118   7/29/99 12:05a Dave
132  * Nebula speed optimizations.
133  * 
134  * 117   7/28/99 1:36p Andsager
135  * Modify cargo1 to include flag CARGO_NO_DEPLETE.  Add sexp
136  * cargo-no-deplete (only for BIG / HUGE).  Modify ship struct to pack
137  * better.
138  * 
139  * 116   7/26/99 5:50p Dave
140  * Revised ingame join. Better? We'll see....
141  * 
142  * 115   7/26/99 8:06a Andsager
143  * Consistent personas
144  * 
145  * 114   7/24/99 5:22p Jefff
146  * Removed debug rendering of interpolated ships in multiplayer.
147  * 
148  * 113   7/19/99 8:57p Andsager
149  * Added Ship_exited red_alert_carry flag and hull strength for RED ALERT
150  * carry over of Exited_ships
151  * 
152  * 112   7/19/99 7:20p Dave
153  * Beam tooling. Specialized player-killed-self messages. Fixed d3d nebula
154  * pre-rendering.
155  * 
156  * 111   7/19/99 12:02p Andsager
157  * Allow AWACS on any ship subsystem. Fix sexp_set_subsystem_strength to
158  * only blow up subsystem if its strength is > 0
159  * 
160  * 110   7/18/99 9:56p Andsager
161  * Make max_ship_subsys 300 again!
162  * 
163  * 109   7/18/99 5:20p Dave
164  * Jump node icon. Fixed debris fogging. Framerate warning stuff.
165  * 
166  * 108   7/18/99 12:32p Dave
167  * Randomly oriented shockwaves.
168  * 
169  * 107   7/15/99 6:36p Jamesa
170  * Moved default ship name into the ships.tbl
171  * 
172  * 104   7/15/99 9:20a Andsager
173  * FS2_DEMO initial checkin
174  * 
175  * 103   7/13/99 5:03p Alanl
176  * make sure object sounds get assigned to ships
177  * 
178  * 102   7/09/99 5:54p Dave
179  * Seperated cruiser types into individual types. Added tons of new
180  * briefing icons. Campaign screen.
181  * 
182  * 101   7/08/99 5:49p Andsager
183  * Fixed bug colliding with just warped in Cap ship
184  * 
185  * 100   7/08/99 10:53a Dave
186  * New multiplayer interpolation scheme. Not 100% done yet, but still
187  * better than the old way.
188  * 
189  * 99    7/06/99 4:24p Dave
190  * Mid-level checkin. Starting on some potentially cool multiplayer
191  * smoothness crap.
192  * 
193  * 98    7/06/99 10:45a Andsager
194  * Modify engine wash to work on any ship that is not small.  Add AWACS
195  * ask for help.
196  * 
197  * 97    7/01/99 4:23p Dave
198  * Full support for multiple linked ambient engine sounds. Added "big
199  * damage" flag.
200  * 
201  * 96    7/01/99 11:44a Dave
202  * Updated object sound system to allow multiple obj sounds per ship.
203  * Added hit-by-beam sound. Added killed by beam sound.
204  * 
205  * 95    6/30/99 5:53p Dave
206  * Put in new anti-camper code.
207  * 
208  * 94    6/20/99 12:06a Alanl
209  * new event music changes
210  * 
211  * 93    6/16/99 4:06p Dave
212  * New pilot info popup. Added new draw-bitmap-as-poly function.
213  * 
214  * 92    6/16/99 10:21a Dave
215  * Added send-message-list sexpression.
216  * 
217  * 91    6/14/99 3:21p Andsager
218  * Allow collisions between ship and its debris.  Fix up collision pairs
219  * when large ship is warping out.
220  * 
221  * 90    6/10/99 3:43p Dave
222  * Do a better job of syncing text colors to HUD gauges.
223  * 
224  * 89    6/07/99 4:21p Andsager
225  * Add HUD color for tagged object.  Apply to target and radar.
226  * 
227  * 88    6/04/99 5:08p Andsager
228  * Sort of hack to allow minicap and supercap tat the same time.
229  * 
230  * 87    6/03/99 9:29p Andsager
231  * Remove special case for Asteroid ship LOD warning
232  * 
233  * 86    6/03/99 11:43a Dave
234  * Added the ability to use a different model when rendering to the HUD
235  * target box.
236  * 
237  * 85    6/01/99 8:35p Dave
238  * Finished lockarm weapons. Added proper supercap weapons/damage. Added
239  * awacs-set-radius sexpression.
240  * 
241  * 84    5/28/99 9:26a Andsager
242  * Added check_world_pt_in_expanded_ship_bbox() function
243  * 
244  * 83    5/26/99 4:00p Dave
245  * Fixed small lighting bug,
246  * 
247  * 82    5/26/99 11:46a Dave
248  * Added ship-blasting lighting and made the randomization of lighting
249  * much more customizable.
250  * 
251  * 81    5/24/99 5:45p Dave
252  * Added detail levels to the nebula, with a decent speedup. Split nebula
253  * lightning into its own section.
254  * 
255  * 80    5/21/99 5:03p Andsager
256  * Add code to display engine wash death.  Modify ship_kill_packet
257  * 
258  * 79    5/20/99 7:00p Dave
259  * Added alternate type names for ships. Changed swarm missile table
260  * entries.
261  * 
262  * 78    5/19/99 11:09a Andsager
263  * Turn on engine wash.  Check every 1/4 sec.
264  * 
265  * 77    5/18/99 1:30p Dave
266  * Added muzzle flash table stuff.
267  * 
268  * 76    5/18/99 12:08p Andsager
269  * Added observer_process_post to handle observer too far away
270  * 
271  * 75    5/18/99 11:15a Andsager
272  * Fix bug in mulitplayer max rangel
273  * 
274  * 74    5/18/99 10:08a Andsager
275  * Modified single maximum range before blown up to also be multi
276  * friendly.
277  * 
278  * 73    5/14/99 3:01p Andsager
279  * Fix bug in ship_do_cap_subsys_cargo_revealed
280  * 
281  * 72    5/14/99 1:59p Andsager
282  * Multiplayer message for subsystem cargo revealed.
283  * 
284  * 71    5/14/99 11:50a Andsager
285  * Added vaporize for SMALL ships hit by HUGE beams.  Modified dying
286  * frame.  Enlarged debris shards and range at which visible.
287  * 
288  * 70    5/12/99 2:55p Andsager
289  * Implemented level 2 tag as priority in turret object selection
290  * 
291  * 69    5/11/99 10:16p Andsager
292  * First pass on engine wash effect.  Rotation (control input), damage,
293  * shake.  
294  * 
295  * 68    5/10/99 4:54p Dave
296  * Fixed particularly hideous subsystem bug related to multiple ship types
297  * using the same model.
298  * 
299  * 67    4/30/99 12:18p Dave
300  * Several minor bug fixes.
301  * 
302  * 66    4/29/99 2:29p Dave
303  * Made flak work much better in multiplayer.
304  * 
305  * 65    4/28/99 11:13p Dave
306  * Temporary checkin of artillery code.
307  * 
308  * 64    4/28/99 3:11p Andsager
309  * Stagger turret weapon fire times.  Make turrets smarter when target is
310  * protected or beam protected.  Add weaopn range to weapon info struct.
311  * 
312  * 63    4/27/99 12:16a Dave
313  * Fixed beam weapon muzzle glow problem. Fixed premature timeout on the
314  * pxo server list screen. Fixed secondary firing for hosts on a
315  * standalone. Fixed wacky multiplayer weapon "shuddering" problem.
316  * 
317  * 62    4/23/99 12:30p Andsager
318  * Add debug code for showing attack point against big ships.
319  * 
320  * 61    4/23/99 12:01p Johnson
321  * Added SIF_HUGE_SHIP
322  * 
323  * 60    4/20/99 6:39p Dave
324  * Almost done with artillery targeting. Added support for downloading
325  * images on the PXO screen.
326  * 
327  * 59    4/19/99 11:01p Dave
328  * More sophisticated targeting laser support. Temporary checkin.
329  * 
330  * 58    4/19/99 12:21p Johnson
331  * Allow ships with invisible polygons which do not collide
332  * 
333  * 57    4/16/99 5:54p Dave
334  * Support for on/off style "stream" weapons. Real early support for
335  * target-painting lasers.
336  * 
337  * 56    4/12/99 10:07p Dave
338  * Made network startup more forgiving. Added checkmarks to dogfight
339  * screen for players who hit commit.
340  * 
341  * 55    4/02/99 9:55a Dave
342  * Added a few more options in the weapons.tbl for beam weapons. Attempt
343  * at putting "pain" packets into multiplayer.
344  * 
345  * 54    3/31/99 8:24p Dave
346  * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
347  * and background nebulae. Added per-ship non-dimming pixel colors.
348  * 
349  * 53    3/30/99 5:40p Dave
350  * Fixed reinforcements for TvT in multiplayer.
351  * 
352  * 52    3/29/99 6:17p Dave
353  * More work on demo system. Got just about everything in except for
354  * blowing ships up, secondary weapons and player death/warpout.
355  * 
356  * 51    3/28/99 5:58p Dave
357  * Added early demo code. Make objects move. Nice and framerate
358  * independant, but not much else. Don't use yet unless you're me :)
359  * 
360  * 50    3/26/99 5:23p Andsager
361  * Fix bug with special explostions sometimes not generating shockwaves.
362  * 
363  * 49    3/26/99 4:49p Dave
364  * Made cruisers able to dock with stuff. Made docking points and paths
365  * visible in fred.
366  * 
367  * 48    3/25/99 4:47p Johnson
368  * HACK allow Mycernus to dock with Enif
369  * 
370  * 47    3/25/99 2:38p Johnson
371  * Give brad special mission docking stuff
372  * 
373  * 46    3/25/99 1:30p Johnson
374  * Allow Arcadia/Mentu docking
375  * 
376  * 45    3/24/99 4:05p Dave
377  * Put in support for assigning the player to a specific squadron with a
378  * specific logo. Preliminary work for doing pos/orient checksumming in
379  * multiplayer to reduce bandwidth.
380  * 
381  * 44    3/23/99 2:29p Andsager
382  * Fix shockwaves for kamikazi and Fred defined.  Collect together
383  * shockwave_create_info struct.
384  * 
385  * 43    3/20/99 3:46p Dave
386  * Added support for model-based background nebulae. Added 3 new
387  * sexpressions.
388  * 
389  * 42    3/19/99 9:51a Dave
390  * Checkin to repair massive source safe crash. Also added support for
391  * pof-style nebulae, and some new weapons code.
392  * 
393  * 43    3/12/99 4:30p Anoop
394  * Check for OBJ_NONE as well as OBJ_GHOST when firing secondary weapons
395  * 
396  * 42    3/11/99 2:22p Dave
397  * Fixed a countermeasure firing assert for multiplayer.
398  * 
399  * 41    3/10/99 6:51p Dave
400  * Changed the way we buffer packets for all clients. Optimized turret
401  * fired packets. Did some weapon firing optimizations.
402  * 
403  * 40    3/10/99 2:29p Dan
404  * disable lod warning for asteroid ships
405  * 
406  * 39    3/09/99 6:24p Dave
407  * More work on object update revamping. Identified several sources of
408  * unnecessary bandwidth.
409  * 
410  * 38    3/08/99 7:03p Dave
411  * First run of new object update system. Looks very promising.
412  * 
413  * 37    3/05/99 1:33p Dave
414  * Upped subsystem max to 700
415  * 
416  * 36    3/04/99 6:09p Dave
417  * Added in sexpressions for firing beams and checking for if a ship is
418  * tagged.
419  * 
420  * 35    3/02/99 9:25p Dave
421  * Added a bunch of model rendering debug code. Started work on fixing
422  * beam weapon wacky firing.
423  * 
424  * 34    3/01/99 7:39p Dave
425  * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
426  * don't mix respawn points.
427  * 
428  * 33    2/26/99 6:01p Andsager
429  * Add sexp has-been-tagged-delay and cap-subsys-cargo-known-delay
430  * 
431  * 32    2/26/99 4:14p Dave
432  * Put in the ability to have multiple shockwaves for ships.
433  * 
434  * 31    2/21/99 1:48p Dave
435  * Some code for monitoring datarate for multiplayer in detail.
436  * 
437  * 30    2/19/99 3:52p Neilk
438  * Put in some proper handling code for undocking dying objects (handle
439  * wacky object types like OBJ_GHOST).
440  * 
441  * 29    2/11/99 5:22p Andsager
442  * Fixed bugs, generalized block Sexp_variables
443  * 
444  * 28    2/11/99 2:15p Andsager
445  * Add ship explosion modification to FRED
446  * 
447  * 27    2/05/99 12:52p Dave
448  * Fixed Glide nondarkening textures.
449  * 
450  * 26    2/03/99 12:42p Andsager
451  * Add escort priority.  Modify ship_flags_dlg to include field.  Save and
452  * Load.  Add escort priority field to ship.
453  * 
454  * 25    2/02/99 9:36a Andsager
455  * Bash hull strength to zero when ship is killed (by sexp)
456  * 
457  * 24    1/29/99 2:25p Andsager
458  * Added turret_swarm_missiles
459  * 
460  * 23    1/29/99 12:47a Dave
461  * Put in sounds for beam weapon. A bunch of interface screens (tech
462  * database stuff).
463  * 
464  * 22    1/27/99 9:56a Dave
465  * Temporary checkin of beam weapons for Dan to make cool sounds.
466  * 
467  * 21    1/25/99 5:03a Dave
468  * First run of stealth, AWACS and TAG missile support. New mission type
469  * :)
470  * 
471  * 20    1/24/99 11:37p Dave
472  * First full rev of beam weapons. Very customizable. Removed some bogus
473  * Int3()'s in low level net code.
474  * 
475  * 19    1/14/99 6:06p Dave
476  * 100% full squad logo support for single player and multiplayer.
477  * 
478  * 18    1/14/99 12:48a Dave
479  * Todo list bug fixes. Made a pass at putting briefing icons back into
480  * FRED. Sort of works :(
481  * 
482  * 17    1/12/99 5:45p Dave
483  * Moved weapon pipeline in multiplayer to almost exclusively client side.
484  * Very good results. Bandwidth goes down, playability goes up for crappy
485  * connections. Fixed object update problem for ship subsystems.
486  * 
487  * 16    1/08/99 2:08p Dave
488  * Fixed software rendering for pofview. Super early support for AWACS and
489  * beam weapons.
490  * 
491  * 15    1/06/99 2:24p Dave
492  * Stubs and release build fixes.
493  * 
494  * 14    12/23/98 2:53p Andsager
495  * Added ship activation and gas collection subsystems, removed bridge
496  * 
497  * 13    12/09/98 7:34p Dave
498  * Cleanup up nebula effect. Tweaked many values.
499  * 
500  * 12    12/08/98 9:36a Dave
501  * Almost done nebula effect for D3D. Looks 85% as good as Glide.
502  * 
503  * 11    12/06/98 2:36p Dave
504  * Drastically improved nebula fogging.
505  * 
506  * 10    11/19/98 4:19p Dave
507  * Put IPX sockets back in psnet. Consolidated all multiplayer config
508  * files into one.
509  * 
510  * 9     11/14/98 5:33p Dave
511  * Lots of nebula work. Put in ship contrails.
512  * 
513  * 8     11/11/98 5:37p Dave
514  * Checkin for multiplayer testing.
515  * 
516  * 7     10/26/98 9:42a Dave
517  * Early flak gun support.
518  * 
519  * 6     10/23/98 3:51p Dave
520  * Full support for tstrings.tbl and foreign languages. All that remains
521  * is to make it active in Fred.
522  * 
523  * 5     10/23/98 3:03p Andsager
524  * Initial support for changing rotation rate.
525  * 
526  * 4     10/20/98 1:39p Andsager
527  * Make so sparks follow animated ship submodels.  Modify
528  * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
529  * submodel_num.  Add submodel_num to multiplayer hit packet.
530  * 
531  * 3     10/13/98 9:29a Dave
532  * Started neatening up freespace.h. Many variables renamed and
533  * reorganized. Added AlphaColors.[h,cpp]
534  * 
535  * 2     10/07/98 10:53a Dave
536  * Initial checkin.
537  * 
538  * 1     10/07/98 10:51a Dave
539  * 
540  * 915   8/28/98 3:29p Dave
541  * EMP effect done. AI effects may need some tweaking as required.
542  * 
543  * 914   8/25/98 1:48p Dave
544  * First rev of EMP effect. Player side stuff basically done. Next comes
545  * AI code.
546  * 
547  * 913   8/17/98 5:07p Dave
548  * First rev of corkscrewing missiles.
549  * 
550  * 912   7/15/98 11:29a Allender
551  * quick error dialog to prevent the > 50 ships per mission problem
552  * 
553  * 911   7/06/98 6:11p Dave
554  * More object update stuff.
555  * 
556  * 910   6/30/98 2:23p Dave
557  * Revised object update system. Removed updates for all weapons. Put
558  * button info back into control info packet.
559  * 
560  * 909   6/12/98 2:49p Dave
561  * Patch 1.02 changes.
562  * 
563  * 908   6/10/98 6:46p Lawrance
564  * increase SHIP_MULTITEXT_LENGTH to 1500
565  * 
566  * 906   6/09/98 10:31a Hoffoss
567  * Created index numbers for all xstr() references.  Any new xstr() stuff
568  * added from here on out should be added to the end if the list.  The
569  * current list count can be found in FreeSpace.cpp (search for
570  * XSTR_SIZE).
571  * 
572  * 905   6/01/98 11:43a John
573  * JAS & MK:  Classified all strings for localization.
574  * 
575  * 904   5/24/98 10:50p Mike
576  * Fix problem with ships with propagating explosions not being able to
577  * kamikaze.
578  * 
579  * 903   5/23/98 4:14p John
580  * Added code to preload textures to video card for AGP.   Added in code
581  * to page in some bitmaps that weren't getting paged in at level start.
582  * 
583  * 902   5/23/98 12:05a Adam
584  * change ship_is_getting_locked() to take weapon range into account
585  * 
586  * 901   5/22/98 5:32p Andsager
587  * Make big ship explosion sounds play all the way through.  remove
588  * cur_snd from ship struct.
589  * 
590  * 900   5/21/98 7:11p Sandeep
591  * Increased the buffer size a bit during parse ships.tbl to account for
592  * slightly lengthy descriptions
593  * 
594  * 899   5/21/98 3:31p Allender
595  * fix bug where Ship_obj_list was getting overwritten by the exited ships
596  * list
597  * 
598  * 898   5/21/98 1:44p Lawrance
599  * add ship_obj list validation
600  * 
601  * 897   5/21/98 11:33a Lawrance
602  * Check aspect_locked_time when determining if another ship is seeking
603  * lock
604  * 
605  * 896   5/19/98 8:42p Andsager
606  * Add cur_snd (used for sound management of big ship explosions)
607  * 
608  * 895   5/18/98 2:50p Peter
609  * AL: Check to make sure we don't overflow support_ships[] array in
610  * ship_find_repair_ship
611  * 
612  * 894   5/15/98 11:11p Mike
613  * Make game a bit easier based on skill level, mainly at Easy and, to a
614  * lesser extent, Medium.
615  * 
616  * 893   5/15/98 6:45p Hoffoss
617  * Made some things not appear in the release version of Fred.
618  * 
619  * 892   5/15/98 5:37p Hoffoss
620  * Added new 'tech description' fields to ship and weapon tables, and
621  * added usage of it in tech room.
622  * 
623  * 891   5/15/98 12:07p Allender
624  * make messaging come from proper ships when in team vs. team games.
625  * 
626  * 890   5/14/98 9:38p Andsager
627  * Fixed bug in dying_undock_physics when both ships have ovelapping dying
628  * times.
629  * 
630  * 889   5/13/98 6:54p Dave
631  * More sophistication to PXO interface. Changed respawn checking so
632  * there's no window for desynchronization between the server and the
633  * clients.
634  * 
635  * 888   5/12/98 10:54p Andsager
636  * Add new sound manager for big ship sub-explosion sounds
637  * 
638  * 887   5/12/98 2:34p Adam
639  * re-instated the old nicer particle ANI's for ship explosions.
640  * 
641  * 886   5/12/98 9:15a Andsager
642  * Clean up big ship sub-explosion sound.  Make single instance of sounds.
643  * Choose random sounds.  Add timestamp to post split sounds.  Make
644  * explosion flash depend on wheth ship was visible if within ~1.5 radii.
645  * 
646  * 885   5/11/98 4:33p Allender
647  * fixed ingame join problems -- started to work on new object updating
648  * code (currently ifdef'ed out)
649  * 
650  * 884   5/11/98 4:05p Lawrance
651  * Increase sanity timestamp for next_fire_time to 60 seconds
652  * 
653  * 883   5/10/98 11:30p Mike
654  * Better firing of bombs, less likely to go into strafe mode.
655  * 
656  * 882   5/09/98 4:52p Lawrance
657  * Implement padlock view (up/rear/left/right)
658  * 
659  * 881   5/08/98 5:31p Hoffoss
660  * Isolated the joystick force feedback code more from dependence on other
661  * libraries.
662  * 
663  * 880   5/08/98 4:39p Mike
664  * Comment out two Asserts that trap a condition that is actually legal. 
665  *
666  * $NoKeywords: $
667  */
668
669 #include <string.h>
670 #include <setjmp.h>
671
672 #include "pstypes.h"
673 #include "object.h"
674 #include "physics.h"
675 #include "vecmat.h"
676 #include "ship.h"
677 #include "model.h"
678 #include "key.h"
679 #include "weapon.h"
680 #include "radar.h"
681 #include "2d.h"
682 #include "3d.h"
683 #include "floating.h"
684 #include "ai.h"
685 #include "ailocal.h"
686 #include "fireballs.h"
687 #include "debris.h"
688 #include "hud.h"
689 #include "timer.h"
690 #include "cfile.h"
691 #include "missionlog.h"
692 #include "missionparse.h"
693 #include "bmpman.h"
694 #include "joy.h"
695 #include "joy_ff.h"
696 #include "player.h"
697 #include "parselo.h"
698 #include "freespace.h"
699 #include "sound.h"
700 #include "model.h"
701 #include "linklist.h"
702 #include "hudets.h"
703 #include "hudtarget.h"
704 #include "hudshield.h"
705 #include "multi.h"
706 #include "multiutil.h"
707 #include "multimsgs.h"
708 #include "aigoals.h"
709 #include "gamesnd.h"
710 #include "eventmusic.h"
711 #include "shipfx.h"
712 #include "sexp.h"
713 #include "gamesequence.h"
714 #include "objectsnd.h"
715 #include "cmeasure.h"
716 #include "animplay.h"
717 #include "controlsconfig.h"
718 #include "afterburner.h"
719 #include "shockwave.h"
720 #include "hudsquadmsg.h"
721 #include "swarm.h"
722 #include "fvi.h"
723 #include "subsysdamage.h"
724 #include "missionmessage.h"
725 #include "lighting.h"
726 #include "particle.h"
727 #include "shiphit.h"
728 #include "asteroid.h"
729 #include "hudtargetbox.h"
730 #include "multi_respawn.h"
731 #include "hudartillery.h"
732 #include "hudwingmanstatus.h"
733 #include "jumpnode.h"
734 #include "redalert.h"
735 #include "corkscrew.h"
736 #include "emp.h"
737 #include "localize.h"
738 #include "neb.h"
739 #include "shipcontrails.h"
740 #include "alphacolors.h"
741 #include "demo.h"
742 #include "beam.h"
743 #include "staticrand.h"
744 #include "missionshipchoice.h"
745
746 #if defined(FS2_DEMO) || defined(FS1_DEMO)
747         #define MAX_SHIP_SUBOBJECTS             360
748 #else
749         #define MAX_SHIP_SUBOBJECTS             700                     //      Reduced from 1000 to 400 by MK on 4/1/98.  
750                                                                                                                                 // Highest I saw was 164 in sm2-03a which Sandeep says has a lot of ships.
751                                                                                                                                 // JAS: sm3-01 needs 460.   You cannot know this number until *all* ships
752                                                                                                                                 // have warped in.   So I put code in the paging code which knows all ships
753                                                                                                                                 // that will warp in.
754 #endif
755
756 //#define MIN_COLLISION_MOVE_DIST               5.0
757 //#define COLLISION_VEL_CONST                   0.1
758 #define COLLISION_FRICTION_FACTOR       0.0             // ratio of maximum friction impulse to repulsion impulse
759 #define COLLISION_ROTATION_FACTOR       1.0             // increase in rotation from collision
760
761 int     Ai_render_debug_flag=0;
762 #ifndef NDEBUG
763 int     Ship_sphere_check = 0;
764 int     Ship_auto_repair = 1;           // flag to indicate auto-repair of subsystem should occur
765 extern void render_path_points(object *objp);
766 #endif
767
768 // mwa -- removed 11/24/97 int  num_ships = 0;
769 int     num_wings = 0;
770 int     Num_reinforcements = 0;
771 ship    Ships[MAX_SHIPS];
772 ship    *Player_ship;
773 wing    Wings[MAX_WINGS];
774 int     Starting_wings[MAX_PLAYER_WINGS];  // wings player starts a mission with (-1 = none)
775 int     ships_inited = 0;
776
777 engine_wash_info Engine_wash_info[MAX_ENGINE_WASH_TYPES];
778 char get_engine_wash_index(char *engine_wash_name);
779
780 // information for ships which have exited the game
781 exited_ship Ships_exited[MAX_EXITED_SHIPS];
782 int Num_exited_ships;
783
784 int     Num_engine_wash_types;
785 int     Num_ship_types;
786 int     Num_ship_subobj_types;
787 int     Num_ship_subobjects;
788 int     Player_ship_class;      // needs to be player specific, move to player structure        
789
790 #define         SHIP_OBJ_USED   (1<<0)                          // flag used in ship_obj struct
791 #define         MAX_SHIP_OBJS   MAX_SHIPS                       // max number of ships tracked in ship list
792 ship_obj                Ship_objs[MAX_SHIP_OBJS];               // array used to store ship object indexes
793 ship_obj                Ship_obj_list;                                                  // head of linked list of ship_obj structs
794
795 ship_info               Ship_info[MAX_SHIP_TYPES];
796 ship_subsys             Ship_subsystems[MAX_SHIP_SUBOBJECTS];
797 ship_subsys             ship_subsys_free_list;
798 reinforcements  Reinforcements[MAX_REINFORCEMENTS];
799
800 int Num_player_ship_precedence;                         // Number of ship types in Player_ship_precedence
801 int Player_ship_precedence[MAX_PLAYER_SHIP_CHOICES];    // Array of ship types, precedence list for player ship/wing selection
802
803 static int Laser_energy_out_snd_timer;  // timer so we play out of laser sound effect periodically
804 static int Missile_out_snd_timer;       // timer so we play out of laser sound effect periodically
805
806 // structure used to hold ship counts of particular types.  The order in which these appear is crucial
807 // since the goal code relies on this placement to find the array index in the Ship_counts array
808 const char *Ship_type_names[MAX_SHIP_TYPE_COUNTS] = {
809 //XSTR:OFF
810         "no type",
811         "cargo",
812         "fighter/bomber",
813         "cruiser",
814         "freighter",
815         "capital",
816         "transport",
817         "support",
818         "navbuoy",
819         "sentry gun",
820         "escape pod",
821         "super cap",
822         "stealth",
823         "fighter",
824         "bomber",
825         "drydock",
826         "awacs",
827         "gas miner",
828         "corvette",
829         "knossos device"
830 //XSTR:ON
831 };
832
833 int Ship_type_flags[MAX_SHIP_TYPE_COUNTS] = {
834         0,
835         SIF_CARGO,
836         SIF_FIGHTER | SIF_BOMBER,
837         SIF_CRUISER,
838         SIF_FREIGHTER,
839         SIF_CAPITAL,
840         SIF_TRANSPORT,
841         SIF_SUPPORT,
842         SIF_NAVBUOY,
843         SIF_SENTRYGUN,
844         SIF_ESCAPEPOD,
845         SIF_SUPERCAP,
846         SIF_STEALTH,
847         SIF_FIGHTER,
848         SIF_BOMBER,
849         SIF_DRYDOCK,
850         SIF_AWACS,
851         SIF_GAS_MINER,
852         SIF_CORVETTE,
853         SIF_KNOSSOS_DEVICE,
854 };
855
856 ship_counts Ship_counts[MAX_SHIP_TYPE_COUNTS];
857
858 // I don't want to do an AI cargo check every frame, so I made a global timer to limit check to
859 // every SHIP_CARGO_CHECK_INTERVAL ms.  Didn't want to make a timer in each ship struct.  Ensure
860 // inited to 1 at mission start.
861 static int Ship_cargo_check_timer;
862
863 // a global definition of the IFF colors
864 color IFF_colors[MAX_IFF_COLORS][2];    // AL 1-2-97: Create two IFF colors, regular and bright
865
866 void ship_iff_init_colors()
867 {
868         int i, alpha;
869         int iff_bright_delta=4;
870
871         // init IFF colors
872         for ( i=0; i<2; i++ ) {
873
874                 if ( i == 0 )
875                         alpha = (HUD_COLOR_ALPHA_MAX - iff_bright_delta) * 16;
876                 else 
877                         alpha = HUD_COLOR_ALPHA_MAX * 16;
878
879                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_HOSTILE][i],  0xff, 0x00, 0x00, alpha, AC_TYPE_HUD);
880                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_FRIENDLY][i], 0x00, 0xff, 0x00, alpha, AC_TYPE_HUD);
881                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_NEUTRAL][i],  0xff, 0x00, 0x00, alpha, AC_TYPE_HUD);
882                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_UNKNOWN][i],  0xff, 0x00, 0xff, alpha, AC_TYPE_HUD);
883                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_SELECTION][i], 0xff, 0xff, 0xff, alpha, AC_TYPE_HUD);
884                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_MESSAGE][i],  0x7f, 0x7f, 0x7f, alpha, AC_TYPE_HUD);
885                 gr_init_alphacolor( &IFF_colors[IFF_COLOR_TAGGED][i],           0xff, 0xff, 0x00, alpha, AC_TYPE_HUD);
886         }
887 }
888
889 // set the ship_obj struct fields to default values
890 void ship_obj_list_reset_slot(int index)
891 {
892         Ship_objs[index].flags = 0;
893         Ship_objs[index].next = NULL;
894         Ship_objs[index].prev = (ship_obj*)-1;
895 }
896
897 // if the given ship is in alpha/beta/gamma/zeta wings
898 int ship_in_abgz(ship *shipp)
899 {
900         if(!strcmp(shipp->ship_name, "Alpha 1")) return 1;
901         if(!strcmp(shipp->ship_name, "Alpha 2")) return 1;
902         if(!strcmp(shipp->ship_name, "Alpha 3")) return 1;
903         if(!strcmp(shipp->ship_name, "Alpha 4")) return 1;
904
905         if(!strcmp(shipp->ship_name, "Beta 1")) return 1;
906         if(!strcmp(shipp->ship_name, "Beta 2")) return 1;
907         if(!strcmp(shipp->ship_name, "Beta 3")) return 1;
908         if(!strcmp(shipp->ship_name, "Beta 4")) return 1;
909
910         if(!strcmp(shipp->ship_name, "Gamma 1")) return 1;
911         if(!strcmp(shipp->ship_name, "Gamma 2")) return 1;
912         if(!strcmp(shipp->ship_name, "Gamma 3")) return 1;
913         if(!strcmp(shipp->ship_name, "Gamma 4")) return 1;
914
915         if(!strcmp(shipp->ship_name, "Zeta 1")) return 1;
916         if(!strcmp(shipp->ship_name, "Zeta 2")) return 1;
917         if(!strcmp(shipp->ship_name, "Zeta 3")) return 1;
918         if(!strcmp(shipp->ship_name, "Zeta 4")) return 1;
919
920         // not in
921         return 0;
922 }
923
924 // ---------------------------------------------------
925 // ship_obj_list_init()
926 //
927 void ship_obj_list_init()
928 {
929         int i;
930
931         list_init(&Ship_obj_list);
932         for ( i = 0; i < MAX_SHIP_OBJS; i++ ) {
933                 ship_obj_list_reset_slot(i);
934         }
935 }
936
937 // ---------------------------------------------------
938 // ship_obj_list_add()
939 //
940 // Function to add a node to the Ship_obj_list.  Only
941 // called from ship_create()
942 int ship_obj_list_add(int objnum)
943 {
944         int i;
945
946         for ( i = 0; i < MAX_SHIP_OBJS; i++ ) {
947                 if ( !(Ship_objs[i].flags & SHIP_OBJ_USED) )
948                         break;
949         }
950         if ( i == MAX_SHIP_OBJS ) {
951                 Error(LOCATION, "Fatal Error: Ran out of ship object nodes\n");
952                 return -1;
953         }
954         
955         Ship_objs[i].flags = 0;
956         Ship_objs[i].objnum = objnum;
957         list_append(&Ship_obj_list, &Ship_objs[i]);
958         Ship_objs[i].flags |= SHIP_OBJ_USED;
959
960         return i;
961 }
962
963 // ---------------------------------------------------
964 // ship_obj_list_remove()
965 //
966 // Function to remove a node from the Ship_obj_list.  Only
967 // called from ship_delete()
968 void ship_obj_list_remove(int index)
969 {
970         SDL_assert(index >= 0 && index < MAX_SHIP_OBJS);
971         list_remove(&Ship_obj_list, &Ship_objs[index]); 
972         ship_obj_list_reset_slot(index);
973 }
974
975 // ---------------------------------------------------
976 // ship_obj_list_rebuild()
977 //
978 // Called from the save/restore code to re-create the Ship_obj_list
979 //
980 void ship_obj_list_rebuild()
981 {
982         object *objp;
983
984         ship_obj_list_init();
985
986         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
987                 if ( objp->type == OBJ_SHIP ) {
988                         Ships[objp->instance].ship_list_index = ship_obj_list_add(OBJ_INDEX(objp));
989                 }
990         }
991 }
992
993 ship_obj *get_ship_obj_ptr_from_index(int index)
994 {
995         SDL_assert(index >= 0 && index < MAX_SHIP_OBJS);
996         return &Ship_objs[index];
997 }
998
999
1000 // return number of ships in the game.
1001 int ship_get_num_ships()
1002 {
1003         int count;
1004         ship_obj *so;
1005
1006         count = 0;
1007         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) )
1008                 count++;
1009
1010         return count;
1011 }
1012
1013 // parse an engine wash info record
1014 void parse_engine_wash()
1015 {
1016         engine_wash_info *ewp;
1017         ewp = &Engine_wash_info[Num_engine_wash_types];
1018
1019         // name of engine wash info
1020         required_string("$Name:");
1021         stuff_string(ewp->name, F_NAME, NULL);
1022
1023         // half angle of cone of wash from thruster
1024         required_string("$Angle:");
1025         stuff_float(&ewp->angle);
1026         ewp->angle *= (PI / 180.0f);
1027
1028         // radius multiplier for hemisphere around thruster pt
1029         required_string("$Radius Mult:");
1030         stuff_float(&ewp->radius_mult);
1031
1032         // length of cone
1033         required_string("$Length:");
1034         stuff_float(&ewp->length);
1035
1036         // intensity inside hemisphere (or at 0 distance from frustated cone)
1037         required_string("$Intensity:");
1038         stuff_float(&ewp->intensity);
1039 }
1040
1041
1042 #define SHIP_MULTITEXT_LENGTH 1500
1043 // function to parse the information for a specific ship type.  
1044 int parse_ship()
1045 {
1046         char buf[SHIP_MULTITEXT_LENGTH + 1];
1047         ship_info *sip;
1048         int cont_flag = 1;
1049         float   hull_percentage_of_hits = 100.0f;
1050         int n_subsystems = 0;
1051         model_subsystem subsystems[MAX_MODEL_SUBSYSTEMS];               // see model.h for max_model_subsystems
1052         for (int idx=0; idx<MAX_MODEL_SUBSYSTEMS; idx++) {
1053                 subsystems[idx].stepped_rotation = NULL;
1054                 subsystems[idx].ai_rotation = NULL;
1055         }
1056         int i, num_allowed, rtn = 0;
1057         int allowed_weapons[MAX_WEAPON_TYPES];
1058
1059         sip = &Ship_info[Num_ship_types];
1060
1061         //      Defaults!
1062         //      These should be specified in ships.tbl eventually!
1063         //      End of defaults.
1064
1065         required_string("$Name:");
1066         stuff_string(sip->name, F_NAME, NULL);
1067
1068         // AL 28-3-98: If this is a demo build, we only want to parse weapons that are preceded with
1069         //             the '@' symbol
1070 #ifdef DEMO // not needed FS2_DEMO (using separate table file)
1071         if ( sip->name[0] != '@' ) {
1072                 // advance to next weapon, and return -1
1073                 if ( skip_to_start_of_strings("$Name:", "#End") != 1 ) {
1074                         Int3();
1075                 }
1076                 return -1;
1077         }
1078 #endif
1079
1080 #ifdef NDEBUG
1081         if (SDL_strchr(sip->name, '#') && Fred_running)
1082                 rtn = 1;
1083 #endif
1084
1085         if ( sip->name[0] == '@' ) {
1086                 char old_name[NAME_LENGTH];
1087                 SDL_strlcpy(old_name, sip->name, sizeof(old_name));
1088                 SDL_strlcpy(sip->name, old_name+1, sizeof(sip->name));
1089         }
1090
1091         diag_printf ("Ship name -- %s\n", sip->name);
1092         if ( ship_info_lookup( sip->name ) != -1 ){
1093                 Error(LOCATION, "Error:  Ship name %s already exists in ships.tbl.  All ship class names must be unique.", sip->name);
1094         }
1095
1096         required_string("$Short name:");
1097         stuff_string(sip->short_name, F_NAME, NULL);
1098         diag_printf ("Ship short name -- %s\n", sip->short_name);
1099
1100         find_and_stuff("$Species:", &sip->species, F_NAME, Species_names, MAX_SPECIES_NAMES, "species names");
1101         diag_printf ("Ship species -- %s\n", Species_names[sip->species]);
1102
1103         sip->type_str = sip->maneuverability_str = sip->armor_str = sip->manufacturer_str = NULL;
1104         if (optional_string("+Type:")) {
1105                 stuff_string(buf, F_MESSAGE, NULL);
1106                 sip->type_str = strdup(buf);
1107         }
1108
1109         if (optional_string("+Maneuverability:")) {
1110                 stuff_string(buf, F_MESSAGE, NULL);
1111                 sip->maneuverability_str = strdup(buf);
1112         }
1113
1114         if (optional_string("+Armor:")) {
1115                 stuff_string(buf, F_MESSAGE, NULL);
1116                 sip->armor_str = strdup(buf);
1117         }
1118
1119         if (optional_string("+Manufacturer:")) {
1120                 stuff_string(buf, F_MESSAGE, NULL);
1121                 sip->manufacturer_str = strdup(buf);
1122         }
1123
1124         sip->desc = NULL;
1125         if (optional_string("+Description:")) {
1126                 stuff_string(buf, F_MULTITEXT, NULL);
1127                 sip->desc = strdup(buf);
1128         }
1129
1130         sip->tech_desc = NULL;
1131         if (optional_string("+Tech Description:")) {
1132                 stuff_string(buf, F_MULTITEXT, NULL, SHIP_MULTITEXT_LENGTH);
1133                 sip->tech_desc = strdup(buf);
1134         }
1135
1136         // Code added here by SS to parse the optional strings for length, gun_mounts, missile_banks
1137
1138         sip->ship_length = NULL;
1139         if (optional_string("+Length:")) {
1140                 stuff_string(buf, F_MESSAGE, NULL);
1141                 sip->ship_length = strdup(buf);
1142         }
1143         
1144         sip->gun_mounts = NULL;
1145         if (optional_string("+Gun Mounts:")) {
1146                 stuff_string(buf, F_MESSAGE, NULL);
1147                 sip->gun_mounts = strdup(buf);
1148         }
1149         
1150         sip->missile_banks = NULL;
1151         if (optional_string("+Missile Banks:")) {
1152                 stuff_string(buf, F_MESSAGE, NULL);
1153                 sip->missile_banks = strdup(buf);
1154         }
1155
1156
1157         // End code by SS
1158
1159         sip->num_detail_levels = 0;
1160
1161         required_string( "$POF file:" );
1162         stuff_string( sip->pof_file, F_NAME, NULL );
1163
1164         // optional hud targeting model
1165         SDL_strlcpy(sip->pof_file_hud, "", sizeof(sip->pof_file_hud));
1166         if(optional_string( "$POF target file:")){
1167                 stuff_string(sip->pof_file_hud, F_NAME, NULL);
1168         }
1169
1170         required_string("$Detail distance:");
1171         sip->num_detail_levels = stuff_int_list(sip->detail_distance, MAX_SHIP_DETAIL_LEVELS, RAW_INTEGER_TYPE);
1172
1173         // check for optional pixel colors
1174         sip->num_nondark_colors = 0;
1175         while(optional_string("$ND:")){         
1176                 ubyte nr, ng, nb;
1177                 stuff_byte(&nr);
1178                 stuff_byte(&ng);
1179                 stuff_byte(&nb);
1180
1181                 if(sip->num_nondark_colors < MAX_NONDARK_COLORS){
1182                         sip->nondark_colors[sip->num_nondark_colors][0] = nr;
1183                         sip->nondark_colors[sip->num_nondark_colors][1] = ng;
1184                         sip->nondark_colors[sip->num_nondark_colors++][2] = nb;
1185                 }
1186         }
1187
1188         required_string("$Show damage:");
1189         int bogus_bool;
1190         stuff_boolean(&bogus_bool);
1191
1192         required_string("$Density:");
1193         stuff_float( &(sip->density) );
1194         diag_printf ("Ship density -- %7.3f\n", sip->density);
1195
1196         required_string("$Damp:");
1197         stuff_float( &(sip->damp) );
1198         diag_printf ("Ship damp -- %7.3f\n", sip->damp);
1199
1200         required_string("$Rotdamp:");
1201         stuff_float( &(sip->rotdamp) );
1202         diag_printf ("Ship rotdamp -- %7.3f\n", sip->rotdamp);
1203
1204         required_string("$Max Velocity:");
1205         stuff_vector(&sip->max_vel);
1206
1207         // calculate the max speed from max_velocity
1208         sip->max_speed = vm_vec_mag(&sip->max_vel);
1209
1210         required_string("$Rotation Time:");
1211         stuff_vector(&sip->rotation_time);
1212
1213         sip->srotation_time = (sip->rotation_time.xyz.x + sip->rotation_time.xyz.y)/2.0f;
1214
1215         sip->max_rotvel.xyz.x = (2 * PI) / sip->rotation_time.xyz.x;
1216         sip->max_rotvel.xyz.y = (2 * PI) / sip->rotation_time.xyz.y;
1217         sip->max_rotvel.xyz.z = (2 * PI) / sip->rotation_time.xyz.z;
1218
1219         // get the backwards velocity;
1220         required_string("$Rear Velocity:");
1221         stuff_float(&sip->max_rear_vel);
1222
1223         // get the accelerations
1224         required_string("$Forward accel:");
1225         stuff_float(&sip->forward_accel );
1226
1227         required_string("$Forward decel:");
1228         stuff_float(&sip->forward_decel );
1229
1230         required_string("$Slide accel:");
1231         stuff_float(&sip->slide_accel );
1232
1233         required_string("$Slide decel:");
1234         stuff_float(&sip->slide_decel );
1235
1236         // get ship explosion info
1237         required_string("$Expl inner rad:");
1238         stuff_float(&sip->inner_rad);
1239
1240         required_string("$Expl outer rad:");
1241         stuff_float(&sip->outer_rad);
1242
1243         required_string("$Expl damage:");
1244         stuff_float(&sip->damage);
1245
1246         required_string("$Expl blast:");
1247         stuff_float(&sip->blast);
1248
1249         required_string("$Expl Propagates:");
1250         stuff_boolean(&sip->explosion_propagates);
1251
1252         required_string("$Shockwave Speed:");
1253         stuff_float( &sip->shockwave_speed );
1254
1255         sip->shockwave_count = 1;
1256         if(optional_string("$Shockwave Count:")){
1257                 stuff_int(&sip->shockwave_count);
1258         }
1259
1260         for ( i = 0; i < MAX_WEAPON_TYPES; i++ ){
1261                 sip->allowed_weapons[i] = 0;
1262         }
1263
1264         // Set the weapons filter used in weapons loadout (for primary weapons)
1265         if (optional_string("$Allowed PBanks:")) {
1266                 num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
1267
1268                 // actually say which weapons are allowed
1269                 for ( i = 0; i < num_allowed; i++ ) {
1270                         if ( allowed_weapons[i] >= 0 ) {                //      MK, Bug fix, 9/6/99.  Used to be "allowed_weapons" not "allowed_weapons[i]".
1271                                 sip->allowed_weapons[allowed_weapons[i]] |= 1;
1272                         }
1273                 }
1274         }
1275
1276         // Set the weapons filter used in weapons loadout (for primary weapons)
1277         if (optional_string("$Allowed Dogfight PBanks:")) {
1278                 num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
1279
1280                 // actually say which weapons are allowed
1281                 for ( i = 0; i < num_allowed; i++ ) {
1282                         if ( allowed_weapons[i] >= 0 ) {
1283                                 sip->allowed_weapons[allowed_weapons[i]] |= 2;
1284                         }
1285                 }
1286         }
1287
1288         //      Get default primary bank weapons
1289         for ( i = 0; i < MAX_PRIMARY_BANKS; i++ ){
1290                 sip->primary_bank_weapons[i] = -1;
1291         }
1292         required_string("$Default PBanks:");
1293         sip->num_primary_banks = stuff_int_list(sip->primary_bank_weapons, MAX_PRIMARY_BANKS, WEAPON_LIST_TYPE);
1294
1295         // error checking
1296         for ( i = 0; i < sip->num_primary_banks; i++ ) {
1297                 SDL_assert(sip->primary_bank_weapons[i] >= 0);
1298         }
1299
1300         // Set the weapons filter used in weapons loadout (for secondary weapons)
1301         if (optional_string("$Allowed SBanks:")) {
1302                 num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
1303
1304                 // actually say which weapons are allowed
1305                 for ( i = 0; i < num_allowed; i++ ) {
1306                         if ( allowed_weapons[i] >= 0 ) {
1307                                 sip->allowed_weapons[allowed_weapons[i]] |= 1;
1308                         }
1309                 }
1310         }
1311
1312         // Set the weapons filter used in weapons loadout (for secondary weapons)
1313         if (optional_string("$Allowed Dogfight SBanks:")) {
1314                 num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
1315
1316                 // actually say which weapons are allowed
1317                 for ( i = 0; i < num_allowed; i++ ) {
1318                         if ( allowed_weapons[i] >= 0 ) {
1319                                 sip->allowed_weapons[allowed_weapons[i]] |= 2;
1320                         }
1321                 }
1322         }
1323
1324         //      Get default secondary bank weapons
1325         for ( i = 0; i < MAX_SECONDARY_BANKS; i++ ){
1326                 sip->secondary_bank_weapons[i] = -1;
1327         }
1328         required_string("$Default SBanks:");
1329         sip->num_secondary_banks = stuff_int_list(sip->secondary_bank_weapons, MAX_SECONDARY_BANKS, WEAPON_LIST_TYPE);
1330
1331         // error checking
1332         for ( i = 0; i < sip->num_secondary_banks; i++ ) {
1333                 SDL_assert(sip->secondary_bank_weapons[i] >= 0);
1334         }
1335
1336         // Get the capacity of each secondary bank
1337         required_string("$Sbank Capacity:");
1338         int capacity_count;
1339         capacity_count = stuff_int_list(sip->secondary_bank_ammo_capacity, MAX_SECONDARY_BANKS, RAW_INTEGER_TYPE);
1340         if ( capacity_count != sip->num_secondary_banks ) {
1341                 Warning(LOCATION, "Secondary bank capacities have not been specified for ship class %s... fix this!!", sip->name);
1342         }
1343
1344         required_string("$Shields:");
1345         stuff_float(&sip->shields);
1346
1347         // optional shield color
1348         sip->shield_color[0] = 255;
1349         sip->shield_color[1] = 255;
1350         sip->shield_color[2] = 255;
1351         if(optional_string("$Shield Color:")){
1352                 stuff_byte(&sip->shield_color[0]);
1353                 stuff_byte(&sip->shield_color[1]);
1354                 stuff_byte(&sip->shield_color[2]);
1355         }
1356
1357         // The next three fields are used for the ETS
1358         required_string("$Power Output:");
1359         stuff_float(&sip->power_output);
1360
1361         required_string("$Max Oclk Speed:");
1362         stuff_float(&sip->max_overclocked_speed);
1363
1364         required_string("$Max Weapon Eng:");
1365         stuff_float(&sip->max_weapon_reserve);
1366
1367         required_string("$Hitpoints:");
1368         stuff_float(&sip->initial_hull_strength);
1369
1370         required_string("$Flags:");
1371         char    ship_strings[MAX_SHIP_FLAGS][NAME_LENGTH];
1372         int num_strings = stuff_string_list(ship_strings, MAX_SHIP_FLAGS);
1373         sip->flags = SIF_DEFAULT_VALUE;
1374         for ( i=0; i<num_strings; i++ ) {
1375                 if (!SDL_strcasecmp(NOX("no_collide"), ship_strings[i]))
1376                         sip->flags &= ~SIF_DO_COLLISION_CHECK;
1377                 else if (!SDL_strcasecmp(NOX("player_ship"), ship_strings[i]))
1378                         sip->flags |= SIF_PLAYER_SHIP;
1379                 else if (!SDL_strcasecmp(NOX("default_player_ship"), ship_strings[i]))
1380                         sip->flags |= SIF_DEFAULT_PLAYER_SHIP;
1381                 else if ( !SDL_strcasecmp(NOX("repair_rearm"), ship_strings[i]))
1382                         sip->flags |= SIF_SUPPORT;
1383                 else if ( !SDL_strcasecmp(NOX("cargo"), ship_strings[i]))
1384                         sip->flags |= SIF_CARGO;
1385                 else if ( !SDL_strcasecmp( NOX("fighter"), ship_strings[i]))
1386                         sip->flags |= SIF_FIGHTER;
1387                 else if ( !SDL_strcasecmp( NOX("bomber"), ship_strings[i]))
1388                         sip->flags |= SIF_BOMBER;
1389                 else if ( !SDL_strcasecmp( NOX("transport"), ship_strings[i]))
1390                         sip->flags |= SIF_TRANSPORT;
1391                 else if ( !SDL_strcasecmp( NOX("freighter"), ship_strings[i]))
1392                         sip->flags |= SIF_FREIGHTER;
1393                 else if ( !SDL_strcasecmp( NOX("capital"), ship_strings[i]))
1394                         sip->flags |= SIF_CAPITAL;
1395                 else if (!SDL_strcasecmp( NOX("supercap"), ship_strings[i]))
1396                         sip->flags |= SIF_SUPERCAP;
1397                 else if (!SDL_strcasecmp( NOX("drydock"), ship_strings[i]))
1398                         sip->flags |= SIF_DRYDOCK;
1399                 else if ( !SDL_strcasecmp( NOX("cruiser"), ship_strings[i]))
1400                         sip->flags |= SIF_CRUISER;
1401                 else if ( !SDL_strcasecmp( NOX("navbuoy"), ship_strings[i]))
1402                         sip->flags |= SIF_NAVBUOY;
1403                 else if ( !SDL_strcasecmp( NOX("sentrygun"), ship_strings[i]))
1404                         sip->flags |= SIF_SENTRYGUN;
1405                 else if ( !SDL_strcasecmp( NOX("escapepod"), ship_strings[i]))
1406                         sip->flags |= SIF_ESCAPEPOD;
1407                 else if ( !SDL_strcasecmp( NOX("no type"), ship_strings[i]))
1408                         sip->flags |= SIF_NO_SHIP_TYPE;
1409                 else if ( !SDL_strcasecmp( NOX("ship copy"), ship_strings[i]))
1410                         sip->flags |= SIF_SHIP_COPY;
1411                 else if ( !SDL_strcasecmp( NOX("in tech database"), ship_strings[i]))
1412 #ifdef MAKE_FS1
1413                         sip->flags |= SIF_IN_TECH_DATABASE;
1414 #else
1415                         sip->flags |= SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M;
1416 #endif
1417                 else if ( !SDL_strcasecmp( NOX("in tech database multi"), ship_strings[i]))
1418                         sip->flags |= SIF_IN_TECH_DATABASE_M;
1419                 else if ( !SDL_strcasecmp( NOX("dont collide invisible"), ship_strings[i]))
1420                         sip->flags |= SIF_DONT_COLLIDE_INVIS;
1421                 else if ( !SDL_strcasecmp( NOX("big damage"), ship_strings[i]))
1422                         sip->flags |= SIF_BIG_DAMAGE;
1423                 else if ( !SDL_strcasecmp( NOX("corvette"), ship_strings[i]))
1424                         sip->flags |= SIF_CORVETTE;
1425                 else if ( !SDL_strcasecmp( NOX("gas miner"), ship_strings[i]))
1426                         sip->flags |= SIF_GAS_MINER;
1427                 else if ( !SDL_strcasecmp( NOX("awacs"), ship_strings[i]))
1428                         sip->flags |= SIF_AWACS;
1429                 else if ( !SDL_strcasecmp( NOX("knossos"), ship_strings[i]))
1430                         sip->flags |= SIF_KNOSSOS_DEVICE;
1431                 else if ( !SDL_strcasecmp( NOX("no_fred"), ship_strings[i]))
1432                         sip->flags |= SIF_NO_FRED;
1433                 else
1434                         Warning(LOCATION, "Bogus string in ship flags: %s\n", ship_strings[i]);
1435         }
1436
1437         find_and_stuff("$AI Class:", &sip->ai_class, F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class names");
1438
1439         // Get Afterburner information
1440         // Be aware that if $Afterburner is not 1, the other Afterburner fields are not read in
1441         required_string("$Afterburner:");
1442         int has_afterburner;
1443         stuff_boolean(&has_afterburner);
1444         if ( has_afterburner == 1 ) {
1445                 sip->flags |= SIF_AFTERBURNER;
1446
1447                 required_string("+Aburn Max Vel:");
1448                 stuff_vector(&sip->afterburner_max_vel);
1449
1450                 required_string("+Aburn For accel:");
1451                 stuff_float(&sip->afterburner_forward_accel);
1452
1453                 required_string("+Aburn Fuel:");
1454                 stuff_float(&sip->afterburner_fuel_capacity);
1455
1456                 required_string("+Aburn Burn Rate:");
1457                 stuff_float(&sip->afterburner_burn_rate);
1458
1459
1460                 required_string("+Aburn Rec Rate:");
1461                 stuff_float(&sip->afterburner_recover_rate);
1462         } else {
1463                 sip->afterburner_max_vel.xyz.x = 0.0f;
1464                 sip->afterburner_max_vel.xyz.y = 0.0f;
1465                 sip->afterburner_max_vel.xyz.z = 0.0f;
1466         }
1467
1468         required_string("$Countermeasures:");
1469         stuff_int(&sip->cmeasure_max);
1470
1471         required_string("$Scan time:");
1472         stuff_int(&sip->scan_time);
1473
1474         required_string("$EngineSnd:");
1475         stuff_int(&sip->engine_snd);
1476
1477         required_string("$Closeup_pos:");
1478         stuff_vector(&sip->closeup_pos);
1479
1480         required_string("$Closeup_zoom:");
1481         stuff_float(&sip->closeup_zoom);
1482
1483         sip->shield_icon_index = 255;           // stored as ubyte
1484         if (optional_string("$Shield_icon:")) {
1485                 char tmpbuf[NAME_LENGTH];
1486                 stuff_string(tmpbuf, F_NAME, NULL);
1487                 hud_shield_assign_info(sip, tmpbuf);
1488         }
1489
1490         // read in filename for icon that is used in ship selection
1491         sip->icon_filename[0] = 0;
1492         if ( optional_string("$Ship_icon:") ) {
1493                 stuff_string(sip->icon_filename, F_NAME, NULL);
1494         }
1495
1496         // read in filename for animation that is used in ship selection
1497         sip->anim_filename[0] = 0;
1498         if ( optional_string("$Ship_anim:") ) {
1499                 stuff_string(sip->anim_filename, F_NAME, NULL);
1500         }
1501
1502         // read in filename for animation that is used in ship selection
1503         sip->overhead_filename[0] = 0;
1504         if ( optional_string("$Ship_overhead:") ) {
1505                 stuff_string(sip->overhead_filename, F_NAME, NULL);
1506         }
1507
1508         sip->score = 0;
1509         if ( optional_string("$Score:") ){
1510                 stuff_int( &sip->score );
1511         }
1512
1513         // if the ship is a stealth ship
1514         if ( optional_string("$Stealth:") ){
1515                 sip->flags |= SIF_STEALTH;
1516         }
1517
1518 #ifndef MAKE_FS1
1519         // parse contrail info
1520         char trail_name[MAX_FILENAME_LEN] = "";
1521         trail_info *ci;
1522         memset(&sip->ct_info, 0, sizeof(trail_info) * MAX_SHIP_CONTRAILS);
1523         sip->ct_count = 0;
1524         while(optional_string("$Trail:")){
1525                 // this means you've reached the max # of contrails for a ship
1526                 SDL_assert(sip->ct_count <= MAX_SHIP_CONTRAILS);
1527
1528                 ci = &sip->ct_info[sip->ct_count++];
1529                 
1530                 required_string("+Offset:");
1531                 stuff_vector(&ci->pt);
1532                 
1533                 required_string("+Start Width:");
1534                 stuff_float(&ci->w_start);
1535                 
1536                 required_string("+End Width:");
1537                 stuff_float(&ci->w_end);
1538                 
1539                 required_string("+Start Alpha:");
1540                 stuff_float(&ci->a_start);
1541                 
1542                 required_string("+End Alpha:");
1543                 stuff_float(&ci->a_end);
1544
1545                 required_string("+Max Life:");
1546                 stuff_float(&ci->max_life);
1547                 
1548                 required_string("+Spew Time:");
1549                 stuff_int(&ci->stamp);          
1550
1551                 required_string("+Bitmap:");
1552                 stuff_string(trail_name, F_NAME, NULL);
1553                 ci->bitmap = bm_load(trail_name);
1554         }
1555 #endif
1556
1557         while (cont_flag) {
1558                 int r = required_string_3("#End", "$Subsystem:", "$Name" );
1559                 switch (r) {
1560                 case 0:
1561                         cont_flag = 0;
1562                         break;
1563                 case 1:
1564                 {
1565                         float   turning_rate;
1566                         float   percentage_of_hits;
1567                         model_subsystem *sp;                    // to append on the ships list of subsystems
1568
1569                         SDL_assert ( n_subsystems < MAX_MODEL_SUBSYSTEMS );
1570                         sp = &subsystems[n_subsystems++];                       // subsystems a local -- when done, we will malloc and copy
1571                         required_string("$Subsystem:");
1572                         stuff_string(sp->subobj_name, F_NAME, ",");
1573                         Mp++;
1574                         stuff_float(&percentage_of_hits);
1575                         stuff_float(&turning_rate);
1576                         hull_percentage_of_hits -= percentage_of_hits;
1577                         sp->max_hits = sip->initial_hull_strength * (percentage_of_hits / 100.0f);
1578                         sp->type = SUBSYSTEM_UNKNOWN;
1579                         // specified as how long to turn 360 degrees in ships.tbl
1580                         if ( turning_rate > 0.0f ){
1581                                 sp->turret_turning_rate = PI2 / turning_rate;           
1582                         } else {
1583                                 sp->turret_turning_rate = 0.0f;         
1584                         }
1585
1586                         for (i=0; i<MAX_PRIMARY_BANKS; i++)
1587                                 sp->primary_banks[i] = -1;
1588                         for (i=0; i<MAX_SECONDARY_BANKS; i++) {
1589                                 sp->secondary_banks[i] = -1;
1590                                 sp->secondary_bank_capacity[i] = 0;
1591                         }
1592
1593                         //      Get default primary bank weapons
1594                         if (optional_string("$Default PBanks:")){
1595                                 stuff_int_list(sp->primary_banks, MAX_PRIMARY_BANKS, WEAPON_LIST_TYPE);
1596                         }
1597
1598                         //      Get default secondary bank weapons
1599                         if (optional_string("$Default SBanks:")){
1600                                 stuff_int_list(sp->secondary_banks, MAX_SECONDARY_BANKS, WEAPON_LIST_TYPE);
1601                         }
1602
1603                         // Get the capacity of each secondary bank
1604                         if (optional_string("$Sbank Capacity:")){
1605                                 stuff_int_list(sp->secondary_bank_capacity, MAX_SECONDARY_BANKS, RAW_INTEGER_TYPE);
1606                         }
1607
1608                         // Get optional engine wake info
1609                         if (optional_string("$Engine Wash:")) {
1610                                 char engine_wash_name[32];
1611                                 stuff_string(engine_wash_name, F_NAME, NULL);
1612                                 // get and set index
1613                                 sp->engine_wash_index = get_engine_wash_index(engine_wash_name);
1614                         } else {
1615                                 sp->engine_wash_index = -1;
1616                         }
1617                                 
1618                         // Get any AWACS info
1619                         sp->awacs_intensity = 0.0f;
1620                         if(optional_string("$AWACS:")){
1621                                 stuff_float(&sp->awacs_intensity);
1622                                 stuff_float(&sp->awacs_radius);
1623                                 sip->flags |= SIF_HAS_AWACS;
1624                         }
1625
1626                         sp->turret_weapon_type = sp->primary_banks[0];  // temporary, will be obsolete later.
1627                         if ( sp->turret_weapon_type < 0 ) {
1628                                 sp->turret_weapon_type = sp->secondary_banks[0];
1629                         }
1630                         sp->model_num = -1;             // init value for later sanity checking!!
1631                 }
1632                 break;
1633                 case 2:
1634                         cont_flag = 0;
1635                         break;
1636                 default:
1637                         Int3(); // Impossible return value from required_string_3.
1638                 }
1639         }       
1640         SDL_assert( hull_percentage_of_hits > 0.0f );           // must be > 0
1641
1642         // when done reading subsystems, malloc and copy the subsystem data to the ship info structure
1643         sip->n_subsystems = n_subsystems;
1644         if ( n_subsystems > 0 ) {
1645                 sip->subsystems = (model_subsystem *)malloc(sizeof(model_subsystem) * n_subsystems );
1646                 SDL_assert( sip->subsystems != NULL );
1647         }
1648         else {
1649                 sip->subsystems = NULL;
1650         }
1651                 
1652         for ( i = 0; i < n_subsystems; i++ ){
1653                 sip->subsystems[i] = subsystems[i];
1654         }
1655
1656         // if we have a ship copy, then check to be sure that our base ship exists
1657         if ( sip->flags & SIF_SHIP_COPY ) {
1658                 int index;
1659
1660                 index = ship_info_base_lookup( Num_ship_types );                // Num_ship_types is our current entry into the array
1661                 if ( index == -1 ) {
1662                         char *p, name[NAME_LENGTH];;
1663
1664                         SDL_strlcpy( name, sip->name, sizeof(name) );
1665                         p = SDL_strchr(name, '#');
1666                         if ( p )
1667                                 *p = '\0';
1668                         Error(LOCATION, "Ship %s is a copy, but base ship %s couldn't be found.", sip->name, name);
1669                 }
1670         }
1671
1672         return rtn;
1673 }
1674
1675 char get_engine_wash_index(char *engine_wash_name)
1676 {
1677         int i;
1678
1679         for (i=0; i<Num_engine_wash_types; i++) {
1680                 if ( 0 == SDL_strcasecmp(engine_wash_name, Engine_wash_info[i].name) ) {
1681                         return (char)i;
1682                 }
1683         }
1684
1685         // not found, so return -1
1686         return -1;
1687 }
1688
1689 void parse_shiptbl()
1690 {
1691         // open localization
1692         lcl_ext_open();
1693         
1694         read_file_text("ships.tbl");
1695         reset_parse();
1696
1697 #ifndef MAKE_FS1
1698         // parse default ship
1699         required_string("#Default Player Ship");
1700         required_string("$Name:");
1701         stuff_string(default_player_ship, F_NAME, NULL, 254);
1702         required_string("#End");
1703 #endif
1704
1705 #ifndef MAKE_FS1
1706         Num_engine_wash_types = 0;
1707 #endif
1708         Num_ship_types = 0;
1709
1710 #ifndef MAKE_FS1
1711         required_string("#Engine Wash Info");
1712         while (required_string_either("#End", "$Name:")) {
1713                 SDL_assert( Num_engine_wash_types < MAX_ENGINE_WASH_TYPES );
1714
1715                 parse_engine_wash();
1716                 Num_engine_wash_types++;
1717         }
1718
1719         required_string("#End");
1720 #endif
1721         required_string("#Ship Classes");
1722
1723         while (required_string_either("#End","$Name:")) {
1724                 SDL_assert( Num_ship_types < MAX_SHIP_TYPES );
1725
1726                 if ( parse_ship() ) {
1727                         continue;
1728                 }
1729
1730                 Num_ship_types++;
1731         }
1732
1733         required_string("#End");
1734
1735         // Read in a list of ship_info indicies that are an ordering of the player ship precedence.
1736         // This list is used to select an alternate ship when a particular ship is not available
1737         // during ship selection.
1738         required_string("$Player Ship Precedence:");
1739         Num_player_ship_precedence = stuff_int_list(Player_ship_precedence, MAX_PLAYER_SHIP_CHOICES, SHIP_INFO_TYPE);
1740
1741         // close localization
1742         lcl_ext_close();
1743 }
1744
1745 int ship_show_velocity_dot = 0;
1746
1747
1748 DCF_BOOL( show_velocity_dot, ship_show_velocity_dot )
1749
1750
1751 // Called once at the beginning of the game to parse ships.tbl and stuff the Ship_info[]
1752 // structure
1753 void ship_init()
1754 {
1755         int rval;
1756
1757         if ( !ships_inited ) {
1758                 
1759                 if ((rval = setjmp(parse_abort)) != 0) {
1760                         Error(LOCATION, "Error parsing 'ships.tbl'\r\nError code = %i.\r\n", rval);
1761                 } else {                        
1762                         parse_shiptbl();
1763                         ships_inited = 1;
1764                 }
1765
1766                 ship_iff_init_colors();
1767         }
1768
1769         ship_level_init();      // needed for FRED
1770 }
1771
1772
1773 // This will get called at the start of each level.
1774 void ship_level_init()
1775 {
1776         int i;
1777
1778         // Reset everything between levels
1779
1780
1781         // Mark all the models as invalid, since all the models get paged out 
1782         // between levels.
1783         for (i=0; i<MAX_SHIP_TYPES; i++ )       {
1784                 Ship_info[i].modelnum = -1;
1785                 Ship_info[i].modelnum_hud = -1;
1786         }
1787
1788         // mwa removed 11/24/97  num_ships = 0;
1789         Num_exited_ships = 0;
1790         for (i=0; i<MAX_SHIPS; i++ )    {
1791                 Ships[i].objnum = -1;
1792         }
1793
1794         for ( i = 0; i < MAX_EXITED_SHIPS; i++ ) {
1795                 memset ( &Ships_exited[i], 0, sizeof(exited_ship) );
1796                 Ships_exited[i].obj_signature = -1;
1797         }
1798
1799         num_wings = 0;
1800         for (i = 0; i < MAX_WINGS; i++ )
1801                 Wings[i].num_waves = -1;
1802
1803         for (i=0; i<MAX_PLAYER_WINGS; i++)
1804                 Starting_wings[i] = -1;
1805
1806         // Empty the subsys list
1807         memset( Ship_subsystems, 0, sizeof(ship_subsys)*MAX_SHIP_SUBOBJECTS );
1808
1809         list_init( &ship_subsys_free_list );
1810         for ( i = 0; i < MAX_SHIP_SUBOBJECTS; i++ )
1811                 list_append( &ship_subsys_free_list, &Ship_subsystems[i] );
1812
1813         Laser_energy_out_snd_timer = 1;
1814         Missile_out_snd_timer           = 1;
1815
1816         for (i = 0; i < MAX_SHIP_TYPE_COUNTS; i++ ) {
1817                 Ship_counts[i].total = 0;
1818                 Ship_counts[i].killed = 0;
1819         }
1820
1821         ship_obj_list_init();
1822
1823         Ship_cargo_check_timer = 1;
1824
1825         shipfx_large_blowup_level_init();
1826 }
1827
1828 // function to add a ship onto the exited ships list.  The reason parameter
1829 // tells us why the ship left the mission (i.e. departed or destroyed)
1830 void ship_add_exited_ship( ship *sp, int reason )
1831 {
1832         int i, entry;
1833
1834         // reuse oldest slots if none left
1835         if ( Num_exited_ships == MAX_EXITED_SHIPS ) {
1836                 int oldest_entry;
1837
1838                 // find the oldest entry
1839                 oldest_entry = 0;
1840                 for ( i = 1; i < MAX_SHIPS; i++ ) {
1841                         if ( Ships_exited[i].time < Ships_exited[oldest_entry].time ) {
1842                                 oldest_entry = i;
1843                         }
1844                 }
1845                 entry = oldest_entry;
1846         } else {
1847                 entry = Num_exited_ships;
1848                 Num_exited_ships++;
1849         }
1850
1851         SDL_strlcpy( Ships_exited[entry].ship_name, sp->ship_name, sizeof(Ships_exited[0].ship_name) );
1852         Ships_exited[entry].obj_signature = Objects[sp->objnum].signature;
1853         Ships_exited[entry].team = sp->team;
1854         Ships_exited[entry].flags = reason;
1855         // if ship is red alert, flag as such
1856         if (sp->flags & SF_RED_ALERT_STORE_STATUS) {
1857                 Ships_exited[entry].flags |= SEF_RED_ALERT_CARRY;
1858         }
1859         Ships_exited[entry].time = Missiontime;
1860         Ships_exited[entry].hull_strength = int(Objects[sp->objnum].hull_strength);
1861
1862         if ( sp->flags & SF_CARGO_REVEALED )
1863                 Ships_exited[entry].flags |= SEF_CARGO_KNOWN;
1864         if ( sp->time_first_tagged > 0 )
1865                 Ships_exited[entry].flags |= SEF_BEEN_TAGGED;
1866 }
1867
1868 // function which attempts to find information about an exited ship based on shipname
1869 int ship_find_exited_ship_by_name( const char *name )
1870 {
1871         int i;
1872
1873         for (i = 0; i < Num_exited_ships; i++) {
1874                 if ( !SDL_strcasecmp(name, Ships_exited[i].ship_name) )
1875                         break;
1876         }
1877
1878         if ( i == Num_exited_ships )
1879                 return -1;
1880         else
1881                 return i;
1882 }
1883
1884 // function which attempts to find information about an exited ship based on shipname
1885 int ship_find_exited_ship_by_signature( int signature )
1886 {
1887         int i;
1888
1889         for (i = 0; i < Num_exited_ships; i++) {
1890                 if ( signature == Ships_exited[i].obj_signature )
1891                         break;
1892         }
1893
1894         if ( i == Num_exited_ships )
1895                 return -1;
1896         else
1897                 return i;
1898 }
1899
1900
1901 void physics_ship_init(object *objp)
1902 {
1903         ship_info       *sinfo = &Ship_info[Ships[objp->instance].ship_info_index];
1904         physics_info    *pi = &objp->phys_info;
1905         polymodel *pm = model_get( Ships[objp->instance].modelnum );
1906
1907         // use mass and I_body_inv from POF read into polymodel
1908         physics_init(pi);
1909         pi->mass = pm->mass * sinfo->density;
1910         pi->I_body_inv = pm->moment_of_inertia;
1911         // scale pm->I_body_inv value by density
1912         vm_vec_scale( &pi->I_body_inv.v.rvec, sinfo->density );
1913         vm_vec_scale( &pi->I_body_inv.v.uvec, sinfo->density );
1914         vm_vec_scale( &pi->I_body_inv.v.fvec, sinfo->density );
1915
1916         pi->side_slip_time_const = sinfo->damp;
1917         pi->rotdamp = sinfo->rotdamp;
1918         pi->max_vel = sinfo->max_vel;
1919         pi->afterburner_max_vel = sinfo->afterburner_max_vel;
1920         pi->max_rotvel = sinfo->max_rotvel;
1921         pi->max_rear_vel = sinfo->max_rear_vel;
1922         pi->flags |= PF_ACCELERATES;
1923
1924
1925
1926
1927         pi->forward_accel_time_const=sinfo->forward_accel;
1928         pi->afterburner_forward_accel_time_const=sinfo->afterburner_forward_accel;
1929         pi->forward_decel_time_const=sinfo->forward_decel;
1930         pi->slide_accel_time_const=sinfo->slide_accel;
1931         pi->slide_decel_time_const=sinfo->slide_decel;
1932
1933         if ( (pi->max_vel.xyz.x > 0.000001f) || (pi->max_vel.xyz.y > 0.000001f) )
1934                 pi->flags |= PF_SLIDE_ENABLED;
1935
1936         vm_vec_zero(&pi->vel);
1937         vm_vec_zero(&pi->rotvel);
1938         pi->speed = 0.0f;
1939         pi->heading = 0.0f;
1940 //      pi->accel = 0.0f;
1941         vm_set_identity(&pi->last_rotmat);
1942 }
1943
1944 // function to set the orders allowed for a ship -- based on ship type.  This value might get overridden
1945 // by a value in the mission file.
1946 int ship_get_default_orders_accepted( ship_info *sip )
1947 {
1948         int ship_info_flag;
1949
1950         ship_info_flag = sip->flags;
1951
1952         if ( ship_info_flag & SIF_FIGHTER )
1953                 return FIGHTER_MESSAGES;
1954         else if ( ship_info_flag & SIF_BOMBER )
1955                 return BOMBER_MESSAGES;
1956         else if ( ship_info_flag & (SIF_CRUISER | SIF_GAS_MINER | SIF_AWACS | SIF_CORVETTE) )
1957                 return CRUISER_MESSAGES;
1958         else if ( ship_info_flag & SIF_FREIGHTER )
1959                 return FREIGHTER_MESSAGES;
1960         else if ( ship_info_flag & SIF_CAPITAL )
1961                 return CAPITAL_MESSAGES;
1962         else if ( ship_info_flag & SIF_TRANSPORT )
1963                 return TRANSPORT_MESSAGES;
1964         else if ( ship_info_flag & SIF_SUPPORT )
1965                 return SUPPORT_MESSAGES;
1966         else
1967                 return 0;
1968 }
1969
1970 void ship_set(int ship_index, int objnum, int ship_type)
1971 {
1972         int i;
1973
1974         object  *objp = &Objects[objnum];
1975         ship    *shipp = &Ships[ship_index];
1976         ship_weapon     *swp = &shipp->weapons;
1977         ship_info       *sip = &(Ship_info[ship_type]);
1978
1979         // Create n!
1980         // sprintf(shipp->ship_name, "%s %d", Ship_info[ship_type].name, ship_index); // moved to ship_create()
1981         SDL_assert(strlen(shipp->ship_name) < NAME_LENGTH - 1);
1982         shipp->ship_info_index = ship_type;
1983         shipp->objnum = objnum;
1984         shipp->group = 0;
1985         shipp->reinforcement_index = -1;
1986         shipp->cargo1 = 0;
1987         shipp->hotkey = -1;
1988         shipp->score = 0;
1989         shipp->escort_priority = 0;
1990         shipp->special_exp_index = -1;
1991         shipp->num_hits = 0;
1992         shipp->flags = 0;
1993         shipp->wash_killed = 0;
1994         shipp->time_cargo_revealed = 0;
1995         shipp->time_first_tagged = 0;
1996         shipp->wash_timestamp = timestamp(0);
1997         shipp->dock_objnum_when_dead = -1;
1998         shipp->large_ship_blowup_index = -1;
1999         shipp->respawn_priority = 0;
2000         for (i=0; i<NUM_SUB_EXPL_HANDLES; i++) {
2001                 shipp->sub_expl_sound_handle[i] = -1;
2002         }
2003
2004         if ( !Fred_running ) {
2005                 shipp->final_warp_time = timestamp(-1);
2006                 shipp->final_death_time = timestamp(-1);        // There death sequence ain't start et.
2007                 shipp->really_final_death_time = timestamp(-1); // There death sequence ain't start et.
2008                 shipp->next_fireball = timestamp(-1);           // When a random fireball will pop up
2009                 shipp->next_hit_spark = timestamp(-1);          // when a hit spot will spark
2010                 for (i=0; i<MAX_SHIP_ARCS; i++ )        {
2011                         shipp->arc_timestamp[i] = timestamp(-1);                // Mark this arc as unused
2012                 }
2013                 shipp->arc_next_time = timestamp(-1);           // No electrical arcs yet.
2014         } else {                // the values should be different for Fred
2015                 shipp->final_warp_time = -1;
2016                 shipp->final_death_time = 0;
2017                 shipp->really_final_death_time = -1;
2018                 shipp->next_fireball = -1;
2019                 shipp->next_hit_spark = -1;
2020                 for (i=0; i<MAX_SHIP_ARCS; i++ )        {
2021                         shipp->arc_timestamp[i] = -1;
2022                 }
2023                 shipp->arc_next_time = -1;
2024         }
2025         shipp->team = TEAM_FRIENDLY;                                    //      Default friendly, probably get overridden.
2026         shipp->arrival_location = 0;
2027         shipp->arrival_distance = 0;
2028         shipp->arrival_anchor = -1;
2029         shipp->arrival_delay = 0;
2030         shipp->arrival_cue = -1;
2031         shipp->departure_location = 0;
2032         shipp->departure_delay = 0;
2033         shipp->departure_cue = -1;
2034         shipp->shield_hits = 0;                                                 //      No shield hits yet on this baby.
2035         shipp->current_max_speed = Ship_info[ship_type].max_speed;
2036
2037         shipp->alt_type_index = -1;
2038
2039         shipp->lightning_stamp = -1;
2040
2041         shipp->emp_intensity = -1.0f;
2042         shipp->emp_decr = 0.0f;
2043
2044         shipp->targeting_laser_bank = -1;
2045         shipp->targeting_laser_objnum = -1;
2046
2047         shipp->determination = 10;
2048         shipp->wingnum = -1;
2049         for (i = 0; i < MAX_PLAYERS; i++)
2050                 shipp->last_targeted_subobject[i] = NULL;
2051
2052         if (Fred_running){
2053                 objp->hull_strength = 100.0f;
2054         } else {
2055                 objp->hull_strength = sip->initial_hull_strength;
2056         }
2057         
2058         shipp->afterburner_fuel = sip->afterburner_fuel_capacity;
2059
2060         shipp->cmeasure_count = sip->cmeasure_max;
2061
2062         for ( i = 0; i < MAX_PRIMARY_BANKS; i++ ){
2063                 swp->next_primary_fire_stamp[i] = timestamp(0);         
2064         }
2065
2066         shipp->cmeasure_fire_stamp = timestamp(0);
2067
2068         for ( i = 0; i < MAX_SECONDARY_BANKS; i++ ) {
2069                 if (Fred_running){
2070                         shipp->weapons.secondary_bank_ammo[i] = 100;
2071                 } else {
2072                         shipp->weapons.secondary_bank_ammo[i] = 0;
2073                 }
2074                         
2075                 swp->secondary_bank_ammo[i] = 0;
2076                 swp->secondary_next_slot[i] = 0;
2077                 swp->next_secondary_fire_stamp[i] = timestamp(0);
2078                 swp->secondary_bank_rearm_time[i] = timestamp(0);               // will be able to rearm this bank immediately
2079         }
2080
2081         for ( i = 0; i < sip->num_secondary_banks; i++ ) {
2082                 float weapon_size;
2083                 weapon_size = Weapon_info[sip->secondary_bank_weapons[i]].cargo_size;
2084                 SDL_assert( weapon_size > 0.0f );
2085                 if (Fred_running){
2086                         swp->secondary_bank_ammo[i] = 100;
2087                 } else {
2088                         swp->secondary_bank_ammo[i] = fl2i(sip->secondary_bank_ammo_capacity[i] / weapon_size + 0.5f );
2089                 }
2090         }
2091
2092         swp->current_primary_bank = -1;
2093         swp->current_secondary_bank = -1;
2094
2095
2096         if ( sip->num_primary_banks > 0 ) {
2097                 if ( swp->primary_bank_weapons[BANK_1] >= 0 ) {
2098                         swp->current_primary_bank = BANK_1;
2099                 } else {
2100                         swp->current_primary_bank = -1;
2101                 }
2102         }
2103         else {
2104                 swp->current_primary_bank = -1;
2105         }
2106
2107         if ( sip->num_secondary_banks > 0 ) {
2108                 if ( swp->secondary_bank_weapons[BANK_1] >= 0 ) {
2109                         swp->current_secondary_bank = BANK_1;
2110                 } else {
2111                         swp->current_secondary_bank = -1;
2112                 }
2113         }
2114         else {
2115                 swp->current_secondary_bank = -1;
2116         }
2117
2118         shipp->current_cmeasure = 0;
2119
2120         ets_init_ship(objp);    // init ship fields that are used for the ETS
2121
2122         physics_ship_init(objp);
2123         if (Fred_running)
2124                 objp->shields[0] = 100.0f;
2125         else
2126                 set_shield_strength(objp, sip->shields);
2127
2128         shipp->target_shields_delta = 0.0f;
2129         shipp->target_weapon_energy_delta = 0.0f;
2130
2131         ai_object_init(objp, shipp->ai_index);
2132         shipp->weapons.ai_class = Ai_info[shipp->ai_index].ai_class;
2133         shipp->shield_integrity = NULL;
2134 //      shipp->sw.blast_duration = -1;  // init shockwave struct
2135         subsys_set(objnum);
2136         shipp->orders_accepted = ship_get_default_orders_accepted( sip );
2137         shipp->num_swarm_missiles_to_fire = 0;  
2138         shipp->num_turret_swarm_info = 0;
2139         shipp->death_roll_snd = -1;
2140         shipp->thruster_bitmap = -1;
2141         shipp->thruster_frame = 0.0f;
2142         shipp->thruster_glow_bitmap = -1;
2143         shipp->thruster_glow_noise = 1.0f;
2144         shipp->thruster_glow_frame = 0.0f;
2145         shipp->next_engine_stutter = 1;
2146         shipp->persona_index = -1;
2147         shipp->flags |= SF_ENGINES_ON;
2148         shipp->subsys_disrupted_flags=0;
2149         shipp->subsys_disrupted_check_timestamp=timestamp(0);
2150
2151         // swarm missile stuff
2152         shipp->next_swarm_fire = 1;
2153
2154         // corkscrew missile stuff
2155         shipp->next_corkscrew_fire = 1;
2156
2157         // field for score
2158         shipp->score = sip->score;
2159
2160         // tag
2161         shipp->tag_left = -1.0f;
2162         shipp->level2_tag_left = -1.0f;
2163
2164         // multiplayer field initializations
2165         for (i = 0; i < MAX_PLAYERS; i++ ) {
2166                 shipp->np_updates[i].update_stamp = -1;
2167                 shipp->np_updates[i].status_update_stamp = -1;
2168                 shipp->np_updates[i].subsys_update_stamp = -1;
2169                 shipp->np_updates[i].seq = 0;           
2170         }               
2171         extern int oo_arrive_time_count[MAX_SHIPS];             
2172         extern int oo_interp_count[MAX_SHIPS];  
2173         oo_arrive_time_count[shipp - Ships] = 0;                                
2174         oo_interp_count[shipp - Ships] = 0;     
2175
2176         shipp->special_warp_objnum = -1;
2177
2178         // set awacs warning flags so awacs ship only asks for help once at each level
2179         shipp->awacs_warning_flag = AWACS_WARN_NONE;
2180 }
2181
2182 // function which recalculates the overall strength of subsystems.  Needed because
2183 // several places in FreeSpace change subsystem strength and all this data needs to
2184 // be kept up to date.
2185 void ship_recalc_subsys_strength( ship *shipp )
2186 {
2187         int i;
2188         ship_subsys *ship_system;
2189
2190         // fill in the subsys_info fields for all particular types of subsystems
2191         // make the current strength be 1.0.  If there are initial conditions on the ship, then
2192         // the mission parse code should take care of setting that.
2193         for (i = 0; i < SUBSYSTEM_MAX; i++) {
2194                 shipp->subsys_info[i].num = 0;
2195                 shipp->subsys_info[i].total_hits = 0.0f;
2196                 shipp->subsys_info[i].current_hits = 0.0f;
2197         }
2198
2199         // count all of the subsystems of a particular type.  For each generic type of subsystem, we store the
2200         // total count of hits.  (i.e. for 3 engines, we store the sum of the max_hits for each engine)
2201         for ( ship_system = GET_FIRST(&shipp->subsys_list); ship_system != END_OF_LIST(&shipp->subsys_list); ship_system = GET_NEXT(ship_system) ) {
2202                 int type;
2203
2204                 type = ship_system->system_info->type;
2205                 SDL_assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
2206                 shipp->subsys_info[type].num++;
2207                 shipp->subsys_info[type].total_hits += ship_system->system_info->max_hits;
2208                 shipp->subsys_info[type].current_hits += ship_system->current_hits;
2209         }
2210
2211         // set any ship flags which should be set.  unset the flags since we might be repairing a subsystem
2212         // through sexpressions.
2213         shipp->flags &= ~SF_DISABLED;
2214         if ( (shipp->subsys_info[SUBSYSTEM_ENGINE].num > 0) && (shipp->subsys_info[SUBSYSTEM_ENGINE].current_hits == 0.0f) ){
2215                 shipp->flags |= SF_DISABLED;
2216         }
2217
2218         /*
2219         shipp->flags &= ~SF_DISARMED;
2220         if ( (shipp->subsys_info[SUBSYSTEM_TURRET].num > 0) && (shipp->subsys_info[SUBSYSTEM_TURRET].current_hits == 0.0f) ){
2221                 shipp->flags |= SF_DISARMED;
2222         }
2223         */
2224 }
2225
2226 // routine to possibly fixup the model subsystem information for this ship pointer.  Needed when
2227 // ships share the same model.
2228 void ship_copy_subsystem_fixup(ship_info *sip)
2229 {
2230         int i, model_num;
2231
2232         model_num = sip->modelnum;
2233
2234         // since we allow a model file to be shared between several ships, we must check to be sure that our
2235         // subsystems have been loaded properly
2236         /*
2237         subsystems_needed = 0;
2238         for (i = 0; i < sip->n_subsystems; i++ ) {
2239                 if ( sip->subsystems[i].model_num == -1 ){
2240                         subsystems_needed++;
2241                 }
2242         }
2243         */
2244
2245         // if we need to get information for all our subsystems, we need to find another ship with the same model
2246         // number as our own and that has the model information
2247         // if ( subsystems_needed == sip->n_subsystems ) {
2248                 for ( i = 0; i < Num_ship_types; i++ ) {
2249                         model_subsystem *msp;
2250
2251                         if ( (Ship_info[i].modelnum != model_num) || (&Ship_info[i] == sip) ){
2252                                 continue;
2253                         }
2254
2255                         // see if this ship has subsystems and a model for the subsystems.  We only need check the first
2256                         // subsystem since previous error checking would have trapped it's loading as an error.
2257                         SDL_assert( Ship_info[i].n_subsystems == sip->n_subsystems );
2258
2259                         msp = &Ship_info[i].subsystems[0];
2260                         model_copy_subsystems( sip->n_subsystems, &(sip->subsystems[0]), msp );
2261                         sip->flags |= SIF_PATH_FIXUP;
2262                         break;
2263                 }
2264         // }
2265
2266 }
2267
2268
2269 // ignore_subsys_info => default parameter with value of 0.  This is
2270 //                                                               only set to 1 by the save/restore code
2271 void subsys_set(int objnum, int ignore_subsys_info)
2272 {       
2273         ship    *shipp = &Ships[Objects[objnum].instance];
2274         ship_info       *sinfo = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
2275         model_subsystem *sp;
2276         ship_subsys *ship_system;
2277         int i, j, k;
2278
2279         // set up the subsystems for this ship.  walk through list of subsystems in the ship-info array.
2280         // for each subsystem, get a new ship_subsys instance and set up the pointers and other values
2281         list_init ( &shipp->subsys_list );                                                              // initialize the ship's list of subsystems
2282         for ( i = 0; i < sinfo->n_subsystems; i++ ) {
2283
2284                 sp = &(sinfo->subsystems[i]);
2285                 if ( sp->model_num == -1 ) {
2286                         Warning (LOCATION, "Invalid subobj_num or model_num in subsystem %s on ship type %s.\nNot linking into ship!\n\n(This warning means that a subsystem was present in ships.tbl and not present in the model\nit should probably be removed from the model.)\n", sp->subobj_name, sinfo->name );
2287                         continue;
2288                 }
2289
2290                 // set up the linked list
2291                 ship_system = GET_FIRST( &ship_subsys_free_list );              // get a new element from the ship_subsystem array
2292                 SDL_assert ( ship_system != &ship_subsys_free_list );           // shouldn't have the dummy element
2293                 list_remove( &ship_subsys_free_list, ship_system );     // remove the element from the array
2294                 list_append( &shipp->subsys_list, ship_system );                // link the element into the ship
2295
2296                 ship_system->system_info = sp;                                          // set the system_info pointer to point to the data read in from the model
2297                 if ( !Fred_running ){
2298                         ship_system->current_hits = sp->max_hits;               // set the max hits 
2299                 } else {
2300                         ship_system->current_hits = 0.0f;                               // Jason wants this to be 0 in Fred.
2301                 }
2302                 ship_system->turret_next_fire_stamp = timestamp(0);
2303                 ship_system->turret_next_enemy_check_stamp = timestamp(0);
2304                 ship_system->turret_enemy_objnum = -1;
2305                 ship_system->turret_next_fire_stamp = timestamp((int) frand_range(1.0f, 500.0f));       // next time this turret can fire
2306                 ship_system->turret_last_fire_direction = sp->turret_norm;
2307                 ship_system->turret_next_fire_pos = 0;
2308                 ship_system->turret_time_enemy_in_range = 0.0f;
2309                 ship_system->disruption_timestamp=timestamp(0);
2310                 ship_system->turret_pick_big_attack_point_timestamp = timestamp(0);
2311                 vm_vec_zero(&ship_system->turret_big_attack_point);
2312                 ship_system->subsys_cargo_name = -1;
2313                 ship_system->subsys_cargo_revealed = 0;
2314                 
2315                 // zero flags
2316                 ship_system->weapons.flags = 0;
2317
2318                 j = 0;
2319                 for (k=0; k<MAX_PRIMARY_BANKS; k++){
2320                         if (sp->primary_banks[k] != -1) {
2321                                 ship_system->weapons.primary_bank_weapons[j] = sp->primary_banks[k];
2322                                 ship_system->weapons.next_primary_fire_stamp[j++] = 0;
2323                         }
2324                 }
2325
2326                 ship_system->weapons.num_primary_banks = j;
2327
2328                 j = 0;
2329                 for (k=0; k<MAX_SECONDARY_BANKS; k++){
2330                         if (sp->secondary_banks[k] != -1) {
2331                                 ship_system->weapons.secondary_bank_weapons[j] = sp->secondary_banks[k];
2332                                 ship_system->weapons.secondary_bank_capacity[j] = sp->secondary_bank_capacity[k];
2333                                 ship_system->weapons.next_secondary_fire_stamp[j++] = timestamp(0);
2334                         }
2335                 }
2336
2337                 ship_system->weapons.num_secondary_banks = j;
2338                 ship_system->weapons.current_primary_bank = -1;
2339                 ship_system->weapons.current_secondary_bank = -1;
2340                 
2341                 for (k=0; k<MAX_SECONDARY_BANKS; k++) {
2342                         ship_system->weapons.secondary_bank_ammo[k] = (Fred_running ? 100 : ship_system->weapons.secondary_bank_capacity[k]);
2343
2344                         ship_system->weapons.secondary_next_slot[k] = 0;
2345                 }
2346
2347                 ship_system->weapons.last_fired_weapon_index = -1;
2348                 ship_system->weapons.last_fired_weapon_signature = -1;
2349                 ship_system->weapons.detonate_weapon_time = -1;
2350                 ship_system->weapons.ai_class = sinfo->ai_class;  // assume ai class of ship for turret
2351
2352                 // rapid fire (swarm) stuff
2353                 ship_system->turret_swarm_info_index = -1;
2354
2355                 // AWACS stuff
2356                 ship_system->awacs_intensity = sp->awacs_intensity;
2357                 ship_system->awacs_radius = sp->awacs_radius;
2358                 if (ship_system->awacs_intensity > 0) {
2359                         ship_system->system_info->flags |= MSS_FLAG_AWACS;
2360                 }
2361
2362                 // turn_rate, turn_accel
2363                 // model_set_instance_info
2364                 float turn_accel = 0.5f;
2365                 model_set_instance_info(&ship_system->submodel_info_1, sp->turn_rate, turn_accel);
2366
2367                 // model_clear_instance_info( &ship_system->submodel_info_1 );
2368                 model_clear_instance_info( &ship_system->submodel_info_2 );
2369         }
2370
2371         if ( !ignore_subsys_info ) {
2372                 ship_recalc_subsys_strength( shipp );
2373         }
2374 }
2375
2376
2377 #ifndef NDEBUG
2378
2379 //      Render docking information, NOT while in object's reference frame.
2380 void render_dock_bays(object *objp)
2381 {
2382         ship_info       *sip;
2383         polymodel       *pm;
2384         dock_bay                *db;
2385
2386         sip = &Ship_info[Ships[objp->instance].ship_info_index];
2387         pm = model_get( sip->modelnum );
2388
2389         if (pm->docking_bays == NULL)
2390                 return;
2391
2392         if (pm->docking_bays[0].num_slots != 2)
2393                 return;
2394
2395         db = &pm->docking_bays[0];
2396
2397         vertex  v0, v1;
2398         vector  p0, p1, p2, p3, nr;
2399
2400         vm_vec_unrotate(&p0, &db->pnt[0], &objp->orient);
2401         vm_vec_add2(&p0, &objp->pos);
2402         g3_rotate_vertex(&v0, &p0);
2403
2404         vm_vec_unrotate(&p1, &db->pnt[1], &objp->orient);
2405         vm_vec_add2(&p1, &objp->pos);
2406         g3_rotate_vertex(&v1, &p1);
2407
2408         gr_set_color(255, 0, 0);
2409         g3_draw_line(&v0, &v1);
2410
2411         vm_vec_avg(&p2, &p0, &p1);
2412
2413         vm_vec_unrotate(&nr, &db->norm[0], &objp->orient);
2414         vm_vec_scale_add(&p3, &p2, &nr, 10.0f);
2415
2416         g3_rotate_vertex(&v0, &p2);
2417         g3_rotate_vertex(&v1, &p3);
2418         gr_set_color(255, 255, 0);
2419         g3_draw_line(&v0, &v1);
2420         g3_draw_sphere(&v1, 1.25f);
2421
2422 }
2423
2424 #endif
2425
2426 int Ship_shadows = 0;
2427
2428 DCF_BOOL( ship_shadows, Ship_shadows );
2429
2430 MONITOR( NumShipsRend );        
2431
2432 int Show_shield_hits = 0;
2433 DCF_BOOL( show_shield_hits, Show_shield_hits );
2434
2435 int Show_tnorms = 0;
2436 DCF_BOOL( show_tnorms, Show_tnorms );
2437
2438 int Show_paths = 0;
2439 DCF_BOOL( show_paths, Show_paths );
2440
2441 int Show_fpaths = 0;
2442 DCF_BOOL( show_fpaths, Show_fpaths );
2443
2444 void ship_render(object * obj)
2445 {
2446         int num;
2447         ship_info * si;
2448         ship * shipp;
2449
2450         num = obj->instance;
2451
2452         SDL_assert( num >= 0);  
2453
2454 #if 0
2455         // show target when attacking big ship
2456         vector temp, target;
2457         ai_info *aip = &Ai_info[Ships[obj->instance].ai_index];
2458         if ( (aip->target_objnum >= 0)  && (Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].flags & (SIF_SUPERCAP|SIF_CAPITAL|SIF_CRUISER)) ) {
2459                 vm_vec_unrotate(&temp, &aip->big_attack_point, &Objects[aip->target_objnum].orient);
2460                 vm_vec_add(&target, &temp, &Objects[aip->target_objnum].pos);
2461
2462                 vertex v0, v1;
2463                 gr_set_color(128,0,0);
2464                 g3_rotate_vertex( &v0, &obj->pos );
2465                 g3_rotate_vertex( &v1, &target );
2466
2467                 g3_draw_line(&v0, &v1);
2468
2469                 g3_draw_sphere(&v1, 5.0f);
2470         }
2471 #endif
2472
2473
2474 //      if (Ships[num].subtype == SHIP_PLAYER ) return; 
2475         if ( obj == Viewer_obj ) {
2476                 if (ship_show_velocity_dot && (obj==Player_obj) )       {
2477                         vector p0,v;
2478                         vertex v0;
2479
2480                         vm_vec_scale_add( &v, &obj->phys_info.vel, &obj->orient.v.fvec, 3.0f );
2481                         vm_vec_normalize( &v );
2482                         
2483                                         
2484                         vm_vec_scale_add( &p0, &obj->pos, &v, 20.0f);
2485
2486                         g3_rotate_vertex( &v0, &p0 );
2487                         
2488                         gr_set_color(0,128,0);
2489                         g3_draw_sphere( &v0, 0.1f );
2490                 }
2491
2492                 // Show the shield hit effect for the viewer.
2493                 if ( Show_shield_hits ) {
2494                         shipp = &Ships[num];
2495                         if (shipp->shield_hits) {
2496                                 create_shield_explosion_all(obj);
2497                                 shipp->shield_hits = 0;
2498                         }
2499                 }               
2500
2501                 return;
2502         }
2503
2504         MONITOR_INC( NumShipsRend, 1 ); 
2505
2506         shipp = &Ships[num];
2507         si = &Ship_info[Ships[num].ship_info_index];
2508
2509         // Make ships that are warping in not render during stage 1
2510         if ( shipp->flags & SF_ARRIVING_STAGE_1 ){                              
2511                 return;
2512         }
2513
2514         if ( Ship_shadows && shipfx_in_shadow( obj ) )  {
2515                 light_set_shadow(1);
2516         } else {
2517                 light_set_shadow(0);
2518         }
2519
2520         ship_model_start(obj);
2521
2522         uint render_flags = MR_NORMAL;
2523
2524         // Turn off model caching for the player ship in external view.
2525         if (obj == Player_obj)  {
2526                 render_flags |= MR_ALWAYS_REDRAW;       
2527         }
2528
2529         // Turn off model caching if this is the player's target.
2530         if ( Player_ai->target_objnum == OBJ_INDEX(obj))        {
2531                 render_flags |= MR_ALWAYS_REDRAW;       
2532         }       
2533
2534 #ifndef NDEBUG
2535         if(Show_paths || Show_fpaths){
2536                 render_flags |= MR_BAY_PATHS;
2537         }
2538 #endif
2539
2540         // Only render electrical arcs if within 500m of the eye (for a 10m piece)
2541         if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f )        {
2542                 int i;
2543                 for (i=0; i<MAX_SHIP_ARCS; i++ )        {
2544                         if ( timestamp_valid( shipp->arc_timestamp[i] ) )       {
2545                                 render_flags |= MR_ALWAYS_REDRAW;       // Turn off model caching if arcing.
2546                                 model_add_arc( shipp->modelnum, -1, &shipp->arc_pts[i][0], &shipp->arc_pts[i][1], shipp->arc_type[i] );
2547                         }
2548                 }
2549         }
2550
2551         if ( shipp->large_ship_blowup_index > -1 )      {
2552                 shipfx_large_blowup_render(shipp);
2553         } else {
2554
2555                 //      ship_get_subsystem_strength( shipp, SUBSYSTEM_ENGINE)>ENGINE_MIN_STR
2556
2557                 if ( (shipp->thruster_bitmap > -1) && (!(shipp->flags & SF_DISABLED)) && (!ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE)) ) {
2558                         float   ft;
2559
2560                         //      Add noise to thruster geometry.
2561                         ft = obj->phys_info.forward_thrust;
2562                         ft *= (1.0f + frand()/5.0f - 1.0f/10.0f);
2563                         if (ft > 1.0f)
2564                                 ft = 1.0f;
2565
2566                         model_set_thrust( shipp->modelnum, ft, shipp->thruster_bitmap, shipp->thruster_glow_bitmap, shipp->thruster_glow_noise );
2567                         render_flags |= MR_SHOW_THRUSTERS;
2568                 }
2569
2570                 // fill the model flash lighting values in
2571                 shipfx_flash_light_model( obj, shipp );
2572
2573                 object *docked_objp = NULL;
2574                 ship * docked_shipp = NULL;
2575                 ship * warp_shipp = shipp;
2576                          
2577                 // check to see if departing ship is docked with anything.
2578                 docked_objp = ai_find_docked_object( obj );
2579                 if ( docked_objp ) {
2580                         docked_shipp = &Ships[docked_objp->instance];
2581
2582                         if ( docked_shipp->flags & (SF_DEPART_WARP|SF_ARRIVING) )       {
2583                                 warp_shipp = docked_shipp;
2584                         }
2585                 }
2586
2587                 // Warp_shipp points to the ship that is going through a
2588                 // warp... either this ship or the ship it is docked with.
2589                 
2590                 // If the ship is going "through" the warp effect, then
2591                 // set up the model renderer to only draw the polygons in front
2592                 // of the warp in effect
2593                 int clip_started = 0;
2594
2595                 if ( warp_shipp->flags & (SF_ARRIVING|SF_DEPART_WARP) ) {
2596
2597                         clip_started = 1;
2598                         g3_start_user_clip_plane( &warp_shipp->warp_effect_pos, &warp_shipp->warp_effect_fvec );
2599
2600                         // Turn off model caching while going thru warp effect.
2601                         render_flags |= MR_ALWAYS_REDRAW;       
2602                 }
2603
2604                 // maybe set squad logo bitmap
2605                 model_set_insignia_bitmap(-1);
2606                 if(Game_mode & GM_MULTIPLAYER){
2607                         // if its any player's object
2608                         int np_index = multi_find_player_by_object( obj );
2609                         if((np_index >= 0) && (np_index < MAX_PLAYERS) && MULTI_CONNECTED(Net_players[np_index]) && (Net_players[np_index].player != NULL)){
2610                                 model_set_insignia_bitmap(Net_players[np_index].player->insignia_texture);
2611                         }
2612                 }
2613                 // in single player, we want to render model insignias on all ships in alpha beta and gamma
2614                 else {                  
2615                         // if its an object in my squadron
2616                         if(ship_in_abgz(shipp)){
2617                                 model_set_insignia_bitmap(Player->insignia_texture);
2618                         }
2619                 }
2620
2621                 // maybe disable lighting
2622                 // if((The_mission.flags & MISSION_FLAG_FULLNEB) && (neb2_get_fog_intensity(obj) > 0.33f) && (si->flags & SIF_SMALL_SHIP)){
2623                         // render_flags |= MR_NO_LIGHTING;
2624                 // }
2625
2626                 // nebula               
2627                 if(The_mission.flags & MISSION_FLAG_FULLNEB){           
2628                         extern void model_set_fog_level(float l);
2629                         model_set_fog_level(neb2_get_fog_intensity(obj));
2630                 }
2631
2632                 // small ships
2633                 if((The_mission.flags & MISSION_FLAG_FULLNEB) && (si->flags & SIF_SMALL_SHIP)){                 
2634                         // force detail levels
2635                         float fog_val = neb2_get_fog_intensity(obj);
2636                         if(fog_val >= 0.6f){
2637                                 model_set_detail_level(2);
2638                                 model_render( shipp->modelnum, &obj->orient, &obj->pos, render_flags | MR_LOCK_DETAIL, OBJ_INDEX(obj) );
2639                         } else {
2640                                 model_render( shipp->modelnum, &obj->orient, &obj->pos, render_flags, OBJ_INDEX(obj) );
2641                         }
2642                 } else {
2643                         model_render( shipp->modelnum, &obj->orient, &obj->pos, render_flags, OBJ_INDEX(obj) );
2644                 }
2645
2646                 // always turn off fog after rendering a ship
2647                 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0, -1.0f, -1.0f);
2648
2649                 light_set_shadow(0);
2650
2651                 #ifndef NDEBUG
2652                 if (Show_shield_mesh)
2653                         ship_draw_shield( obj);         //      Render the shield.
2654                 #endif
2655
2656                 if ( clip_started )     {
2657                         g3_stop_user_clip_plane();
2658                 }
2659         } 
2660
2661 /*      if (Mc.shield_hit_tri != -1) {
2662                 //render_shield_explosion(model_num, orient, pos, &Hit_point, Hit_tri);
2663                 Mc.shield_hit_tri = -1;
2664         }
2665 */
2666
2667         ship_model_stop(obj);
2668
2669         if (shipp->shield_hits) {
2670                 create_shield_explosion_all(obj);
2671                 shipp->shield_hits = 0;
2672         }
2673
2674 #ifndef NDEBUG
2675         if (Ai_render_debug_flag || Show_paths) {
2676                 if ( shipp->ai_index != -1 ){
2677                         render_path_points(obj);
2678                 }
2679
2680                 render_dock_bays(obj);
2681         }
2682 #endif
2683         
2684 #ifndef NDEBUG
2685         if(Show_tnorms){
2686                 ship_subsys *systemp;
2687                 vector tpos, tnorm, temp;
2688                 vector v1, v2;
2689                 vertex l1, l2;
2690
2691                 gr_set_color(0, 0, 255);
2692                 systemp = GET_FIRST( &shipp->subsys_list );             
2693                 while ( systemp != END_OF_LIST(&shipp->subsys_list) ) {
2694                         ship_get_global_turret_gun_info(obj, systemp, &tpos, &tnorm, 1, &temp);
2695                         
2696                         v1 = tpos;
2697                         vm_vec_scale_add(&v2, &v1, &tnorm, 20.0f);
2698
2699                         g3_rotate_vertex(&l1, &v1);
2700                         g3_rotate_vertex(&l2, &v2);
2701
2702                         g3_draw_sphere(&l1, 2.0f);
2703                         g3_draw_line(&l1, &l2);
2704
2705                         systemp = GET_NEXT(systemp);
2706                 }
2707         }
2708 #endif
2709 }
2710
2711 void ship_subsystem_delete(ship *shipp)
2712 {
2713         ship_subsys *systemp, *temp;
2714
2715         systemp = GET_FIRST( &shipp->subsys_list );
2716         while ( systemp != END_OF_LIST(&shipp->subsys_list) ) {
2717                 temp = GET_NEXT( systemp );                                                             // use temporary since pointers will get screwed with next operation
2718                 list_remove( &shipp->subsys_list, systemp );                    // remove the element
2719                 list_append( &ship_subsys_free_list, systemp );         // and place back onto free list
2720                 systemp = temp;                                                                                         // use the temp variable to move right along
2721         }
2722 }
2723
2724 void ship_delete( object * obj )
2725 {
2726         ship    *shipp;
2727         int     num, objnum;
2728
2729         num = obj->instance;
2730         SDL_assert( num >= 0);
2731
2732         objnum = OBJ_INDEX(obj);
2733         SDL_assert( Ships[num].objnum == objnum );
2734
2735         shipp = &Ships[num];
2736
2737         if (shipp->ai_index != -1){
2738                 ai_free_slot(shipp->ai_index);
2739         }       
2740
2741         // free up the list of subsystems of this ship.  walk through list and move remaining subsystems
2742         // on ship back to the free list for other ships to use.
2743         ship_subsystem_delete(&Ships[num]);
2744
2745         shipp->objnum = -1;
2746         // mwa 11/24/97 num_ships--;
2747
2748         if (model_get(shipp->modelnum)->shield.ntris) {
2749                 free(shipp->shield_integrity);
2750                 shipp->shield_integrity = NULL;
2751         }
2752
2753         if ( shipp->ship_list_index != -1 ) {
2754                 ship_obj_list_remove(shipp->ship_list_index);
2755                 shipp->ship_list_index = -1;
2756         }
2757
2758         free_sexp2(shipp->arrival_cue);
2759         free_sexp2(shipp->departure_cue);
2760
2761         // call the contrail system
2762         ct_ship_delete(shipp);
2763 }
2764
2765 // function used by ship_destroyed and ship_departed which is called if the ship
2766 // is in a wing.  This function updates the ship_index list (i.e. removes it's
2767 // entry in the list), and packs the array accordingly.
2768 void ship_wing_cleanup( int shipnum, wing *wingp )
2769 {
2770         int i, index = -1, team;
2771
2772         team = Ships[shipnum].team;
2773         // compress the ship_index array and mark the last entry with a -1
2774         for (i = 0; i < wingp->current_count; i++ ) {
2775                 if ( wingp->ship_index[i] == shipnum ) {
2776                         index = i;
2777                         break;
2778                 }
2779         }
2780
2781         // SDL_assert(index != -1);
2782         
2783         // this can happen in multiplayer (dogfight, ingame join specifically)
2784         if(index == -1){
2785                 return;
2786         }
2787
2788         for ( i = index; i < wingp->current_count - 1; i++ ){
2789                 wingp->ship_index[i] = wingp->ship_index[i+1];
2790         }
2791
2792         wingp->current_count--;
2793         SDL_assert ( wingp->current_count >= 0 );
2794         wingp->ship_index[wingp->current_count] = -1;
2795
2796         // if the current count is 0, check to see if the wing departed or was destroyed.
2797         if ( wingp->current_count == 0 ) {
2798
2799                 // if this wing was ordered to depart by the player, set the current_wave equal to the total
2800                 // waves so we can mark the wing as gone and no other ships arrive
2801                 if ( wingp->flags & WF_DEPARTURE_ORDERED ) 
2802                         wingp->current_wave = wingp->num_waves;
2803
2804                 // first, be sure to mark a wing destroyed event if all members of wing were destroyed and on
2805                 // the last wave.  This circumvents a problem where the wing could be marked as departed and
2806                 // destroyed if the last ships were destroyed after the wing's departure cue became true.
2807
2808                 // if the wing wasn't destroyed, and it is departing, then mark it as departed -- in this
2809                 // case, there had better be ships in this wing with departure entries in the log file.  The
2810                 // logfile code checks for this case.  
2811                 if ( (wingp->current_wave == wingp->num_waves) && (wingp->total_destroyed == wingp->total_arrived_count) ) {
2812                         mission_log_add_entry(LOG_WING_DESTROYED, wingp->name, NULL, team);
2813                         wingp->flags |= WF_WING_GONE;
2814                         wingp->time_gone = Missiontime;
2815                 } else if ( (wingp->flags & WF_WING_DEPARTING) || (wingp->current_wave == wingp->num_waves) ) {
2816 #ifndef NDEBUG
2817                         ship_obj *so;
2818
2819
2820                         // apparently, there have been reports of ships still present in the mission when this log
2821                         // entry if written.  Do a sanity check here to find out for sure.
2822                         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
2823
2824                                 // skip the player -- stupid special case.
2825                                 if ( &Objects[so->objnum] == Player_obj )
2826                                         continue;
2827
2828                                 if ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN) )
2829                                         continue;
2830
2831                                 if ( (Ships[Objects[so->objnum].instance].wingnum == WING_INDEX(wingp)) && !(Ships[Objects[so->objnum].instance].flags & (SF_DEPARTING|SF_DYING)) )
2832                                         Int3();
2833                         }
2834 #endif
2835
2836                         if ( wingp->flags & (WF_WING_DEPARTING|WF_DEPARTURE_ORDERED) )
2837                                 mission_log_add_entry(LOG_WING_DEPART, wingp->name, NULL, team);
2838
2839                         wingp->flags |= WF_WING_GONE;
2840                         wingp->time_gone = Missiontime;
2841                 }
2842         }
2843 }
2844
2845 // function to do management, like log entries and wing cleanup after a ship has been destroyed
2846
2847 void ship_destroyed( int num )
2848 {
2849         ship            *shipp;
2850         object  *objp;
2851
2852         shipp = &Ships[num];
2853         objp = &Objects[shipp->objnum];
2854
2855         // add the information to the exited ship list
2856         ship_add_exited_ship( shipp, SEF_DESTROYED );
2857
2858         // determine if we need to count this ship as a klll in counting number of kills per ship type
2859         // look at the ignore flag for the ship (if not in a wing), or the ignore flag for the wing
2860         // (if the ship is in a wing), and add to the kill count if the flags are not set
2861         if ( !(shipp->flags & SF_IGNORE_COUNT) ||  ((shipp->wingnum != -1) && !(Wings[shipp->wingnum].flags & WF_IGNORE_COUNT)) )
2862                 ship_add_ship_type_kill_count( Ship_info[shipp->ship_info_index].flags );
2863
2864         // if ship belongs to a wing -- increment the total number of ships in the wing destroyed
2865         if ( shipp->wingnum != -1 ) {
2866                 wing *wingp;
2867
2868                 wingp = &Wings[shipp->wingnum];
2869                 wingp->total_destroyed++;
2870                 ship_wing_cleanup( num, wingp );
2871         }
2872
2873         //      Note, this call to ai_ship_destroy must come after ship_wing_cleanup for guarded wings to
2874         //      properly note the destruction of a ship in their wing.
2875         if ( shipp->ai_index != -1 ) {
2876                 ai_ship_destroy(num, SEF_DESTROYED);            //      Do AI stuff for destruction of ship.
2877         }
2878
2879         nprintf(("Alan","SHIP DESTROYED: %s\n", shipp->ship_name));
2880
2881         if ( (shipp->wing_status_wing_index >= 0) && (shipp->wing_status_wing_pos >= 0) ) {
2882                 nprintf(("Alan","STATUS UPDATED: %s\n", shipp->ship_name));
2883                 hud_set_wingman_status_dead(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
2884         }
2885
2886         // let the event music system know a hostile was destoyed (important for deciding when to transition from battle to normal music)
2887         if (Player_ship != NULL) {
2888                 if (shipp->team != Player_ship->team) {
2889                         event_music_hostile_ship_destroyed();
2890                 }
2891         }
2892 }
2893
2894 void ship_vanished(int num)
2895 {
2896         ship *sp;
2897         object *objp;   
2898
2899         sp = &Ships[num];
2900         objp = &Objects[sp->objnum];
2901
2902         // demo recording
2903         if(Game_mode & GM_DEMO_RECORD){
2904                 demo_POST_departed(Objects[Ships[num].objnum].signature, Ships[num].flags);
2905         }
2906
2907         // add the information to the exited ship list
2908         ship_add_exited_ship( sp, SEF_DEPARTED );
2909
2910         // update wingman status gauge
2911         if ( (sp->wing_status_wing_index >= 0) && (sp->wing_status_wing_pos >= 0) ) {
2912                 hud_set_wingman_status_departed(sp->wing_status_wing_index, sp->wing_status_wing_pos);
2913         }
2914
2915         ai_ship_destroy(num, SEF_DEPARTED);             // should still do AI cleanup after ship has departed
2916 }
2917
2918 void ship_departed( int num )
2919 {
2920         ship *sp;
2921         int i;
2922
2923         sp = &Ships[num];
2924
2925         // demo recording
2926         if(Game_mode & GM_DEMO_RECORD){
2927                 demo_POST_departed(Objects[Ships[num].objnum].signature, Ships[num].flags);
2928         }
2929
2930         // add the information to the exited ship list
2931         ship_add_exited_ship( sp, SEF_DEPARTED );
2932
2933         // update wingman status gauge
2934         if ( (sp->wing_status_wing_index >= 0) && (sp->wing_status_wing_pos >= 0) ) {
2935                 hud_set_wingman_status_departed(sp->wing_status_wing_index, sp->wing_status_wing_pos);
2936         }
2937
2938         // see if this ship departed within the radius of a jump node -- if so, put the node name into
2939         // the secondary mission log field
2940         for ( i = 0; i < Num_jump_nodes; i++ ) {
2941                 float radius, dist;
2942                 vector ship_pos, node_pos;
2943
2944                 ship_pos = Objects[sp->objnum].pos;
2945                 node_pos = Objects[Jump_nodes[i].objnum].pos;
2946                 radius = model_get_radius( Jump_nodes[i].modelnum );
2947                 dist = vm_vec_dist( &ship_pos, &node_pos );
2948                 if ( dist <= radius ) {
2949                         mission_log_add_entry(LOG_SHIP_DEPART, sp->ship_name, Jump_nodes[i].name, sp->wingnum);
2950                         break;
2951                 }
2952                 dist = 1.0f;
2953         }
2954
2955         if ( i == Num_jump_nodes ){
2956                 mission_log_add_entry(LOG_SHIP_DEPART, sp->ship_name, NULL, sp->wingnum);
2957         }
2958                 
2959         ai_ship_destroy(num, SEF_DEPARTED);             // should still do AI cleanup after ship has departed
2960
2961         // don't bother doing this for demo playback - we don't keep track of wing info
2962         if(!(Game_mode & GM_DEMO_PLAYBACK)){
2963                 if ( sp->wingnum != -1 ) {
2964                         wing *wingp;
2965
2966                         wingp = &Wings[sp->wingnum];
2967                         wingp->total_departed++;
2968                         ship_wing_cleanup( num, wingp );
2969                 }
2970         }
2971 }
2972
2973 // --------------------------------------------------------------------------------------------------------------------
2974 // ship_explode_area_calc_damage
2975 // 
2976 // input                        pos1                    =>              ship explosion position
2977 //                                      pos2                    =>              other ship position
2978 //                                      inner_rad       =>              distance from ship center for which full damage is applied
2979 //                                      outer_rad       =>              distance from ship center for which no damage is applied
2980 //                                      max_damage      =>              maximum damage applied
2981 //                                      max_blast       =>              maximum impulse applied from blast
2982 // 
2983 // calculates the blast and damage applied to a ship from another ship blowing up.
2984 //
2985 int ship_explode_area_calc_damage( vector *pos1, vector *pos2, float inner_rad, float outer_rad, float max_damage, float max_blast, float *damage, float *blast )
2986 {
2987         float dist;
2988
2989         dist = vm_vec_dist_quick( pos1, pos2 );
2990
2991         // check outside outer radius
2992         if ( dist > outer_rad )
2993                 return -1;
2994
2995         if ( dist < inner_rad ) {
2996         // check insider inner radius
2997                 *damage = max_damage;
2998                 *blast = max_blast;
2999         } else {
3000         // between inner and outer
3001                 float fraction = 1.0f - (dist - inner_rad) / (outer_rad - inner_rad);
3002                 *damage  = fraction * max_damage;
3003                 *blast   = fraction * max_blast;
3004         }
3005
3006         return 1;
3007 }
3008
3009 // --------------------------------------------------------------------------------------------------------------------
3010 // ship_blow_up_area_apply_blast
3011 // this function applies damage to ship close to others when a ship dies and blows up
3012 //
3013 //              inputs: objp                    =>              ship object pointers
3014 //                                      pos                     =>              position of the ship when it finally blows up
3015 //                                      inner_rad       =>              distance from ship center for which full damage is applied
3016 //                                      outer_rad       =>              distance from ship center for which no damage is applied
3017 //                                      damage          =>              maximum damage applied
3018 //                                      blast                   =>              maximum impulse applied from blast
3019
3020 void ship_blow_up_area_apply_blast( object *exp_objp)
3021 {
3022         ship_info       *sip;
3023         SDL_assert( exp_objp->type == OBJ_SHIP );
3024         float   inner_rad, outer_rad, max_damage, max_blast, shockwave_speed;
3025         shockwave_create_info sci;
3026
3027         //      No area explosion in training missions.
3028         if (The_mission.game_type & MISSION_TYPE_TRAINING){
3029                 return;
3030         }
3031                 
3032         if ((exp_objp->hull_strength <= KAMIKAZE_HULL_ON_DEATH) && (Ai_info[Ships[exp_objp->instance].ai_index].ai_flags & AIF_KAMIKAZE) && (Ships[exp_objp->instance].special_exp_index < 0)) {
3033                 float override = Ai_info[Ships[exp_objp->instance].ai_index].kamikaze_damage;
3034
3035                 inner_rad = exp_objp->radius*2.0f;
3036                 outer_rad = exp_objp->radius*4.0f; // + (override * 0.3f);
3037                 max_damage = override;
3038                 max_blast = override * 5.0f;
3039                 shockwave_speed = 100.0f;
3040         } else {
3041                 sip = &Ship_info[Ships[exp_objp->instance].ship_info_index];
3042
3043                 if (Ships[exp_objp->instance].special_exp_index != -1) {
3044                         int start = Ships[exp_objp->instance].special_exp_index;
3045                         int propagates;
3046                         inner_rad = (float) atoi(Sexp_variables[start+INNER_RAD].text);
3047                         outer_rad = (float) atoi(Sexp_variables[start+OUTER_RAD].text);
3048                         max_damage = (float) atoi(Sexp_variables[start+DAMAGE].text);
3049                         max_blast = (float) atoi(Sexp_variables[start+BLAST].text);
3050                         propagates = atoi(Sexp_variables[start+PROPAGATE].text);
3051                         if (propagates) {
3052                                 shockwave_speed = (float) atoi(Sexp_variables[start+SHOCK_SPEED].text);
3053                         } else {
3054                                 shockwave_speed = 0.0f;
3055                         }
3056                 } else {
3057                         inner_rad = sip->inner_rad;
3058                         outer_rad = sip->outer_rad;
3059                         max_damage = sip->damage;
3060                         max_blast  = sip->blast;
3061                         shockwave_speed = sip->shockwave_speed;
3062                 }
3063         }
3064
3065         // nprintf(("AI", "Frame %i: Area effect blast from ship %s\n", Framecount, Ships[exp_objp->instance].ship_name));
3066
3067         // account for ships that give no damage when they blow up.
3068         if ( (max_damage < 0.1f) && (max_blast < 0.1f) ){
3069                 return;
3070         }
3071
3072         if ( shockwave_speed > 0 ) {
3073                 sci.inner_rad = inner_rad;
3074                 sci.outer_rad = outer_rad;
3075                 sci.blast = max_blast;
3076                 sci.damage = max_damage;
3077                 sci.speed = shockwave_speed;
3078                 sci.rot_angle = frand_range(0.0f, 359.0f);
3079                 shipfx_do_shockwave_stuff(&Ships[exp_objp->instance], &sci);
3080                 // shockwave_create(Ships[exp_objp->instance].objnum, &exp_objp->pos, shockwave_speed, inner_rad, outer_rad, max_damage, max_blast, SW_SHIP_DEATH);
3081         } else {
3082                 object *objp;
3083                 float blast = 0.0f;
3084                 float damage = 0.0f;
3085                 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3086                         if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
3087                                 continue;
3088                         }
3089                 
3090                         if ( objp == exp_objp ){
3091                                 continue;
3092                         }
3093
3094                         // don't blast navbuoys
3095                         if ( objp->type == OBJ_SHIP ) {
3096                                 if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
3097                                         continue;
3098                                 }
3099                         }
3100
3101                         if ( ship_explode_area_calc_damage( &exp_objp->pos, &objp->pos, inner_rad, outer_rad, max_damage, max_blast, &damage, &blast ) == -1 ){
3102                                 continue;
3103                         }
3104
3105                         switch ( objp->type ) {
3106                         case OBJ_SHIP:
3107                                 ship_apply_global_damage( objp, exp_objp, &exp_objp->pos, damage );
3108                                 vector force, vec_ship_to_impact;
3109                                 vm_vec_sub( &vec_ship_to_impact, &objp->pos, &exp_objp->pos );
3110                                 vm_vec_copy_normalize( &force, &vec_ship_to_impact );
3111                                 vm_vec_scale( &force, blast );
3112                                 ship_apply_whack( &force, &vec_ship_to_impact, objp );
3113                                 break;
3114                         case OBJ_ASTEROID:
3115                                 asteroid_hit(objp, NULL, NULL, damage);
3116                                 break;
3117                         default:
3118                                 Int3();
3119                                 break;
3120                         }
3121                 }       // end for
3122         }
3123 }
3124
3125 void do_dying_undock_physics(object* objp, ship* sp) 
3126 {
3127         SDL_assert(sp->dock_objnum_when_dead >= 0);
3128         if(sp->dock_objnum_when_dead < 0){
3129                 return;
3130         }
3131         object* dock_obj = &Objects[sp->dock_objnum_when_dead];
3132
3133         // sanity checks
3134         SDL_assert(objp->type == OBJ_SHIP);
3135         SDL_assert(dock_obj->type == OBJ_SHIP);
3136         if((objp->type != OBJ_SHIP) || (dock_obj->type != OBJ_SHIP)){
3137                 return;
3138         }
3139
3140         float damage = 0.2f*Ship_info[sp->ship_info_index].initial_hull_strength;
3141         ship_apply_global_damage(dock_obj, objp, &objp->pos, damage);
3142
3143         // do physics
3144         vector impulse_norm, impulse_vec, pos;
3145         vm_vec_sub(&impulse_norm, &dock_obj->pos, &objp->pos);
3146         vm_vec_normalize(&impulse_norm);
3147         // set for relative separation velocity of ~30
3148         float impulse_mag = 50.f*dock_obj->phys_info.mass*objp->phys_info.mass/(dock_obj->phys_info.mass + objp->phys_info.mass);
3149         vm_vec_copy_scale(&impulse_vec, &impulse_norm, impulse_mag);
3150         vm_vec_rand_vec_quick(&pos);
3151         vm_vec_scale(&pos, dock_obj->radius);
3152         // apply whack to dock obj
3153         physics_apply_whack(&impulse_vec, &pos, &dock_obj->phys_info, &dock_obj->orient, dock_obj->phys_info.mass);
3154         // enhance rotation of the docked ship
3155         vm_vec_scale(&dock_obj->phys_info.rotvel, 2.0f);
3156
3157         // apply whack to ship
3158         vm_vec_negate(&impulse_vec);
3159         vm_vec_rand_vec_quick(&pos);
3160         vm_vec_scale(&pos, objp->radius);
3161         physics_apply_whack(&impulse_vec, &pos, &objp->phys_info, &objp->orient, objp->phys_info.mass);
3162
3163         // reset dock_objnum_when_dead to -1 for dockee, since docker has blown up.
3164         if (Ships[dock_obj->instance].dock_objnum_when_dead == sp->objnum) {
3165                 Ships[dock_obj->instance].dock_objnum_when_dead = -1;
3166         }
3167 }
3168
3169 //      Do the stuff we do in a frame for a ship that's in its death throes.
3170 void ship_dying_frame(object *objp, int ship_num)
3171 {
3172         ship    *sp;
3173         sp = &Ships[ship_num];
3174         int knossos_ship = false;
3175
3176         if ( sp->flags & SF_DYING )     {
3177                 knossos_ship = (Ship_info[sp->ship_info_index].flags & SIF_KNOSSOS_DEVICE);
3178
3179                 // bash hull value toward 0 (from self destruct)
3180                 if (objp->hull_strength > 0) {
3181                         int time_left = timestamp_until(sp->final_death_time);
3182                         float hits_left = objp->hull_strength;
3183
3184                         objp->hull_strength -= hits_left * (1000.0f * flFrametime) / time_left;
3185                 }
3186
3187                 // special case of VAPORIZE
3188                 if (sp->flags & SF_VAPORIZE) {
3189                         // SDL_assert(Ship_info[sp->ship_info_index].flags & SIF_SMALL_SHIP);
3190                         if (timestamp_elapsed(sp->final_death_time)) {
3191
3192                                 // play death sound
3193                                 snd_play_3d( &Snds[SND_VAPORIZED], &objp->pos, &View_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY  );
3194
3195                                 // do joystick effect
3196                                 if (objp == Player_obj) {
3197                                         joy_ff_explode();
3198                                 }
3199
3200                                 // if dying ship is docked, do damage to docked and physics
3201                                 if (sp->dock_objnum_when_dead != -1)  {
3202                                         do_dying_undock_physics(objp, sp);
3203                                 }                       
3204
3205                                 // do all accounting for respawning client and server side here.
3206                                 if (objp == Player_obj) {                               
3207                                         gameseq_post_event(GS_EVENT_DEATH_BLEW_UP);
3208                                 }
3209
3210                                 // mark object as dead
3211                                 objp->flags |= OF_SHOULD_BE_DEAD;
3212
3213                                 // Don't blow up model.  Only use debris shards.
3214                                 // call ship function to clean up after the ship is destroyed.
3215                                 ship_destroyed(ship_num);
3216                                 return;
3217                         } else {
3218                                 return;
3219                         }
3220                 }
3221
3222                 // bash the desired rotvel
3223                 objp->phys_info.desired_rotvel = sp->deathroll_rotvel;
3224
3225                 // Do fireballs for Big ship with propagating explostion, but not Kamikaze
3226                 if (!(Ai_info[sp->ai_index].ai_flags & AIF_KAMIKAZE) && ship_get_exp_propagates(sp)) {
3227                         if ( timestamp_elapsed(Ships[ship_num].next_fireball))  {
3228                                 vector outpnt, pnt1, pnt2;
3229                                 polymodel *pm = model_get(sp->modelnum);
3230
3231                                 // Gets two random points on the surface of a submodel
3232                                 submodel_get_two_random_points(sp->modelnum, pm->detail[0], &pnt1, &pnt2 );
3233
3234                                 //      vm_vec_avg( &tmp, &pnt1, &pnt2 ); [KNOSSOS get random in plane 1/1.414 in rad
3235                                 model_find_world_point(&outpnt, &pnt1, sp->modelnum, pm->detail[0], &objp->orient, &objp->pos );
3236
3237                                 float rad = objp->radius*0.1f;
3238                                 int fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
3239                                 fireball_create( &outpnt, fireball_type, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
3240                                 // start the next fireball up in the next 50 - 200 ms (2-3 per frame)
3241                                 sp->next_fireball = timestamp_rand(333,500);
3242
3243                                 // do sound - maybe start a random sound, if it has played far enough.
3244                                 do_sub_expl_sound(objp->radius, &outpnt, sp->sub_expl_sound_handle);
3245                         }
3246                 }
3247
3248                 // create little fireballs for knossos as it dies
3249                 if (knossos_ship) {
3250                         if ( timestamp_elapsed(Ships[ship_num].next_fireball)) {
3251                                 vector rand_vec, outpnt; // [0-.7 rad] in plane
3252                                 vm_vec_rand_vec_quick(&rand_vec);
3253                                 float scale = -vm_vec_dotprod(&objp->orient.v.fvec, &rand_vec) * (0.9f + 0.2f * frand());
3254                                 vm_vec_scale_add2(&rand_vec, &objp->orient.v.fvec, scale);
3255                                 vm_vec_normalize_quick(&rand_vec);
3256                                 scale = objp->radius * frand() * 0.717f;
3257                                 vm_vec_scale(&rand_vec, scale);
3258                                 vm_vec_add(&outpnt, &objp->pos, &rand_vec);
3259
3260                                 float rad = objp->radius*0.2f;
3261                                 int fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
3262                                 fireball_create( &outpnt, fireball_type, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
3263                                 // start the next fireball up in the next 50 - 200 ms (2-3 per frame)
3264                                 sp->next_fireball = timestamp_rand(333,500);
3265
3266                                 // emit particles
3267                                 particle_emitter        pe;
3268
3269                                 pe.num_low = 15;                                        // Lowest number of particles to create
3270                                 pe.num_high = 30;                               // Highest number of particles to create
3271                                 pe.pos = outpnt;                                // Where the particles emit from
3272                                 pe.vel = objp->phys_info.vel;   // Initial velocity of all the particles
3273                                 pe.min_life = 2.0f;     // How long the particles live
3274                                 pe.max_life = 12.0f;    // How long the particles live
3275                                 pe.normal = objp->orient.v.uvec;        // What normal the particle emit around
3276                                 pe.normal_variance = 2.0f;              //      How close they stick to that normal 0=on normal, 1=180, 2=360 degree
3277                                 pe.min_vel = 50.0f;
3278                                 pe.max_vel = 350.0f;
3279                                 pe.min_rad = 30.0f;     // * objp->radius;
3280                                 pe.max_rad = 100.0f; // * objp->radius;
3281                                 particle_emit( &pe, PARTICLE_SMOKE2, 0, 50 );
3282
3283                                 // do sound - maybe start a random sound, if it has played far enough.
3284                                 do_sub_expl_sound(objp->radius, &outpnt, sp->sub_expl_sound_handle);
3285                         }
3286                 }
3287
3288
3289                 //nprintf(("AI", "Ship.cpp: Frame=%i, Time = %7.3f, Ship %s will die in %7.3f seconds.\n", Framecount, f2fl(Missiontime), Ships[ship_num].ship_name, (float) timestamp_until(sp->final_death_time)/1000.0f));
3290                 int time_until_minor_explosions = timestamp_until(sp->final_death_time);
3291
3292                 // Wait until just before death and set off some explosions
3293                 // If it is less than 1/2 second until large explosion, but there is
3294                 // at least 1/10th of a second left, then create 5 small explosions
3295                 if ( (time_until_minor_explosions < 500) && (time_until_minor_explosions > 100) && (!sp->pre_death_explosion_happened) ) {
3296                         //mprintf(( "Ship almost dying!!\n" ));
3297                         sp->next_fireball = timestamp(-1);      // never time out again
3298                         sp->pre_death_explosion_happened=1;             // Mark this event as having occurred
3299
3300                         polymodel *pm = model_get(sp->modelnum);
3301
3302                         // Start shockwave for ship with propagating explosion, do now for timing
3303                         if ( ship_get_exp_propagates(sp) ) {
3304                                 ship_blow_up_area_apply_blast( objp );
3305                         }
3306
3307                         for (int zz=0; zz<6; zz++ ) {
3308                                 // dont make sequence of fireballs for knossos
3309                                 if (knossos_ship) {
3310                                         break;
3311                                 }
3312                                 // Find two random vertices on the model, then average them
3313                                 // and make the piece start there.
3314                                 vector tmp, outpnt, pnt1, pnt2;
3315
3316                                 // Gets two random points on the surface of a submodel [KNOSSOS]
3317                                 submodel_get_two_random_points(sp->modelnum, pm->detail[0], &pnt1, &pnt2 );
3318
3319                                 vm_vec_avg( &tmp, &pnt1, &pnt2 );
3320                                 model_find_world_point(&outpnt, &tmp, sp->modelnum, pm->detail[0], &objp->orient, &objp->pos );
3321
3322                                 float rad = frand()*0.30f;
3323                                 rad += objp->radius*0.40f;
3324                                 fireball_create( &outpnt, FIREBALL_EXPLOSION_MEDIUM, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
3325                         }
3326
3327                         // if ship is docked, undock now.
3328                         if (sp->dock_objnum_when_dead != -1)  {                         
3329                                 // other ship undocks
3330                                 //      These asserts should no longer be needed and they cause a problem that is not obvious how to fix.
3331                                 //SDL_assert( !(Ai_info[Ships[dock_obj->instance].ai_index].ai_flags & AIF_DOCKED) );
3332                                 //SDL_assert( Ai_info[Ships[dock_obj->instance].ai_index].dock_objnum == -1 );
3333                                 // MWA  Ai_info[Ships[dock_obj->instance].ai_index].ai_flags &= ~AIF_DOCKED;
3334                                 // MWA  Ai_info[Ships[dock_obj->instance].ai_index].dock_objnum = -1;
3335                                 // MWA Ai_info[Ships[dock_obj->instance].ai_index].mode = AIM_NONE;
3336                         }
3337                 }
3338
3339                 if ( timestamp_elapsed(sp->final_death_time))   {
3340
3341                         sp->final_death_time = timestamp(-1);   // never time out again
3342                         //mprintf(( "Ship dying!!\n" ));
3343                         
3344                         // play ship explosion sound effect, pick appropriate explosion sound
3345                         int sound_index;
3346                         if ( Ship_info[sp->ship_info_index].flags & (SIF_CAPITAL | SIF_KNOSSOS_DEVICE) ) {
3347                                 sound_index=SND_CAPSHIP_EXPLODE;
3348                         } else {
3349                                 if ( OBJ_INDEX(objp) & 1 ) {
3350                                         sound_index=SND_SHIP_EXPLODE_1;
3351                                 } else {
3352                                         sound_index=SND_SHIP_EXPLODE_2;
3353                                 }
3354                         }
3355
3356                         snd_play_3d( &Snds[sound_index], &objp->pos, &View_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY  );
3357                         if (objp == Player_obj)
3358                                 joy_ff_explode();
3359
3360                         if ( sp->death_roll_snd != -1 ) {
3361                                 snd_stop(sp->death_roll_snd);
3362                                 sp->death_roll_snd = -1;
3363                         }
3364
3365                         // if dying ship is docked, do damage to docked and physics
3366                         if (sp->dock_objnum_when_dead != -1)  {
3367                                 do_dying_undock_physics(objp, sp);
3368                         }                       
3369
3370                         // play a random explosion
3371                         particle_emitter        pe;
3372
3373                         pe.num_low = 50;                                        // Lowest number of particles to create
3374                         pe.num_high = 100;                              // Highest number of particles to create
3375                         pe.pos = objp->pos;                             // Where the particles emit from
3376                         pe.vel = objp->phys_info.vel;   // Initial velocity of all the particles
3377                         pe.min_life = 0.5f;                             // How long the particles live
3378                         pe.max_life = 4.0f;                             // How long the particles live
3379                         pe.normal = objp->orient.v.uvec;        // What normal the particle emit around
3380                         pe.normal_variance = 2.0f;              //      How close they stick to that normal 0=on normal, 1=180, 2=360 degree
3381                         pe.min_vel = 0.0f;                              // How fast the slowest particle can move
3382                         pe.max_vel = 20.0f;                             // How fast the fastest particle can move
3383                         pe.min_rad = 0.1f;                              // Min radius
3384                         pe.max_rad = 1.5f;                              // Max radius
3385
3386                         if (!knossos_ship) {
3387                                 particle_emit( &pe, PARTICLE_SMOKE2, 0 );
3388                         }
3389
3390                         // If this is a large ship with a propagating explosion, set it to blow up.
3391                         if ( ship_get_exp_propagates(sp) )      {
3392                                 if (Ai_info[sp->ai_index].ai_flags & AIF_KAMIKAZE) {
3393                                         ship_blow_up_area_apply_blast( objp );
3394                                 }
3395                                 shipfx_large_blowup_init(sp);
3396                                 // need to timeout immediately to keep physics in sync
3397                                 sp->really_final_death_time = timestamp(0);
3398                         } else {
3399                                 // only do big fireball if not big ship
3400                                 float big_rad;
3401                                 int fireball_objnum, fireball_type;
3402                                 float explosion_life;
3403                                 big_rad = objp->radius*1.75f;
3404                                 fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
3405                                 if (knossos_ship) {
3406                                         big_rad = objp->radius * 1.2f;
3407                                         fireball_type = FIREBALL_EXPLOSION_LARGE1;
3408                                 }
3409                                 fireball_objnum = fireball_create( &objp->pos, fireball_type, OBJ_INDEX(objp), big_rad, 0, &objp->phys_info.vel );
3410                                 if ( fireball_objnum > -1 )     {
3411                                         explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
3412                                 } else {
3413                                         explosion_life = 0.0f;
3414                                 }
3415
3416                                 // JAS:  I put in all this code because of an item on my todo list that
3417                                 // said that the ship destroyed debris shouldn't pop in until the
3418                                 // big explosion is 30% done.  I did this on Oct24 and me & Adam 
3419                                 // thought it looked dumb since the explosion didn't move with the
3420                                 // ship, so instead of just taking this code out, since we might need
3421                                 // it in the future, I disabled it.   You can reenable it by changing
3422                                 // the commenting on the following two lines.
3423                                 sp->really_final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 );      // Wait till 30% of vclip time before breaking the ship up.
3424                                 //sp->really_final_death_time = timestamp(0);   // Make ship break apart the instant the explosion starts
3425                         }
3426
3427                         sp->flags |= SF_EXPLODED;
3428
3429                         if ( !(ship_get_exp_propagates(sp)) ) {
3430                                 // apply area of effect blast damage from ship explosion
3431                                 ship_blow_up_area_apply_blast( objp );
3432                         }
3433                 }
3434
3435                 if ( timestamp_elapsed(sp->really_final_death_time))    {
3436
3437                         //mprintf(( "Ship really dying!!\n" ));
3438                         // do large_ship_split and explosion
3439                         if ( sp->large_ship_blowup_index > -1 ) {
3440                                 if ( shipfx_large_blowup_do_frame(sp, flFrametime) )    {
3441                                         // do all accounting for respawning client and server side here.
3442                                         if(objp == Player_obj) {                                
3443                                                 gameseq_post_event(GS_EVENT_DEATH_BLEW_UP);
3444                                         }
3445
3446                                         objp->flags |= OF_SHOULD_BE_DEAD;                                                                       
3447                                         
3448                                         ship_destroyed(ship_num);               // call ship function to clean up after the ship is destroyed.
3449                                 }
3450                                 return;
3451                         } 
3452
3453                         //fireball_create( &objp->pos, FIREBALL_SHIP_EXPLODE1, OBJ_INDEX(objp), objp->radius/2.0f );
3454                         //mprintf(("Frame %i: Died!\n", Framecount));
3455
3456                         shipfx_blow_up_model(objp, Ships[ship_num].modelnum, 0, 20, &objp->pos );
3457
3458                         // do all accounting for respawning client and server side here.
3459                         if(objp == Player_obj) {                                
3460                                 gameseq_post_event(GS_EVENT_DEATH_BLEW_UP);
3461                         }
3462
3463                         objp->flags |= OF_SHOULD_BE_DEAD;
3464                                                                 
3465                         ship_destroyed(ship_num);               // call ship function to clean up after the ship is destroyed.
3466                         sp->really_final_death_time = timestamp( -1 );  // Never time out again!
3467                 }
3468
3469                 // If a ship is dying (and not a capital or big ship) then stutter the engine sound
3470                 if ( timestamp_elapsed(sp->next_engine_stutter) ) {
3471                         if ( !(Ship_info[sp->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
3472                                 sp->flags ^= SF_ENGINES_ON;                     // toggle state of engines
3473                                 sp->next_engine_stutter = timestamp_rand(50, 250);
3474                         }
3475                 }
3476         }
3477 }
3478
3479 void ship_chase_shield_energy_targets(ship *shipp, object *obj, float frametime)
3480 {
3481         float delta;
3482         ship_info       *sip;
3483
3484         if (shipp->flags & SF_DYING)
3485                 return;
3486
3487         sip = &Ship_info[shipp->ship_info_index];
3488
3489         delta = frametime * ETS_RECHARGE_RATE * sip->shields / 100.0f;
3490
3491         //      Chase target_shields and target_weapon_energy
3492         if (shipp->target_shields_delta > 0.0f) {
3493                 if (delta > shipp->target_shields_delta)
3494                         delta = shipp->target_shields_delta;
3495
3496                 add_shield_strength(obj, delta);
3497                 shipp->target_shields_delta -= delta;
3498         } else if (shipp->target_shields_delta < 0.0f) {
3499                 if (delta < -shipp->target_shields_delta)
3500                         delta = -shipp->target_shields_delta;
3501
3502                 add_shield_strength(obj, -delta);
3503                 shipp->target_shields_delta += delta;
3504         }
3505
3506         delta = frametime * ETS_RECHARGE_RATE * sip->max_weapon_reserve / 100.0f;
3507
3508         if (shipp->target_weapon_energy_delta > 0.0f) {
3509                 if (delta > shipp->target_weapon_energy_delta)
3510                         delta = shipp->target_weapon_energy_delta;
3511
3512                 shipp->weapon_energy += delta;
3513                 shipp->target_weapon_energy_delta -= delta;
3514         } else if (shipp->target_weapon_energy_delta < 0.0f) {
3515                 if (delta < -shipp->target_weapon_energy_delta)
3516                         delta = -shipp->target_weapon_energy_delta;
3517
3518                 shipp->weapon_energy -= delta;
3519                 shipp->target_weapon_energy_delta += delta;
3520         }
3521
3522 }
3523
3524 // Stuff for showing ship thrusters. 
3525 typedef struct thrust_anim {
3526         int     num_frames;
3527         int     first_frame;
3528         float time;                             // in seconds
3529 } thrust_anim;
3530
3531 #define NUM_THRUST_ANIMS                        6
3532 #define NUM_THRUST_GLOW_ANIMS           6
3533
3534 // These are indexed by:  Species*2 + (After_burner_on?1:0)
3535 static thrust_anim      Thrust_anims[NUM_THRUST_ANIMS];
3536 char    Thrust_anim_names[NUM_THRUST_ANIMS][MAX_FILENAME_LEN] = {       
3537 //XSTR:OFF
3538         "thruster01", "thruster01a", 
3539         "thruster02", "thruster02a", 
3540         "thruster03", "thruster03a" 
3541 //XSTR:ON
3542 };
3543
3544 // These are indexed by:  Species*2 + (After_burner_on?1:0)
3545 static thrust_anim      Thrust_glow_anims[NUM_THRUST_GLOW_ANIMS];
3546 char    Thrust_glow_anim_names[NUM_THRUST_GLOW_ANIMS][MAX_FILENAME_LEN] = {     
3547 //XSTR:OFF
3548         "thrusterglow01", "thrusterglow01a", 
3549         "thrusterglow02", "thrusterglow02a", 
3550         "thrusterglow03", "thrusterglow03a" 
3551 //XSTR:ON
3552 };
3553
3554 static int Thrust_anim_inited = 0;
3555
3556 // loads the animations for ship's afterburners
3557 void ship_init_thrusters()
3558 {
3559         int                     fps, i;
3560         thrust_anim     *ta;
3561
3562         if ( Thrust_anim_inited == 1 )
3563                 return;
3564
3565         // AL 29-3-98: Don't want to include Shivan thrusters in the demo build
3566         int num_thrust_anims = NUM_THRUST_ANIMS;
3567         #ifdef DEMO // N/A FS2_DEMO
3568                 num_thrust_anims = NUM_THRUST_ANIMS - 2;
3569         #endif
3570
3571         for ( i = 0; i < num_thrust_anims; i++ ) {
3572                 ta = &Thrust_anims[i];
3573                 ta->first_frame = bm_load_animation(Thrust_anim_names[i],  &ta->num_frames, &fps, 1);
3574                 if ( ta->first_frame == -1 ) {
3575                         Error(LOCATION,"Error loading animation file: %s\n",Thrust_anim_names[i]);
3576                         return;
3577                 }
3578                 SDL_assert(fps != 0);
3579                 ta->time = i2fl(ta->num_frames)/fps;
3580         }
3581
3582         // AL 29-3-98: Don't want to include Shivan thrusters in the demo build
3583         int num_thrust_glow_anims = NUM_THRUST_GLOW_ANIMS;
3584         #ifdef DEMO // N/A FS2_DEMO
3585                 num_thrust_glow_anims = NUM_THRUST_GLOW_ANIMS - 2;
3586         #endif
3587
3588         for ( i = 0; i < num_thrust_glow_anims; i++ ) {
3589                 ta = &Thrust_glow_anims[i];
3590                 ta->num_frames = NOISE_NUM_FRAMES;
3591                 fps = 15;
3592                 ta->first_frame = bm_load( Thrust_glow_anim_names[i] );
3593                 if ( ta->first_frame == -1 ) {
3594                         Error(LOCATION,"Error loading bitmap file: %s\n",Thrust_glow_anim_names[i]);
3595                         return;
3596                 }
3597                 SDL_assert(fps != 0);
3598                 ta->time = i2fl(ta->num_frames)/fps;
3599         }
3600
3601         Thrust_anim_inited = 1;
3602 }
3603
3604
3605 // JAS - figure out which thruster bitmap will get rendered next
3606 // time around.  ship_render needs to have shipp->thruster_bitmap set to
3607 // a valid bitmap number, or -1 if we shouldn't render thrusters.
3608 void ship_do_thruster_frame( ship *shipp, object *objp, float frametime )
3609 {
3610         float rate;
3611         int framenum;
3612         int anim_index;
3613         thrust_anim *the_anim;
3614         ship_info       *sinfo = &Ship_info[shipp->ship_info_index];
3615
3616         if ( !Thrust_anim_inited )      ship_init_thrusters();
3617
3618         // The animations are organized by:
3619         // Species*2 + (After_burner_on?1:0)
3620         anim_index = sinfo->species*2;
3621
3622         if ( objp->phys_info.flags & PF_AFTERBURNER_ON )        {
3623                 anim_index++;           //      select afterburner anim.
3624                 rate = 1.5f;            // go at 1.5x faster when afterburners on
3625         } else {
3626                 // If thrust at 0, go at half as fast, full thrust; full framerate
3627                 // so set rate from 0.5 to 1.0, depending on thrust from 0 to 1
3628                 // rate = 0.5f + objp->phys_info.forward_thrust / 2.0f;
3629                 rate = 0.67f * (1.0f + objp->phys_info.forward_thrust);
3630         }
3631
3632 //      rate = 0.1f;
3633
3634         SDL_assert( anim_index > -1 );
3635         SDL_assert( anim_index < NUM_THRUST_ANIMS );
3636
3637         the_anim = &Thrust_anims[anim_index];
3638
3639         SDL_assert( frametime > 0.0f );
3640         shipp->thruster_frame += frametime * rate;
3641
3642         // Sanity checks
3643         if ( shipp->thruster_frame < 0.0f )     shipp->thruster_frame = 0.0f;
3644         if ( shipp->thruster_frame > 100.0f ) shipp->thruster_frame = 0.0f;
3645
3646         while ( shipp->thruster_frame > the_anim->time )        {
3647                 shipp->thruster_frame -= the_anim->time;
3648         }
3649         framenum = fl2i( (shipp->thruster_frame*the_anim->num_frames) / the_anim->time );
3650         if ( framenum < 0 ) framenum = 0;
3651         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
3652
3653 //      if ( anim_index == 0 )
3654 //              mprintf(( "Frame = %d/%d, anim=%d\n", framenum+1,  the_anim->num_frames, anim_index ));
3655         
3656         // Get the bitmap for this frame
3657         shipp->thruster_bitmap = the_anim->first_frame + framenum;
3658
3659 //      mprintf(( "TF: %.2f\n", shipp->thruster_frame ));
3660
3661         // Do it for glow bitmaps
3662         the_anim = &Thrust_glow_anims[anim_index];
3663
3664         SDL_assert( frametime > 0.0f );
3665         shipp->thruster_glow_frame += frametime * rate;
3666
3667         // Sanity checks
3668         if ( shipp->thruster_glow_frame < 0.0f )        shipp->thruster_glow_frame = 0.0f;
3669         if ( shipp->thruster_glow_frame > 100.0f ) shipp->thruster_glow_frame = 0.0f;
3670
3671         while ( shipp->thruster_glow_frame > the_anim->time )   {
3672                 shipp->thruster_glow_frame -= the_anim->time;
3673         }
3674         framenum = fl2i( (shipp->thruster_glow_frame*the_anim->num_frames) / the_anim->time );
3675         if ( framenum < 0 ) framenum = 0;
3676         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
3677
3678 //      if ( anim_index == 0 )
3679 //              mprintf(( "Frame = %d/%d, anim=%d\n", framenum+1,  the_anim->num_frames, anim_index ));
3680         
3681         // Get the bitmap for this frame
3682         shipp->thruster_glow_bitmap = the_anim->first_frame;    // + framenum;
3683         shipp->thruster_glow_noise = Noise[framenum];
3684
3685 }
3686
3687
3688 // JAS - figure out which thruster bitmap will get rendered next
3689 // time around.  ship_render needs to have shipp->thruster_bitmap set to
3690 // a valid bitmap number, or -1 if we shouldn't render thrusters.
3691 // This does basically the same thing as ship_do_thruster_frame, except it
3692 // operates on a weapon.   This is in the ship code because it needs
3693 // the same thruster animation info as the ship stuff, and I would
3694 // rather extern this one function than all the thruster animation stuff.
3695 void ship_do_weapon_thruster_frame( weapon *weaponp, object *objp, float frametime )
3696 {
3697         float rate;
3698         int framenum;
3699         int anim_index;
3700         thrust_anim *the_anim;
3701
3702         if ( !Thrust_anim_inited )      ship_init_thrusters();
3703
3704         // The animations are organized by:
3705         // Species*2 + (After_burner_on?1:0)
3706         anim_index = weaponp->species*2;
3707
3708         // If thrust at 0, go at half as fast, full thrust; full framerate
3709         // so set rate from 0.5 to 1.0, depending on thrust from 0 to 1
3710         // rate = 0.5f + objp->phys_info.forward_thrust / 2.0f;
3711         rate = 0.67f * (1.0f + objp->phys_info.forward_thrust);
3712
3713         SDL_assert( anim_index > -1 );
3714         SDL_assert( anim_index < NUM_THRUST_ANIMS );
3715
3716         the_anim = &Thrust_anims[anim_index];
3717
3718         SDL_assert( frametime > 0.0f );
3719         weaponp->thruster_frame += frametime * rate;
3720
3721         // Sanity checks
3722         if ( weaponp->thruster_frame < 0.0f )   weaponp->thruster_frame = 0.0f;
3723         if ( weaponp->thruster_frame > 100.0f ) weaponp->thruster_frame = 0.0f;
3724
3725         while ( weaponp->thruster_frame > the_anim->time )      {
3726                 weaponp->thruster_frame -= the_anim->time;
3727         }
3728         framenum = fl2i( (weaponp->thruster_frame*the_anim->num_frames) / the_anim->time );
3729         if ( framenum < 0 ) framenum = 0;
3730         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
3731
3732 //      if ( anim_index == 0 )
3733 //              mprintf(( "Frame = %d/%d, anim=%d\n", framenum+1,  the_anim->num_frames, anim_index ));
3734         
3735         // Get the bitmap for this frame
3736         weaponp->thruster_bitmap = the_anim->first_frame + framenum;
3737
3738 //      mprintf(( "TF: %.2f\n", weaponp->thruster_frame ));
3739
3740         // Do it for glow bitmaps
3741         the_anim = &Thrust_glow_anims[anim_index];
3742
3743         SDL_assert( frametime > 0.0f );
3744         weaponp->thruster_glow_frame += frametime * rate;
3745
3746         // Sanity checks
3747         if ( weaponp->thruster_glow_frame < 0.0f )      weaponp->thruster_glow_frame = 0.0f;
3748         if ( weaponp->thruster_glow_frame > 100.0f ) weaponp->thruster_glow_frame = 0.0f;
3749
3750         while ( weaponp->thruster_glow_frame > the_anim->time ) {
3751                 weaponp->thruster_glow_frame -= the_anim->time;
3752         }
3753         framenum = fl2i( (weaponp->thruster_glow_frame*the_anim->num_frames) / the_anim->time );
3754         if ( framenum < 0 ) framenum = 0;
3755         if ( framenum >= the_anim->num_frames ) framenum = the_anim->num_frames-1;
3756
3757 //      if ( anim_index == 0 )
3758 //              mprintf(( "Frame = %d/%d, anim=%d\n", framenum+1,  the_anim->num_frames, anim_index ));
3759         
3760         // Get the bitmap for this frame
3761         weaponp->thruster_glow_bitmap = the_anim->first_frame;  // + framenum;
3762         weaponp->thruster_glow_noise = Noise[framenum];
3763 }
3764
3765
3766
3767 // Repair damaged subsystems for a ship, called for each ship once per frame.
3768 // TODO: optimize by only calling ever N seconds and keeping track of elapsed time
3769 //
3770 // NOTE: need to update current_hits in the sp->subsys_list element, and the sp->subsys_info[]
3771 // element.
3772 #define SHIP_REPAIR_SUBSYSTEM_RATE      0.01f   // percent repair per second for a subsystem
3773 #define SUBSYS_REPAIR_THRESHOLD         0.1     // only repair subsystems that have > 10% strength
3774 void ship_auto_repair_frame(int shipnum, float frametime)
3775 {
3776         ship_subsys                     *ssp;
3777         ship_subsys_info        *ssip;
3778         ship                                    *sp;
3779         ship_info                       *sip;
3780
3781         #ifndef NDEBUG
3782         if ( !Ship_auto_repair )        // only repair subsystems if Ship_auto_repair flag is set
3783                 return;
3784         #endif
3785
3786         SDL_assert( shipnum >= 0 && shipnum < MAX_SHIPS);
3787         sp = &Ships[shipnum];
3788         sip = &Ship_info[sp->ship_info_index];
3789
3790         // only allow for the auto-repair of subsystems on small ships
3791         if ( !(sip->flags & SIF_SMALL_SHIP) )
3792                 return;
3793
3794         // AL 3-14-98: only allow auto-repair if power output not zero
3795         if ( sip->power_output <= 0 )
3796                 return;
3797         
3798         // iterate through subsystems, repair as needed based on elapsed frametime
3799         for ( ssp = GET_FIRST(&sp->subsys_list); ssp != END_OF_LIST(&sp->subsys_list); ssp = GET_NEXT(ssp) ) {
3800                 SDL_assert(ssp->system_info->type >= 0 && ssp->system_info->type < SUBSYSTEM_MAX);
3801                 ssip = &sp->subsys_info[ssp->system_info->type];
3802
3803                 if ( ssp->current_hits != ssp->system_info->max_hits ) {                
3804
3805                         // only repair those subsystems which are not destroyed
3806                         if ( ssp->system_info->max_hits <= 0 || ssp->current_hits <= 0 )
3807                                 continue;
3808
3809                         // do incremental repair on the subsystem
3810                         ssp->current_hits += ssp->system_info->max_hits * SHIP_REPAIR_SUBSYSTEM_RATE * frametime;
3811                         ssip->current_hits += ssip->total_hits * SHIP_REPAIR_SUBSYSTEM_RATE * frametime;
3812                 
3813                         // check for overflow of current_hits
3814                         if ( ssp->current_hits >= ssp->system_info->max_hits ) {
3815                                 // TODO: here is hook for when a subsystem is fully repaired (eg add voice)
3816                                 ssp->current_hits = ssp->system_info->max_hits;
3817                         }
3818                         if ( ssip->current_hits >= ssip->total_hits ) {
3819                                 ssip->current_hits = ssip->total_hits;
3820                         }
3821                 }
3822         }       // end for
3823 }
3824
3825 // this function checks to see how far the player has strayed from his starting location (should be
3826 // single player only).  Issues a warning at some distance.  Makes mission end if he keeps flying away
3827 // 3 strikes and you're out or too far away
3828 #define PLAYER_MAX_DIST_WARNING                 70000                   // distance in KM at which player gets warning to return to battle
3829 #define PLAYER_DISTANCE_MAX_WARNINGS    3                               // maximum number of warnings player can receive before mission ends
3830 #define PLAYER_MAX_DIST_END                             75000                   // distance from starting loc at which we end mission
3831 #define PLAYER_WARN_DELTA_TIME                  10000
3832 #define PLAYER_DEATH_DELTA_TIME                 5000
3833
3834 void ship_check_player_distance_sub(player *p, int multi_target=-1)
3835 {
3836         // only check distance for ships
3837         if ( p->control_mode != PCM_NORMAL )    {
3838                 // already warping out... don't bother checking anymore
3839                 return;
3840         }
3841
3842         float dist = vm_vec_dist_quick(&Objects[p->objnum].pos, &vmd_zero_vector);
3843
3844         int give_warning_to_player = 0;
3845         if ( dist > PLAYER_MAX_DIST_WARNING ) {
3846                 if (p->distance_warning_count == 0) {
3847                         give_warning_to_player = 1;
3848                 } else {
3849                         if (timestamp_until(p->distance_warning_time) < 0) {
3850                                 give_warning_to_player = 1;
3851                         }
3852                 }
3853         }
3854
3855         if ( give_warning_to_player ) {
3856                 // increase warning count
3857                 p->distance_warning_count++;
3858                 // set timestamp unless player PLAYER_FLAGS_DIST_TO_BE_KILLED flag is set
3859                 if ( !(p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) ) {
3860                         p->distance_warning_time = timestamp(PLAYER_WARN_DELTA_TIME);
3861                 }
3862                 // issue up to max warnings
3863                 if (p->distance_warning_count <= PLAYER_DISTANCE_MAX_WARNINGS) {
3864                         message_send_builtin_to_player( MESSAGE_STRAY_WARNING, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_SOON, 0, 0, multi_target, -1 );
3865                 }
3866
3867 //              HUD_sourced_printf(HUD_SOURCE_TERRAN_CMD, XSTR("Terran Command: You're straying too far from battle pilot, return immediately or be taken from the battlefield.", -1));
3868                 if (p->distance_warning_count > PLAYER_DISTANCE_MAX_WARNINGS) {
3869                         p->flags |= PLAYER_FLAGS_DIST_WARNING;
3870                 }
3871         }
3872
3873         if ( !(p->flags & PLAYER_FLAGS_FORCE_MISSION_OVER) && ((p->distance_warning_count > PLAYER_DISTANCE_MAX_WARNINGS) || (dist > PLAYER_MAX_DIST_END)) ) {
3874 //              DKA 5/17/99 - DONT force warpout.  Won't work multiplayer.  Blow up ship.
3875                 if ( !(p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) ) {
3876                         message_send_builtin_to_player( MESSAGE_STRAY_WARNING_FINAL, NULL, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, multi_target, -1 );
3877                         p->flags |= PLAYER_FLAGS_DIST_TO_BE_KILLED;
3878                         p->distance_warning_time = timestamp(PLAYER_DEATH_DELTA_TIME);
3879                 }
3880 //              HUD_sourced_printf(HUD_SOURCE_TERRAN_CMD, XSTR("Terran Command: Sorry pilot, removing you from battle because of your insubordination!!!", -1));
3881 //              gameseq_post_event(GS_EVENT_PLAYER_WARPOUT_START_FORCED);
3882
3883                 // get hull strength and blow up
3884                 if ( (p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) && (timestamp_until(p->distance_warning_time) < 0) ) {
3885                         p->flags |= PLAYER_FLAGS_FORCE_MISSION_OVER;
3886                         float damage = 10.0f * Objects[p->objnum].hull_strength;
3887                         ship_apply_global_damage(&Objects[p->objnum], &Objects[p->objnum], NULL, damage);
3888                 }
3889         }
3890
3891         // see if player has moved back into "bounds"
3892         if ( (dist < PLAYER_MAX_DIST_WARNING) && (p->flags & PLAYER_FLAGS_DIST_WARNING) && !(p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) ) {
3893                 p->flags &= ~PLAYER_FLAGS_DIST_WARNING;
3894                 p->distance_warning_count = 1;
3895         }
3896 }
3897
3898 void ship_check_player_distance()
3899 {
3900         int idx;
3901
3902         // multiplayer
3903         if (Game_mode & GM_MULTIPLAYER) {
3904                 // if I'm the server, check all non-observer players including myself
3905                 if (MULTIPLAYER_MASTER) {
3906                         // warn all players
3907                         for (idx=0; idx<MAX_PLAYERS; idx++) {
3908                                 if (MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Objects[Net_players[idx].player->objnum].type != OBJ_GHOST) ) {
3909                                         // if bad, blow him up
3910                                         ship_check_player_distance_sub(Net_players[idx].player, idx);
3911                                 }
3912                         }
3913                 }
3914         }
3915         // single player
3916         else {
3917                 // maybe blow him up
3918                 ship_check_player_distance_sub(Player);
3919         }               
3920 }
3921
3922 void observer_process_post(object *objp)
3923 {
3924         SDL_assert(objp->type == OBJ_OBSERVER);
3925
3926         if (Game_mode & GM_MULTIPLAYER) {
3927                 // if I'm just an observer
3928                 if (MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])) {
3929                         float dist = vm_vec_dist_quick(&Player_obj->pos, &vmd_zero_vector);
3930                         // if beyond max dist, reset to 0
3931                         if (dist > PLAYER_MAX_DIST_END) {
3932                                 // set me to zero
3933                                 if ((Player_obj != NULL) && (Player_obj->type != OBJ_GHOST)) {
3934                                         Player_obj->pos = vmd_zero_vector;
3935                                 }
3936                         }
3937                 }
3938         }
3939 }
3940
3941 // reset some physics info when ship's engines goes from disabled->enabled 
3942 void ship_reset_disabled_physics(object *objp, int ship_class)
3943 {
3944         objp->phys_info.flags &= ~(PF_REDUCED_DAMP | PF_DEAD_DAMP);
3945         objp->phys_info.side_slip_time_const = Ship_info[ship_class].damp;
3946 }
3947
3948 // Clear/set the subsystem disrupted flags
3949 void ship_subsys_disrupted_check(ship *sp)
3950 {
3951         ship_subsys *ss;
3952         int engines_disabled=0;
3953         
3954         if ( sp->subsys_disrupted_flags & (1<<SUBSYSTEM_ENGINE) ) {
3955                 engines_disabled=1;
3956         }
3957
3958         sp->subsys_disrupted_flags=0;
3959
3960         ss = GET_FIRST(&sp->subsys_list);
3961         while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
3962                 if ( !timestamp_elapsed(ss->disruption_timestamp) ) {
3963                         sp->subsys_disrupted_flags |= (1<<ss->system_info->type);
3964                 }
3965                 ss = GET_NEXT( ss );
3966         }
3967
3968         if ( engines_disabled ) {
3969                 if ( !(sp->subsys_disrupted_flags & (1<<SUBSYSTEM_ENGINE)) ) {
3970                         if ( !(sp->flags & SF_DISABLED) ) {
3971                                 ship_reset_disabled_physics(&Objects[sp->objnum], sp->ship_info_index);
3972                         }
3973                 }
3974         }
3975 }
3976
3977 // Maybe check ship subsystems for disruption, and set/clear flags
3978 void ship_subsys_disrupted_maybe_check(ship *shipp)
3979 {
3980         if ( timestamp_elapsed(shipp->subsys_disrupted_check_timestamp) ) {
3981                 ship_subsys_disrupted_check(shipp);
3982                 shipp->subsys_disrupted_check_timestamp=timestamp(250);
3983         }
3984 }
3985
3986 // Determine if a given subsystem is disrupted (ie inoperable)
3987 // input:       ss              =>              pointer to ship subsystem
3988 // exit:                1               =>              subsystem is disrupted
3989 //                              0               =>              subsystem is not disrupted
3990 int ship_subsys_disrupted(ship_subsys *ss)
3991 {
3992         if ( !ss ) {
3993                 Int3();         // should never happen, get Alan if it does.
3994                 return 0;
3995         }
3996
3997         if ( timestamp_elapsed(ss->disruption_timestamp) ) {
3998                 return 0;
3999         } else {
4000                 return 1;
4001         }
4002 }
4003
4004 // Disrupt a subsystem (ie make it inoperable for a time)
4005 // input:       ss              =>              ship subsystem to be disrupted
4006 //                              time    =>              time in ms that subsystem should be disrupted
4007 void ship_subsys_set_disrupted(ship_subsys *ss, int time)
4008 {
4009         int time_left=0;
4010
4011         if ( !ss ) {
4012                 Int3();         // should never happen, get Alan if it does.
4013                 return;
4014         }
4015
4016         time_left=timestamp_until(ss->disruption_timestamp);
4017         if ( time_left < 0 ) {
4018                 time_left=0;
4019         }
4020
4021         ss->disruption_timestamp = timestamp(time+time_left);
4022 }
4023
4024 // Determine if a given subsystem is disrupted (ie inoperable)
4025 // input:       sp              =>              pointer to ship containing subsystem
4026 //                              type    =>              type of subsystem (SUBSYSTEM_*)
4027 // exit:                1               =>              subsystem is disrupted
4028 //                              0               =>              subsystem is not disrupted
4029 //
4030 int ship_subsys_disrupted(ship *sp, int type)
4031 {
4032         if ( sp->subsys_disrupted_flags & (1<<type) ) {
4033                 return 1;
4034         } else {
4035                 return 0;
4036         }
4037 }
4038
4039 float Decay_rate = 1.0f / 120.0f;
4040 DCF(lethality_decay, "time in sec to return from 100 to 0")
4041 {
4042         dc_get_arg(ARG_FLOAT);
4043         Decay_rate = Dc_arg_float;
4044 }
4045
4046 float min_lethality = 0.0f;
4047
4048 void lethality_decay(ai_info *aip)
4049 {
4050         float decay_rate = Decay_rate;
4051         aip->lethality -= 100.0f * decay_rate * flFrametime;
4052         aip->lethality = max(-10.0f, aip->lethality);
4053
4054 //      if (aip->lethality < min_lethality) {
4055 //              min_lethality = aip->lethality;
4056 //              mprintf(("new lethality low: %.1f\n", min_lethality));
4057 //      }
4058
4059 #ifndef NDEBUG
4060         if (Objects[Ships[aip->shipnum].objnum].flags & OF_PLAYER_SHIP) {
4061                 if (Framecount % 10 == 0) {
4062                         int num_turrets = 0;
4063                         if ((aip->target_objnum != -1) && (Objects[aip->target_objnum].type == OBJ_SHIP)) {
4064                                 int num_turrets_attacking(object *turret_parent, int target_objnum);
4065                                 num_turrets = num_turrets_attacking(&Objects[aip->target_objnum], Ships[aip->shipnum].objnum);
4066                         }
4067                         nprintf(("lethality", "Player lethality: %.1f, num turrets targeting player: %d\n", aip->lethality, num_turrets));
4068                 }
4069         }
4070 #endif
4071 }
4072
4073 void ship_process_pre(object *objp, float frametime)
4074 {
4075 }
4076
4077 MONITOR( NumShips );    
4078
4079 //      Player ship uses this code, but does a quick out after doing a few things.
4080 // when adding code to this function, decide whether or not a client in a multiplayer game
4081 // needs to execute the code you are adding.  Code which moves things, creates things, etc
4082 // probably doesn't need to be called.  If you don't know -- find Allender!!!
4083 void ship_process_post(object * obj, float frametime)
4084 {
4085         int     num;
4086         ship    *shipp;
4087
4088         if(obj->type != OBJ_SHIP){
4089                 nprintf(("Network","Ignoring non-ship object in ship_process_post()\n"));
4090                 return;
4091         }
4092
4093         MONITOR_INC( NumShips, 1 );     
4094
4095         num = obj->instance;
4096         SDL_assert( num >= 0 && num < MAX_SHIPS);
4097         SDL_assert( obj->type == OBJ_SHIP );
4098         SDL_assert( Ships[num].objnum == OBJ_INDEX(obj));       
4099
4100         shipp = &Ships[num];
4101
4102         shipp->shield_hits = 0;
4103
4104         update_ets(obj, frametime);
4105
4106         afterburners_update(obj, frametime);
4107
4108         ship_subsys_disrupted_maybe_check(shipp);
4109
4110         ship_dying_frame(obj, num);
4111
4112         ship_chase_shield_energy_targets(shipp, obj, frametime);
4113
4114         // AL 1-6-98: record the initial ammo counts for ships, which is used as the max limit for rearming
4115         if ( !(shipp->flags & SF_AMMO_COUNT_RECORDED) ) {
4116                 for ( int i=0; i<MAX_SECONDARY_BANKS; i++ ) {
4117                         if ( red_alert_mission() ) {
4118                                 int max_missiles = get_max_ammo_count_for_bank(shipp->ship_info_index, i, shipp->weapons.secondary_bank_weapons[i]);
4119                                 shipp->weapons.secondary_bank_start_ammo[i] = max_missiles;
4120                         } else {
4121                                 shipp->weapons.secondary_bank_start_ammo[i] = shipp->weapons.secondary_bank_ammo[i];
4122                         }
4123                 }
4124                 shipp->flags |= SF_AMMO_COUNT_RECORDED;
4125         }
4126
4127         if(!(Game_mode & GM_STANDALONE_SERVER)){
4128                 // Plot ship on the radar.  What about multiplayer ships?
4129                 if ( obj != Player_obj )                        // don't plot myself.
4130                         radar_plot_object( obj );
4131
4132                 // MWA -- move the spark code to before the check for multiplayer master
4133                 //      Do ship sparks.  Don't do sparks on my ship (since I cannot see it).  This
4134                 // code will do sparks on other ships in multiplayer though.
4135                 // JAS: Actually in external view, you can see sparks, so I don't do sparks
4136                 // on the Viewer_obj, not Player_obj.
4137                 if ( (obj != Viewer_obj) && timestamp_elapsed(Ships[num].next_hit_spark) )      {
4138                         shipfx_emit_spark(num,-1);      // -1 means choose random spark location
4139                 }
4140
4141                 if ( obj != Viewer_obj )        {
4142                         shipfx_do_damaged_arcs_frame( shipp );
4143                 }
4144
4145                 // JAS - flicker the thruster bitmaps
4146                 ship_do_thruster_frame(shipp,obj,frametime);            
4147         }
4148
4149         ship_auto_repair_frame(num, frametime);
4150
4151         // MWA -- move the spark code to before the check for multiplayer master
4152         //      Do ship sparks.
4153 //      if (timestamp_elapsed(Ships[num].next_hit_spark))       {
4154 //              ship_spark(num);
4155 //              Ships[num].next_hit_spark = timestamp_rand(100,500);
4156 //      }
4157
4158         shipfx_do_lightning_frame(shipp);
4159
4160         // if the ship has an EMP effect active, process it
4161         emp_process_ship(shipp);        
4162
4163         // call the contrail system
4164         ct_ship_process(shipp);
4165
4166         // process engine wash
4167         void engine_wash_ship_process(ship *shipp);
4168         engine_wash_ship_process(shipp);
4169
4170         // update TAG info
4171         if(shipp->tag_left > 0.0f){
4172                 shipp->tag_left -= flFrametime;
4173                 if(shipp->tag_left <= 0.000001f){
4174                         shipp->tag_left = -1.0f;
4175
4176                         mprintf(("Killing TAG for %s\n", shipp->ship_name));
4177                 }
4178         }
4179         
4180         // update level 2 TAG info
4181         if(shipp->level2_tag_left > 0.0f){
4182                 shipp->level2_tag_left -= flFrametime;
4183                 if(shipp->level2_tag_left <= 0.000001f){
4184                         shipp->level2_tag_left = -1.0f;
4185
4186                         mprintf(("Killing level 2 TAG for %s\n", shipp->ship_name));
4187                 }
4188         }
4189         
4190         if ( shipp->flags & SF_ARRIVING && Ai_info[shipp->ai_index].mode != AIM_BAY_EMERGE )    {
4191                 // JAS -- if the ship is warping in, just move it forward at a speed
4192                 // fast enough to move 2x it's radius in SHIP_WARP_TIME seconds.
4193                 shipfx_warpin_frame( obj, frametime );
4194         } else if ( shipp->flags & SF_DEPART_WARP ) {
4195                 // JAS -- if the ship is warping out, just move it forward at a speed
4196                 // fast enough to move 2x it's radius in SHIP_WARP_TIME seconds.
4197                 shipfx_warpout_frame( obj, frametime );
4198         } else {
4199                 //      Do AI.
4200
4201                 // for multiplayer people.  return here if in multiplay and not the host
4202                 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
4203                         return; 
4204
4205                 // MWA -- moved the code to maybe fire swarm missiles to after the check for
4206                 // multiplayer master.  Only single player and multi server needs to do this code
4207                 // this code might call ship_fire_secondary which will send the fire packets
4208                 swarm_maybe_fire_missile(num);
4209
4210                 // maybe fire turret swarm missiles
4211                 void turret_swarm_maybe_fire_missile(int num);
4212                 turret_swarm_maybe_fire_missile(num);
4213
4214                 // maybe fire a corkscrew missile (just like swarmers)
4215                 cscrew_maybe_fire_missile(num);
4216
4217                 // AL 2-19-98: Fire turret for player if it exists
4218                 if ( obj->flags & OF_PLAYER_SHIP ) {
4219                         player_maybe_fire_turret(obj);
4220                 }
4221
4222                 // if single player, check player object is not too far from starting location
4223                 // DKA 5/17/99 check SINGLE and MULTI
4224 //              if ( !(Game_mode & GM_MULTIPLAYER) && (obj == Player_obj) )
4225                 if (obj == Player_obj) {
4226                         ship_check_player_distance();
4227                 }
4228
4229                 // update ship lethality
4230                 if ( Ships[num].ai_index >= 0 ){
4231                         if (!physics_paused && !ai_paused){
4232                                 lethality_decay(&Ai_info[Ships[num].ai_index]);
4233                         }
4234                 }
4235
4236                 // if the ship is a player ship or an observer ship don't need to do AI
4237                 if ( (obj->flags & OF_PLAYER_SHIP) || (obj->type == OBJ_OBSERVER) ) {
4238                         return;
4239                 }
4240
4241                 if ( Ships[num].ai_index >= 0 ){
4242                         if (!physics_paused && !ai_paused){
4243                                 ai_process( obj, Ships[num].ai_index, frametime );
4244                         }
4245                 }
4246         }                       
4247 }
4248
4249
4250 // ------------------------------------------------------------------------
4251 //      ship_set_default_weapons()
4252 //
4253 //      Set the ship level weapons based on the information contained in the ship
4254 // info.  Weapon assignments are checked against the model to ensure the models
4255 // and the ship info weapon data are in synch.
4256 //
4257 //
4258
4259 void ship_set_default_weapons(ship *shipp, ship_info *sip)
4260 {
4261         int                     i;
4262         polymodel       *po;
4263         ship_weapon *swp = &shipp->weapons;
4264
4265         //      Copy primary and secondary weapons from ship_info to ship.
4266         //      Later, this will happen in the weapon loadout screen.
4267         for (i=0; i < MAX_PRIMARY_BANKS; i++){
4268                 swp->primary_bank_weapons[i] = sip->primary_bank_weapons[i];
4269         }
4270
4271         for (i=0; i < MAX_SECONDARY_BANKS; i++){
4272                 swp->secondary_bank_weapons[i] = sip->secondary_bank_weapons[i];
4273         }
4274
4275         // Copy the number of primary and secondary banks to ship, and verify that
4276         // model is in synch
4277         po = model_get( sip->modelnum );
4278
4279         // Primary banks
4280         if ( po->n_guns > sip->num_primary_banks ) {
4281                 SDL_assert(po->n_guns <= MAX_PRIMARY_BANKS);
4282                 Warning(LOCATION, "There are %d primary banks in the model file,\nbut only %d primary banks in ships.tbl for %s\n", po->n_guns, sip->num_primary_banks, sip->name);
4283                 for ( i = sip->num_primary_banks; i < po->n_guns; i++ ) {
4284                         // Make unspecified weapon for bank be a Light Laser
4285                         swp->primary_bank_weapons[i] = weapon_info_lookup(NOX("Light Laser"));
4286                         SDL_assert(swp->primary_bank_weapons[i] >= 0);
4287                 }
4288                 sip->num_primary_banks = po->n_guns;
4289         }
4290         else if ( po->n_guns < sip->num_primary_banks ) {
4291                 Warning(LOCATION, "There are %d primary banks in ships.tbl for %s\nbut only %d primary banks in the model\n", sip->num_primary_banks, sip->name, po->n_guns);
4292                 sip->num_primary_banks = po->n_guns;
4293         }
4294
4295         // Secondary banks
4296         if ( po->n_missiles > sip->num_secondary_banks ) {
4297                 SDL_assert(po->n_missiles <= MAX_SECONDARY_BANKS);
4298                 Warning(LOCATION, "There are %d secondary banks in model,\nbut only %d secondary banks in ships.tbl for %s\n", po->n_missiles, sip->num_secondary_banks, sip->name);
4299                 for ( i = sip->num_secondary_banks; i < po->n_missiles; i++ ) {
4300                         // Make unspecified weapon for bank be a Rockeye Missile
4301                         swp->secondary_bank_weapons[i] = weapon_info_lookup(NOX("Rockeye Missile"));
4302                         SDL_assert(swp->secondary_bank_weapons[i] >= 0);
4303                 }
4304                 sip->num_secondary_banks = po->n_missiles;
4305         }
4306         else if ( po->n_missiles < sip->num_secondary_banks ) {
4307                 Warning(LOCATION, "There are %d secondary banks in ships.tbl for %s,\n but only %d secondary banks in the model.\n", sip->num_secondary_banks, sip->name, po->n_missiles);
4308                 sip->num_secondary_banks = po->n_missiles;
4309         }
4310
4311         swp->num_primary_banks = sip->num_primary_banks;
4312         swp->num_secondary_banks = sip->num_secondary_banks;
4313         for ( i = 0; i < swp->num_secondary_banks; i++ ) {
4314                 if (Fred_running){
4315                         swp->secondary_bank_ammo[i] = 100;
4316                 } else {
4317                         swp->secondary_bank_ammo[i] = sip->secondary_bank_ammo_capacity[i];
4318                 }
4319
4320                 swp->secondary_bank_capacity[i] = sip->secondary_bank_ammo_capacity[i];
4321         }
4322
4323         for ( i = 0; i < MAX_PRIMARY_BANKS; i++ ){
4324                 swp->next_primary_fire_stamp[i] = timestamp(0);
4325         }
4326
4327         for ( i = 0; i < MAX_SECONDARY_BANKS; i++ ){
4328                 swp->next_secondary_fire_stamp[i] = timestamp(0);
4329         }
4330 }
4331
4332
4333 //      A faster version of ship_check_collision that does not do checking at the polygon
4334 //      level.  Just checks to see if a vector will intersect a sphere.
4335 int ship_check_collision_fast( object * obj, object * other_obj, vector * hitpos)
4336 {
4337         int num;
4338         mc_info mc;
4339
4340         SDL_assert( obj->type == OBJ_SHIP );
4341         SDL_assert( obj->instance >= 0 );
4342
4343         num = obj->instance;
4344
4345         ship_model_start(obj);  // are these needed in this fast case? probably not.
4346
4347         mc.model_num = Ships[num].modelnum;     // Fill in the model to check
4348         mc.orient = &obj->orient;                                       // The object's orient
4349         mc.pos = &obj->pos;                                                     // The object's position
4350         mc.p0 = &other_obj->last_pos;                   // Point 1 of ray to check
4351         mc.p1 = &other_obj->pos;                                        // Point 2 of ray to check
4352         mc.flags = MC_ONLY_SPHERE;                              // flags
4353
4354         model_collide(&mc);
4355         if (mc.num_hits)
4356                 *hitpos = mc.hit_point_world;
4357         
4358         ship_model_stop(obj);   // are these needed in this fast case? probably not.
4359
4360         return mc.num_hits;
4361 }
4362
4363 // ensure that the subsys path is at least SUBSYS_PATH_DIST from the 
4364 // second last to last point.
4365 void ship_maybe_fixup_subsys_path(polymodel *pm, int path_num)
4366 {
4367         vector  *v1, *v2, dir;
4368         float           dist;
4369         int             index_1, index_2;
4370
4371         model_path *mp;
4372         mp = &pm->paths[path_num];
4373
4374         SDL_assert(mp != NULL);
4375         SDL_assert(mp->nverts > 1);
4376         
4377         index_1 = 1;
4378         index_2 = 0;
4379
4380         v1 = &mp->verts[index_1].pos;
4381         v2 = &mp->verts[index_2].pos;
4382         
4383         dist = vm_vec_dist(v1, v2);
4384         if ( dist < SUBSYS_PATH_DIST-10 ) {
4385                 vm_vec_normalized_dir(&dir, v2, v1);
4386                 vm_vec_scale_add(v2, v1, &dir, SUBSYS_PATH_DIST);
4387         }
4388 }
4389
4390 // fill in the path_num field inside the model_subsystem struct.  This is an index into
4391 // the pm->paths[] array, which is a path that provides a frontal approach to a subsystem
4392 // (used for attacking purposes)
4393 //
4394 // NOTE: path_num in model_subsystem has the follows the following convention:
4395 //                      > 0     => index into pm->paths[] for model that subsystem sits on
4396 //                      -1              => path is not yet determined (may or may not exist)
4397 //                      -2              => path doesn't yet exist for this subsystem
4398 void ship_set_subsys_path_nums(ship_info *sip, polymodel *pm)
4399 {
4400         int i,j,found_path;
4401
4402         for ( i = 0; i < sip->n_subsystems; i++ ) {
4403                 sip->subsystems[i].path_num = -1;
4404         }
4405
4406         for ( i = 0; i < sip->n_subsystems; i++ ) {
4407                 found_path = 0;
4408                 for ( j = 0; j < pm->n_paths; j++ ) {
4409                         if ( (sip->subsystems[i].subobj_num != -1) && (sip->subsystems[i].subobj_num == pm->paths[j].parent_submodel) ) {
4410                                 found_path = 1;
4411                         } else if ( !SDL_strcasecmp(sip->subsystems[i].subobj_name, pm->paths[j].parent_name) ) {
4412                                 found_path = 1;
4413                         }
4414         
4415                         if ( found_path ) {
4416                                 if ( pm->n_paths > j ) {
4417                                         sip->subsystems[i].path_num = j;
4418                                         ship_maybe_fixup_subsys_path(pm, j);
4419                                         break;
4420                                 }
4421                         }
4422                 }
4423
4424                 // If a path num wasn't located, then set value to -2
4425                 if ( sip->subsystems[i].path_num == -1 )
4426                         sip->subsystems[i].path_num = -2;
4427         }
4428 }
4429
4430 // Determine the path indices (indicies into pm->paths[]) for the paths used for approaching/departing
4431 // a fighter bay on a capital ship.
4432 void ship_set_bay_path_nums(ship_info *sip, polymodel *pm)
4433 {
4434         int     bay_num, i;
4435         char    bay_num_str[3];
4436
4437         if ( pm->ship_bay != NULL ) {
4438                 free(pm->ship_bay);
4439                 pm->ship_bay = NULL;
4440         }
4441
4442         // currently only capital ships have fighter bays
4443         if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
4444                 return;
4445         }
4446
4447         // malloc out storage for the path information
4448         pm->ship_bay = (ship_bay*)malloc(sizeof(ship_bay));
4449         SDL_assert(pm->ship_bay != NULL);
4450
4451         pm->ship_bay->num_paths = 0;
4452         // TODO: determine if zeroing out here is affecting any earlier initializations
4453         pm->ship_bay->arrive_flags = 0; // bitfield, set to 1 when that path number is reserved for an arrival
4454         pm->ship_bay->depart_flags = 0; // bitfield, set to 1 when that path number is reserved for a departure
4455
4456
4457         // iterate through the paths that exist in the polymodel, searching for $bayN pathnames
4458         for ( i = 0; i < pm->n_paths; i++ ) {
4459                 if ( !SDL_strncasecmp(pm->paths[i].name, NOX("$bay"), 4) ) {
4460                         SDL_strlcpy(bay_num_str, pm->paths[i].name+4, sizeof(bay_num_str));
4461                         bay_num = atoi(bay_num_str);
4462                         SDL_assert(bay_num >= 1 && bay_num <= MAX_SHIP_BAY_PATHS);
4463                         pm->ship_bay->paths[bay_num-1] = i;
4464                         pm->ship_bay->num_paths++;
4465                 }
4466         }
4467 }
4468
4469 // Ensure create time for ship is unqiue
4470 void ship_make_create_time_unique(ship *shipp)
4471 {
4472         int             sanity_counter = 0, collision;
4473         ship            *compare_shipp;
4474         ship_obj        *so;
4475         uint            new_create_time;
4476
4477         new_create_time = shipp->create_time;
4478
4479         while (1) {
4480
4481                 if ( sanity_counter++ > 50 ) {
4482                         Int3();
4483                         break;
4484                 }
4485
4486                 collision = 0;
4487
4488                 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
4489                         compare_shipp = &Ships[Objects[so->objnum].instance];
4490
4491                         if ( compare_shipp == shipp ) {
4492                                 continue;
4493                         }
4494
4495                         if ( compare_shipp->create_time == new_create_time ) {
4496                                 new_create_time++;
4497                                 collision = 1;
4498                                 break;
4499                         }
4500                 }
4501
4502                 if ( !collision ) {
4503                         shipp->create_time = new_create_time;
4504                         break;
4505                 }
4506         }
4507 }
4508
4509 int     Ship_subsys_hwm = 0;
4510
4511 void show_ship_subsys_count()
4512 {
4513         object  *objp;
4514         int             count = 0;      
4515
4516         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4517                 if (objp->type == OBJ_SHIP) {
4518                         count += Ship_info[Ships[(int)objp->type].ship_info_index].n_subsystems;
4519                 }
4520         }
4521
4522         //nprintf(("AI", "Num subsystems, high water mark = %i, %i\n", count, Ship_subsys_hwm));
4523
4524         if (count > Ship_subsys_hwm) {
4525                 Ship_subsys_hwm = count;
4526         }
4527 }
4528
4529 //      Returns object index of ship.
4530 //      -1 means failed.
4531 int ship_create(matrix *orient, vector *pos, int ship_type)
4532 {
4533         int                     i, n, objnum, j, k, t;
4534         ship_info       *sip;
4535         ship                    *shipp;
4536
4537         t = ship_get_num_ships();
4538         
4539         // The following check caps the number of ships that can be created.  Because Fred needs
4540         // to create all the ships, regardless of when they arrive/depart, it needs a higher
4541         // limit than FreeSpace.  On release, however, we will reduce it, thus FreeSpace needs
4542         // to check against what this limit will be, otherwise testing the missions before
4543         // release could work fine, yet not work anymore once a release build is made.
4544         if (Fred_running) {
4545                 if (t >= MAX_SHIPS)
4546                         return -1;
4547
4548         } else {
4549                 if (t >= SHIPS_LIMIT) {
4550                         Error(LOCATION, XSTR("There is a limit of %d ships in the mission at once.  Please be sure that you do not have more than %d ships present in the mission at the same time.", 1495), SHIPS_LIMIT, SHIPS_LIMIT );
4551                         return -1;
4552                 }
4553         }
4554
4555         //nprintf(("AI", "Number of ships = %i\n", t));
4556
4557         for (n=0; n<MAX_SHIPS; n++){
4558                 if (Ships[n].objnum == -1){
4559                         break;
4560                 }
4561         }
4562
4563         if (n == MAX_SHIPS){
4564                 return -1;
4565         }
4566
4567         SDL_assert((ship_type >= 0) && (ship_type < Num_ship_types));
4568         sip = &(Ship_info[ship_type]);
4569         shipp = &Ships[n];
4570
4571         //  check to be sure that this ship falls into a ship size category!!!
4572         //  get Allender or Mike if you hit this SDL_assert
4573         SDL_assert( sip->flags & (SIF_SMALL_SHIP | SIF_BIG_SHIP | SIF_CAPITAL | SIF_NO_SHIP_TYPE | SIF_NOT_FLYABLE | SIF_ESCAPEPOD | SIF_SUPERCAP | SIF_DRYDOCK | SIF_KNOSSOS_DEVICE) );
4574
4575         sip->modelnum = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);              // use the highest detail level
4576         shipp->modelnum = sip->modelnum;
4577
4578         // maybe load an optional hud target model
4579         if(strlen(sip->pof_file_hud)){
4580                 // check to see if a "real" ship uses this model. if so, load it up for him so that subsystems are setup properly
4581                 int idx;
4582                 for(idx=0; idx<Num_ship_types; idx++){
4583                         if(!SDL_strcasecmp(Ship_info[idx].pof_file, sip->pof_file_hud)){
4584                                 Ship_info[idx].modelnum = model_load(Ship_info[idx].pof_file, Ship_info[idx].n_subsystems, &Ship_info[idx].subsystems[0]);
4585                         }
4586                 }
4587
4588                 // mow load it for me with no subsystems
4589                 sip->modelnum_hud = model_load(sip->pof_file_hud, 0, NULL);
4590         }
4591
4592         polymodel * pm;
4593         pm = model_get(shipp->modelnum);
4594
4595         ship_copy_subsystem_fixup(sip);
4596
4597         show_ship_subsys_count();
4598
4599         if ( sip->num_detail_levels < pm->n_detail_levels )     {
4600                 Warning(LOCATION, "For ship '%s', detail level\nmismatch (POF needs %d)", sip->name, pm->n_detail_levels );
4601
4602                 for (i=0; i<pm->n_detail_levels; i++ )  {
4603                         sip->detail_distance[i] = 0;
4604                 }
4605         }
4606
4607         for (i=0; i<sip->num_detail_levels; i++ )       {
4608                 pm->detail_depth[i] = i2fl(sip->detail_distance[i]);
4609         }
4610
4611         if ( sip->flags & SIF_NAVBUOY ) {
4612                 // JAS: Nav buoys don't need to do collisions!
4613                 objnum = obj_create(OBJ_SHIP, -1, n, orient, pos, model_get_radius(shipp->modelnum), OF_RENDERS | OF_PHYSICS );
4614         } else {
4615                 objnum = obj_create(OBJ_SHIP, -1, n, orient, pos, model_get_radius(shipp->modelnum), OF_RENDERS | OF_COLLIDES | OF_PHYSICS );
4616         }
4617         SDL_assert( objnum >= 0 );
4618
4619         shipp->ai_index = ai_get_slot(n);
4620         SDL_assert( shipp->ai_index >= 0 );
4621
4622         SDL_snprintf(shipp->ship_name, sizeof(shipp->ship_name), NOX("%s %d"), Ship_info[ship_type].name, n);
4623         ship_set_default_weapons(shipp, sip);   //      Moved up here because ship_set requires that weapon info be valid.  MK, 4/28/98
4624         ship_set(n, objnum, ship_type);
4625
4626         // fill in the path_num field inside the model_subsystem struct.  This is an index into
4627         // the pm->paths[] array, which is a path that provides a frontal approach to a subsystem
4628         // (used for attacking purposes)
4629         //
4630         // NOTE: path_num in model_subsystem has the follows the following convention:
4631         //                      > 0     => index into pm->paths[] for model that subsystem sits on
4632         //                      -1              => path is not yet determined (may or may not exist)
4633         //                      -2              => path doesn't yet exist for this subsystem
4634         ship_set_subsys_path_nums(sip, pm);
4635
4636         // set the path indicies for fighter bays on the ship (currently, only capital ships have fighter bays)
4637         ship_set_bay_path_nums(sip, pm);        
4638
4639         init_ai_object(objnum);
4640         ai_clear_ship_goals( &Ai_info[Ships[n].ai_index] );             // only do this one here.  Can't do it in init_ai because it might wipe out goals in mission file
4641
4642         //ship_set_default_weapons(shipp, sip);
4643
4644         //      Allocate shield and initialize it.
4645         if (pm->shield.ntris) {
4646                 shipp->shield_integrity = (float *)malloc(sizeof(float)*pm->shield.ntris);
4647                 for (i=0; i<pm->shield.ntris; i++)
4648                         shipp->shield_integrity[i] = 1.0f;
4649
4650         } else
4651                 shipp->shield_integrity = NULL;
4652
4653         // fix up references into paths for this ship's model to point to a ship_subsys entry instead
4654         // of a submodel index.  The ship_subsys entry should be the same for *all* instances of the
4655         // same ship.
4656
4657         if ( !(sip->flags & SIF_PATH_FIXUP )) {
4658                 for ( i = 0; i < pm->n_paths; i++ ) {
4659                         for ( j = 0; j < pm->paths[i].nverts; j++ ) {
4660                                 for ( k = 0; k < pm->paths[i].verts[j].nturrets; k++ ) {
4661                                         int ptindex = pm->paths[i].verts[j].turret_ids[k];              // this index is a submodel number (ala bspgen)
4662                                         int index;
4663                                         ship_subsys *ss;
4664
4665                                         // iterate through the ship_subsystems looking for an id that matches
4666                                         index = 0;
4667                                         ss = GET_FIRST(&Ships[n].subsys_list);
4668                                         while ( ss != END_OF_LIST( &Ships[n].subsys_list ) ) {
4669                                                 if ( ss->system_info->subobj_num == ptindex ) {                 // when these are equal, fix up the ref
4670                                                         pm->paths[i].verts[j].turret_ids[k] = index;                            // in path structure to index a ship_subsys
4671                                                         break;                                                                                  
4672                                                 }
4673                                                 index++;
4674                                                 ss = GET_NEXT( ss );
4675                                         }
4676
4677                                         if ( ss == END_OF_LIST(&Ships[n].subsys_list) )
4678                                                 Warning(LOCATION, "Couldn't fix up turret indices in spline path\n\nModel: %s\nPath: %s\nVertex: %d\nTurret model id:%d\n\nThis probably means the turret was not specified in ships.tbl", sip->pof_file, pm->paths[i].name, j, ptindex );
4679                                 }
4680                         }
4681                 }
4682                 sip->flags |= SIF_PATH_FIXUP;
4683         }
4684
4685         // reset the damage record fields (for scoring purposes)
4686         shipp->total_damage_received = 0.0f;
4687    for(i=0;i<MAX_DAMAGE_SLOTS;i++){
4688                 shipp->damage_ship[i] = 0.0f;
4689                 shipp->damage_ship_id[i] = -1;
4690         }
4691
4692         // Add this ship to Ship_obj_list
4693         shipp->ship_list_index = ship_obj_list_add(objnum);
4694
4695         // Set time when ship is created
4696         shipp->create_time = timer_get_milliseconds();
4697
4698         ship_make_create_time_unique(shipp);
4699
4700         // set the team select index to be -1
4701         shipp->ts_index = -1;
4702
4703         shipp->wing_status_wing_index = -1;             // wing index (0-4) in wingman status gauge
4704         shipp->wing_status_wing_pos = -1;               // wing position (0-5) in wingman status gauge
4705
4706         // call the contrail system
4707         ct_ship_create(shipp);
4708
4709         return objnum;
4710 }
4711
4712 // ----------------------------------------------------------------
4713 // ship_model_change()
4714 //
4715 // Change the ship model for a ship to that for ship class 'ship_type'
4716 //
4717 // input:       n                               =>              index of ship in Ships[] array
4718 //                              ship_type       =>              ship class (index into Ship_info[])
4719 //
4720 void ship_model_change(int n, int ship_type)
4721 {
4722         int                     model_num, i;
4723         ship_info       *sip;
4724         ship                    *sp;
4725
4726
4727         SDL_assert( n >= 0 && n < MAX_SHIPS );
4728         sp = &Ships[n];
4729         sip = &(Ship_info[ship_type]);
4730
4731         model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);          // use the highest detail level
4732
4733         // page in nondims
4734         if(!Fred_running){
4735                 model_page_in_textures(model_num, ship_type);
4736         }
4737
4738         Objects[sp->objnum].radius = model_get_radius(model_num);
4739         sip->modelnum = model_num;
4740         sp->modelnum = model_num;
4741
4742         polymodel * pm;
4743         pm = model_get(sp->modelnum);
4744
4745         ship_copy_subsystem_fixup(sip);
4746
4747         if ( sip->num_detail_levels < pm->n_detail_levels )     {
4748                 Warning(LOCATION, "For ship '%s', detail level\nmismatch (POF needs %d)", sip->name, pm->n_detail_levels );
4749
4750                 for (i=0; i<pm->n_detail_levels; i++ )  {
4751                         sip->detail_distance[i] = 0;
4752                 }
4753         }
4754
4755         for (i=0; i<sip->num_detail_levels; i++ )       {
4756                 pm->detail_depth[i] = i2fl(sip->detail_distance[i]);
4757         }
4758 }
4759
4760 // ----------------------------------------------------------------
4761 // change_ship_type()
4762 //
4763 // Change the ship class on a ship, and changing all required information
4764 // for consistency (ie textures, subsystems, weapons, physics)
4765 //
4766 // input:       n                               =>              index of ship in Ships[] array
4767 //                              ship_type       =>              ship class (index into Ship_info[])
4768 //
4769 void change_ship_type(int n, int ship_type)
4770 {
4771         ship_info       *sip;
4772         ship                    *sp;
4773         object          *objp;
4774
4775
4776         SDL_assert( n >= 0 && n < MAX_SHIPS );
4777         sp = &Ships[n];
4778         sip = &(Ship_info[ship_type]);
4779         objp = &Objects[sp->objnum];
4780
4781         // point to new ship data
4782         sp->ship_info_index = ship_type;
4783
4784         ship_model_change(n, ship_type);
4785
4786         // if the subsystem list is not currently empty, then we need to clear it out first.
4787         if ( NOT_EMPTY(&sp->subsys_list) ) {
4788                 ship_subsys *ship_system, *tmp;
4789
4790                 for ( ship_system = GET_FIRST(&sp->subsys_list); ship_system != END_OF_LIST(&sp->subsys_list);  ) {
4791                         tmp = GET_NEXT(ship_system);
4792                         list_remove( &sp->subsys_list, ship_system );
4793                         list_append( &ship_subsys_free_list, ship_system );
4794                         ship_system = tmp;
4795                 }
4796         }
4797         // fix up the subsystems
4798         subsys_set( sp->objnum );
4799
4800         // set the correct hull strength
4801         if (Fred_running) {
4802                 objp->hull_strength = 100.0f;
4803         } else {
4804                 objp->hull_strength = sip->initial_hull_strength;
4805         }
4806
4807         // set the correct shields strength
4808         if (Fred_running) {
4809                 objp->shields[0] = 100.0f;
4810         } else {
4811                 set_shield_strength(objp, sip->shields);
4812         }
4813
4814         sp->afterburner_fuel = sip->afterburner_fuel_capacity;
4815
4816         ship_set_default_weapons(sp, sip);
4817         physics_ship_init(&Objects[sp->objnum]);
4818         ets_init_ship(&Objects[sp->objnum]);
4819         // mwa removed the next line in favor of simply setting the ai_class in AI_info.  ai_object_init
4820         // was trashing mode in ai_info when it was valid due to goals.
4821         //ai_object_init(&Objects[sp->objnum], sp->ai_index);
4822         Ai_info[sp->ai_index].ai_class = sip->ai_class;
4823 }
4824
4825 #ifndef NDEBUG
4826 //      Fire the debug laser
4827 int ship_fire_primary_debug(object *objp)
4828 {
4829         int     i;
4830         ship    *shipp = &Ships[objp->instance];
4831         vector wpos;
4832
4833         if ( !timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[0]) )
4834                 return 0;
4835
4836         // do timestamp stuff for next firing time
4837         shipp->weapons.next_primary_fire_stamp[0] = timestamp(250);
4838
4839         //      Debug code!  Make the single laser fire only one bolt and from the object center!
4840         for (i=0; i<MAX_WEAPONS; i++)
4841                 if (!SDL_strcasecmp(Weapon_info[i].name, NOX("Debug Laser")))
4842                         break;
4843         
4844         vm_vec_add(&wpos, &objp->pos, &(objp->orient.v.fvec) );
4845         if (i != MAX_WEAPONS) {
4846                 int weapon_objnum;
4847                 weapon_objnum = weapon_create( &wpos, &objp->orient, i, OBJ_INDEX(objp), 0 );
4848                 weapon_set_tracking_info(weapon_objnum, OBJ_INDEX(objp), Ai_info[shipp->ai_index].target_objnum);
4849                 return 1;
4850         } else
4851                 return 0;
4852 }
4853 #endif
4854
4855 //      Launch countermeasures from object *objp.  rand_val is used in multiplayer to ensure that all
4856 // clients in the game fire countermeasure the same way
4857 int ship_launch_countermeasure(object *objp, int rand_val)
4858 {
4859         int     fired, check_count, cmeasure_count;
4860         vector  pos;
4861         ship    *shipp;
4862
4863         shipp = &Ships[objp->instance];
4864
4865         // in the case where the server is an observer, he can launch countermeasures unless we do this.
4866         if( objp->type == OBJ_OBSERVER){
4867                 return 0;
4868         }
4869
4870         if ( !timestamp_elapsed(shipp->cmeasure_fire_stamp) ){
4871                 return 0;
4872         }
4873
4874         shipp->cmeasure_fire_stamp = timestamp(CMEASURE_WAIT);  //      Can launch every half second.
4875 #ifndef NDEBUG
4876         if (Weapon_energy_cheat) {
4877                 shipp->cmeasure_count++;
4878         }
4879 #endif
4880
4881         // we might check the count of countermeasures left depending on game state.  Multiplayer clients
4882         // do not need to check any objects other than themselves for the count
4883         fired = -1;
4884         check_count = 1;
4885         if ( MULTIPLAYER_CLIENT && (objp != Player_obj) ){
4886                 check_count = 0;
4887         }
4888
4889         if (check_count && (shipp->cmeasure_count <= 0) ) {
4890                 if ( objp == Player_obj ) {
4891                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No more countermeasure charges.", 485));
4892                         snd_play( &Snds[SND_OUT_OF_MISSLES], 0.0f );
4893                 }
4894
4895                 // if we have a player ship, then send the fired packet anyway so that the player
4896                 // who fired will get his 'out of countermeasures' sound
4897                 cmeasure_count = 0;
4898                 if ( objp->flags & OF_PLAYER_SHIP ){
4899                         goto send_countermeasure_fired;
4900                 }
4901
4902                 return 0;
4903         }
4904
4905         cmeasure_count = shipp->cmeasure_count;
4906         shipp->cmeasure_count--;
4907
4908         vm_vec_scale_add(&pos, &objp->pos, &objp->orient.v.fvec, -objp->radius/2.0f);
4909
4910         // cmeasure_create fires 1 countermeasure.  returns -1 if not fired, otherwise a non-negative
4911         // value
4912         fired = cmeasure_create( objp, &pos, shipp->current_cmeasure, rand_val );
4913
4914         // Play sound effect for counter measure launch
4915         SDL_assert(shipp->current_cmeasure < Num_cmeasure_types);
4916         if ( Cmeasure_info[shipp->current_cmeasure].launch_sound != -1 ) {
4917                 snd_play_3d( &Snds[Cmeasure_info[shipp->current_cmeasure].launch_sound], &pos, &View_position );
4918         }
4919
4920         
4921 send_countermeasure_fired:
4922         // the new way of doing things
4923         // if(Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING){
4924         if(Game_mode & GM_MULTIPLAYER){
4925                 send_NEW_countermeasure_fired_packet( objp, cmeasure_count, fired );
4926         }
4927         // }
4928         // the old way of doing things
4929         //else {
4930          //     if ( MULTIPLAYER_MASTER ){
4931                 //      send_countermeasure_fired_packet( objp, cmeasure_count, fired );
4932                 //}
4933         //}
4934
4935         return (fired>0);               // return 0 if not fired, 1 otherwise
4936 }
4937
4938 // internal function.. see if enough time has elapsed to play fail sound again
4939 int ship_maybe_play_primary_fail_sound()
4940 {
4941         hud_start_flash_weapon(Player_ship->weapons.current_primary_bank);
4942
4943         if ( timestamp_elapsed(Laser_energy_out_snd_timer) ) {
4944                 Laser_energy_out_snd_timer = timestamp(50);
4945                 snd_play( &Snds[SND_OUT_OF_WEAPON_ENERGY]);
4946                 return 1;
4947         }
4948         return 0;
4949 }
4950
4951 // internal function.. see if enough time has elapsed to play fail sound again
4952 int ship_maybe_play_secondary_fail_sound(weapon_info *wip)
4953 {
4954         hud_start_flash_weapon(Player_ship->weapons.num_primary_banks + Player_ship->weapons.current_secondary_bank);
4955
4956         if ( timestamp_elapsed(Missile_out_snd_timer) ) {
4957                 
4958                 if ( wip->wi_flags & WIF_SWARM ) {
4959                         Missile_out_snd_timer = timestamp(500);
4960                 } else {
4961                         Missile_out_snd_timer = timestamp(50);
4962                 }
4963                 snd_play( &Snds[SND_OUT_OF_MISSLES] );
4964                 return 1;
4965         }
4966         return 0;
4967 }
4968
4969 // internal function.. see if weapon for ship can fire based on weapons subystem
4970 // strength.
4971 //
4972 // returns:             1       =>              weapon failed to fire
4973 //                                      0       =>              weapon can fire
4974 int ship_weapon_maybe_fail(ship *sp)
4975 {
4976         int     rval;
4977         float   weapons_subsys_str;
4978
4979         // If playing on lowest skill level, weapons will not fail due to subsystem damage
4980         if ( Game_skill_level == 0 ){
4981                 return 0;
4982         }
4983
4984         rval = 0;
4985         weapons_subsys_str = ship_get_subsystem_strength( sp, SUBSYSTEM_WEAPONS );
4986         if ( weapons_subsys_str < SUBSYS_WEAPONS_STR_FIRE_FAIL ) {
4987                 rval = 1;
4988         }
4989         else if ( weapons_subsys_str < SUBSYS_WEAPONS_STR_FIRE_OK ) {
4990                 // chance to fire depends on weapons subsystem strength
4991                 if ( (frand()-0.2f) > weapons_subsys_str )              
4992                         rval = 1;
4993         }
4994
4995         if (!rval) {
4996                 // is subsystem disrupted?
4997                 if ( ship_subsys_disrupted(sp, SUBSYSTEM_WEAPONS) ) {
4998                         rval=1;
4999                 }
5000         }
5001                 
5002         return rval;
5003 }
5004
5005 // create a moving tracer based upon a weapon which just fired
5006 float t_rad = 0.5f;
5007 float t_len = 10.0f;
5008 float t_vel = 0.2f;
5009 float t_min = 150.0f;
5010 float t_max = 300.0f;
5011 DCF(t_rad, "")
5012 {
5013         dc_get_arg(ARG_FLOAT);
5014         t_rad = Dc_arg_float;
5015 }
5016 DCF(t_len, "")
5017 {
5018         dc_get_arg(ARG_FLOAT);
5019         t_len = Dc_arg_float;
5020 }
5021 DCF(t_vel, "")
5022 {
5023         dc_get_arg(ARG_FLOAT);
5024         t_vel = Dc_arg_float;
5025 }
5026 DCF(t_min, "")
5027 {
5028         dc_get_arg(ARG_FLOAT);
5029         t_min = Dc_arg_float;
5030 }
5031 DCF(t_max, "")
5032 {
5033         dc_get_arg(ARG_FLOAT);
5034         t_max = Dc_arg_float;
5035 }
5036 void ship_fire_tracer(int weapon_objnum)
5037 {
5038         particle_info pinfo;
5039         object *objp = &Objects[weapon_objnum];
5040         weapon_info *wip = &Weapon_info[Weapons[Objects[weapon_objnum].instance].weapon_info_index];
5041
5042         // setup particle info
5043         memset(&pinfo, 0, sizeof(particle_info));
5044         pinfo.pos = objp->pos;
5045         pinfo.vel = objp->phys_info.vel;
5046         vm_vec_scale(&pinfo.vel, t_vel);
5047         pinfo.lifetime = wip->lifetime;
5048         pinfo.rad = t_rad;
5049         pinfo.type = PARTICLE_BITMAP;
5050         pinfo.optional_data = wip->laser_bitmap;
5051         pinfo.tracer_length = t_len;
5052         pinfo.reverse = 0;
5053         pinfo.attached_objnum = -1;
5054         pinfo.attached_sig = 0;
5055
5056         // create the particle
5057         particle_create(&pinfo);
5058 }
5059
5060 //      Multiplicative delay factors for increasing skill levels.
5061 float Ship_fire_delay_scale_hostile[NUM_SKILL_LEVELS] =  {4.0f, 2.5f, 1.75f, 1.25f, 1.0f};
5062 float Ship_fire_delay_scale_friendly[NUM_SKILL_LEVELS] = {2.0f, 1.4f, 1.25f, 1.1f, 1.0f};
5063
5064 int tracers[MAX_SHIPS][4][4];   
5065
5066 // fires a primary weapon for the given object.  It also handles multiplayer cases.
5067 // in multiplayer, the starting network signature, and number of banks fired are sent
5068 // to all the clients in the game. All the info is passed to send_primary at the end of
5069 // the function.  The check_energy parameter (defaults to 1) tells us whether or not
5070 // we should check the energy.  It will be 0 when a multiplayer client is firing an AI
5071 // primary.
5072 int ship_fire_primary(object * obj, int stream_weapons, int force)
5073 {
5074         vector          gun_point, pnt, firing_pos;
5075         int                     n = obj->instance;
5076         ship                    *shipp;
5077         ship_weapon     *swp;
5078         ship_info       *sip;
5079         ai_info         *aip;
5080         int                     weapon, i, j, weapon_objnum;
5081         int                     bank_to_fire, num_fired = 0;    
5082         int                     banks_fired, have_timeout;                              // used for multiplayer to help determine whether or not to send packet
5083         have_timeout = 0;                       // used to help tell us whether or not we need to send a packet
5084         banks_fired = 0;                        // used in multiplayer -- bitfield of banks that were fired
5085
5086         int                     sound_played;   // used to track what sound is played.  If the player is firing two banks
5087                                                                                 // of the same laser, we only want to play one sound
5088         SDL_assert( obj != NULL );
5089
5090         if(obj == NULL){
5091                 return 0;
5092         }
5093
5094         // in the case where the server is an observer, he can fire (which) would be bad - unless we do this.
5095         if( obj->type == OBJ_OBSERVER){
5096                 return 0;
5097         }
5098
5099         SDL_assert( obj->type == OBJ_SHIP );
5100         SDL_assert( n >= 0 );
5101         SDL_assert( Ships[n].objnum == OBJ_INDEX(obj));
5102         if((obj->type != OBJ_SHIP) || (n < 0) || (n >= MAX_SHIPS) || (Ships[n].objnum != OBJ_INDEX(obj))){
5103                 return 0;
5104         }
5105         
5106         shipp = &Ships[n];
5107         swp = &shipp->weapons;
5108
5109         // bogus 
5110         if((shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
5111                 return 0;
5112         }
5113         if((shipp->ai_index < 0) || (shipp->ai_index >= MAX_AI_INFO)){
5114                 return 0;
5115         }
5116         sip = &Ship_info[shipp->ship_info_index];
5117         aip = &Ai_info[shipp->ai_index];
5118
5119         if ( swp->num_primary_banks <= 0 ) {
5120                 return 0;
5121         }
5122
5123         if ( swp->current_primary_bank < 0 ){
5124                 return 0;
5125         }       
5126
5127         sound_played = -1;
5128
5129         // Fire the correct primary bank.  If primaries are linked (SF_PRIMARY_LINKED set), then fire 
5130         // both primary banks.
5131         int     num_primary_banks;
5132
5133         if ( shipp->flags & SF_PRIMARY_LINKED ) {
5134                 num_primary_banks = swp->num_primary_banks;
5135         } else {
5136                 num_primary_banks = min(1, swp->num_primary_banks);
5137         }
5138
5139         SDL_assert(num_primary_banks > 0);
5140         if (num_primary_banks < 1){
5141                 return 0;
5142         }
5143
5144         // if we're firing stream weapons, but the trigger is not down, do nothing
5145         if(stream_weapons && !(shipp->flags & SF_TRIGGER_DOWN)){
5146                 return 0;
5147         }
5148
5149         for ( i = 0; i < num_primary_banks; i++ ) {             
5150                 bank_to_fire = (swp->current_primary_bank+i)%2; // Max supported banks is 2
5151                 
5152                 weapon = swp->primary_bank_weapons[bank_to_fire];
5153                 SDL_assert( weapon >= 0 && weapon < MAX_WEAPONS );              
5154                 if ( (weapon < 0) || (weapon >= MAX_WEAPON_TYPES) ) {
5155                         Int3();         // why would a ship try to fire a weapon that doesn't exist?
5156                         continue;
5157                 }               
5158                 weapon_info* winfo_p = &Weapon_info[weapon];
5159
5160                 // if this is a targeting laser, start it up
5161                 if((winfo_p->wi_flags & WIF_BEAM) && (winfo_p->b_info.beam_type == BEAM_TYPE_C)){
5162                         ship_start_targeting_laser(shipp);
5163                         continue;
5164                 }
5165
5166                 // if we're firing stream weapons and this is a non stream weapon, skip it
5167                 if(stream_weapons && !(winfo_p->wi_flags & WIF_STREAM)){
5168                         continue;
5169                 }
5170                 // if we're firing non stream weapons and this is a stream weapon, skip it
5171                 if(!stream_weapons && (winfo_p->wi_flags & WIF_STREAM)){
5172                         continue;
5173                 }
5174
5175                 // only non-multiplayer clients (single, multi-host) need to do timestamp checking
5176                 if ( !timestamp_elapsed(swp->next_primary_fire_stamp[bank_to_fire]) ) {
5177                         if (timestamp_until(swp->next_primary_fire_stamp[bank_to_fire]) > 5000){
5178                                 swp->next_primary_fire_stamp[bank_to_fire] = timestamp(1000);
5179                         }
5180
5181                         have_timeout = 1;
5182                         continue;
5183                 }
5184
5185                 //nprintf(("AI", "Time = %7.3f, firing %s\n", f2fl(Missiontime), Weapon_info[weapon].name));
5186
5187                 // do timestamp stuff for next firing time
5188                 float next_fire_delay = (float) winfo_p->fire_wait * 1000.0f;
5189                 if (!(obj->flags & OF_PLAYER_SHIP)) {
5190                         if (shipp->team == Ships[Player_obj->instance].team){
5191                                 next_fire_delay *= Ship_fire_delay_scale_friendly[Game_skill_level];
5192                         } else {
5193                                 next_fire_delay *= Ship_fire_delay_scale_hostile[Game_skill_level];
5194                         }
5195                 }
5196                 
5197                 next_fire_delay *= 1.0f + (num_primary_banks - 1) * 0.5f;               //      50% time penalty if banks linked
5198
5199                 //      MK, 2/4/98: Since you probably were allowed to fire earlier, but couldn't fire until your frame interval
5200                 //      rolled around, subtract out up to half the previous frametime.
5201                 //      Note, unless we track whether the fire button has been held down, and not tapped, it's hard to
5202                 //      know how much time to subtract off.  It could be this fire is "late" because the user didn't want to fire.
5203                 if (next_fire_delay > 0.0f) {
5204                         if (obj->flags & OF_PLAYER_SHIP) {
5205                                 int     t = timestamp_until(swp->next_primary_fire_stamp[bank_to_fire]);
5206                                 if (t < 0) {
5207                                         float   tx;
5208
5209                                         tx = (float) t/-1000.0f;
5210                                         if (tx > flFrametime/2.0f){
5211                                                 tx = 1000.0f * flFrametime * 0.7f;
5212                                         }
5213                                         next_fire_delay -= tx;
5214                                 }
5215                                 
5216                                 if ((int) next_fire_delay < 1){
5217                                         next_fire_delay = 1.0f;
5218                                 }
5219                         }
5220
5221                         swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
5222                 }
5223
5224                 // Here is where we check if weapons subsystem is capable of firing the weapon.
5225                 // Note that we can have partial bank firing, if the weapons subsystem is partially
5226                 // functional, which should be cool.            
5227                 if ( ship_weapon_maybe_fail(shipp) && !force) {
5228                         if ( obj == Player_obj ) {
5229                                 if ( ship_maybe_play_primary_fail_sound() ) {
5230                                 }
5231                         }
5232                         continue;
5233                 }               
5234
5235                 polymodel *po = model_get( Ship_info[shipp->ship_info_index].modelnum );
5236                 if ( po->n_guns > 0 ) {
5237                         int num_slots = po->gun_banks[bank_to_fire].num_slots;
5238
5239                         // fail unless we're forcing (energy based primaries)
5240                         if ( (shipp->weapon_energy < num_slots*winfo_p->energy_consumed) && !force) {
5241                                 if ( obj == Player_obj ) {
5242                                         swp->next_primary_fire_stamp[bank_to_fire] = timestamp(swp->next_primary_fire_stamp[bank_to_fire]);
5243                                         if ( ship_maybe_play_primary_fail_sound() ) {
5244                                         }
5245                                 }
5246                                 continue;
5247                         }                       
5248
5249                         // deplete the weapon reserve energy by the amount of energy used to fire the weapon
5250                         shipp->weapon_energy -= num_slots*winfo_p->energy_consumed;
5251                         if(shipp->weapon_energy < 0.0f){
5252                                 shipp->weapon_energy = 0.0f;
5253                         }                       
5254
5255                         // Mark all these weapons as in the same group
5256                         int new_group_id = weapon_create_group_id();
5257                         
5258                         for ( j = 0; j < num_slots; j++ ) {
5259                                 pnt = po->gun_banks[bank_to_fire].pnt[j];
5260                                 vm_vec_unrotate(&gun_point, &pnt, &obj->orient);
5261                                 vm_vec_add(&firing_pos, &gun_point, &obj->pos);
5262
5263                                 // create the weapon -- the network signature for multiplayer is created inside
5264                                 // of weapon_create
5265                                 weapon_objnum = weapon_create( &firing_pos, &obj->orient, weapon, OBJ_INDEX(obj),0, new_group_id );
5266                                 weapon_set_tracking_info(weapon_objnum, OBJ_INDEX(obj), aip->target_objnum, aip->current_target_is_locked, aip->targeted_subsys);                               
5267
5268                                 // create the muzzle flash effect
5269                                 shipfx_flash_create( obj, shipp, &pnt, &obj->orient.v.fvec, 1, weapon );
5270
5271                                 // maybe shudder the ship - if its me
5272                                 if((winfo_p->wi_flags & WIF_SHUDDER) && (obj == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
5273                                         // calculate some arbitrary value between 100
5274                                         // (mass * velocity) / 10
5275                                         game_shudder_apply(500, (winfo_p->mass * winfo_p->max_speed) / 10.0f);
5276                                 }
5277
5278                                 num_fired++;
5279                         }                                               
5280
5281                         banks_fired |= (1<<bank_to_fire);                               // mark this bank as fired.
5282                 }               
5283
5284                 // Only play the weapon fired sound if it hasn't been played yet.  This is to 
5285                 // avoid playing the same sound multiple times when banks are linked with the
5286                 // same weapon.
5287                 if ( sound_played != winfo_p->launch_snd ) {
5288                         sound_played = winfo_p->launch_snd;
5289                         if ( obj == Player_obj ) {
5290                                 if ( winfo_p->launch_snd != -1 ) {
5291                                         weapon_info *wip;
5292                                         ship_weapon *swp;
5293
5294                                         // HACK
5295                                         if(winfo_p->launch_snd == SND_AUTOCANNON_SHOT){
5296                                                 snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE );
5297                                         } else {
5298                                                 snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
5299                                         }
5300         //                              snd_play( &Snds[winfo_p->launch_snd] );
5301
5302                                         swp = &Player_ship->weapons;
5303                                         if (swp->current_primary_bank >= 0) {
5304                                                 wip = &Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]];
5305                                                 joy_ff_play_primary_shoot((int) ((wip->armor_factor + wip->shield_factor * 0.2f) * (wip->damage * wip->damage - 7.5f) * 0.45f + 0.6f) * 10 + 2000);
5306                                         }
5307                                 }
5308                         }
5309                         else {
5310                                 if ( winfo_p->launch_snd != -1 ) {
5311                                         snd_play_3d( &Snds[winfo_p->launch_snd], &obj->pos, &View_position );
5312                                 }
5313                         }
5314                 }               
5315         }       // end for (go to next primary bank)
5316         
5317         // if multiplayer and we're client-side firing, send the packet
5318         // if((Game_mode & GM_MULTIPLAYER) && (Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING)){
5319         if(Game_mode & GM_MULTIPLAYER){
5320                 // if i'm a client, and this is not me, don't send
5321                 if(!(MULTIPLAYER_CLIENT && (shipp != Player_ship))){
5322                         send_NEW_primary_fired_packet( shipp, banks_fired );
5323                 }
5324         }
5325
5326         // post a primary fired event
5327         if(Game_mode & GM_DEMO_RECORD){
5328                 demo_POST_primary_fired(obj, swp->current_primary_bank, shipp->flags & SF_PRIMARY_LINKED);
5329         }
5330
5331    // STATS
5332    if (obj->flags & OF_PLAYER_SHIP) {
5333                 // in multiplayer -- only the server needs to keep track of the stats.  Call the cool
5334                 // function to find the player given the object *.  It had better return a valid player
5335                 // or our internal structure as messed up.
5336                 if( Game_mode & GM_MULTIPLAYER ) {
5337                         if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
5338                                 int player_num;
5339
5340                                 player_num = multi_find_player_by_object ( obj );
5341                                 SDL_assert ( player_num != -1 );
5342
5343                                 Net_players[player_num].player->stats.mp_shots_fired += num_fired;
5344                         }
5345                 } else {
5346                         Player->stats.mp_shots_fired += num_fired;
5347                 }
5348         }
5349
5350         return num_fired;
5351 }
5352
5353 void ship_start_targeting_laser(ship *shipp)
5354 {       
5355         int bank0_laser = 0;
5356         int bank1_laser = 0;
5357
5358         // determine if either of our banks have a targeting laser
5359         if((shipp->weapons.primary_bank_weapons[0] >= 0) && (Weapon_info[shipp->weapons.primary_bank_weapons[0]].wi_flags & WIF_BEAM) && (Weapon_info[shipp->weapons.primary_bank_weapons[0]].b_info.beam_type == BEAM_TYPE_C)){
5360                 bank0_laser = 1;
5361         }
5362         if((shipp->weapons.primary_bank_weapons[1] >= 0) && (Weapon_info[shipp->weapons.primary_bank_weapons[1]].wi_flags & WIF_BEAM) && (Weapon_info[shipp->weapons.primary_bank_weapons[1]].b_info.beam_type == BEAM_TYPE_C)){
5363                 bank1_laser = 1;
5364         }
5365
5366         // if primary banks are linked
5367         if(shipp->flags & SF_PRIMARY_LINKED){
5368                 if(bank0_laser){
5369                         shipp->targeting_laser_bank = 0;
5370                         return;
5371                 } 
5372                 if(bank1_laser){
5373                         shipp->targeting_laser_bank = 1;
5374                         return;
5375                 }
5376         }
5377         // if we only have 1 bank selected
5378         else {
5379                 if(bank0_laser && (shipp->weapons.current_primary_bank == 0)){
5380                         shipp->targeting_laser_bank = 0;
5381                         return;
5382                 }
5383                 if(bank1_laser && (shipp->weapons.current_primary_bank == 1)){
5384                         shipp->targeting_laser_bank = 1;
5385                         return;
5386                 }
5387         }
5388 }
5389
5390 void ship_stop_targeting_laser(ship *shipp)
5391 {
5392         shipp->targeting_laser_bank = -1;
5393         shipp->targeting_laser_objnum = -1;
5394 }
5395
5396 void ship_process_targeting_lasers()
5397 {
5398         beam_fire_info fire_info;
5399         ship_obj *so;
5400         ship *shipp;    
5401         polymodel *m;
5402
5403         // interate over all ships
5404         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5405                 // sanity checks
5406                 if(so->objnum < 0){
5407                         continue;
5408                 }
5409                 if(Objects[so->objnum].type != OBJ_SHIP){
5410                         continue;
5411                 }
5412                 if(Objects[so->objnum].instance < 0){
5413                         continue;
5414                 }
5415                 shipp = &Ships[Objects[so->objnum].instance];
5416
5417                 // if our trigger is no longer down, switch it off
5418                 if(!(shipp->flags & SF_TRIGGER_DOWN)){
5419                         ship_stop_targeting_laser(shipp);
5420                         continue;
5421                 }               
5422
5423                 // if we have a bank to fire - fire it
5424                 if((shipp->targeting_laser_bank >= 0) && (shipp->targeting_laser_bank < 2)){
5425                         // try and get the model
5426                         m = model_get(shipp->modelnum);
5427                         if(m == NULL){
5428                                 continue;
5429                         }
5430
5431                         // fire a targeting laser
5432                         fire_info.accuracy = 0.0f;
5433                         fire_info.beam_info_index = shipp->weapons.primary_bank_weapons[(int)shipp->targeting_laser_bank];
5434                         fire_info.beam_info_override = NULL;
5435                         fire_info.shooter = &Objects[shipp->objnum];
5436                         fire_info.target = NULL;
5437                         fire_info.target_subsys = NULL;
5438                         fire_info.turret = NULL;
5439                         fire_info.targeting_laser_offset = m->gun_banks[(int)shipp->targeting_laser_bank].pnt[0];                       
5440                         shipp->targeting_laser_objnum = beam_fire_targeting(&fire_info);                        
5441
5442                         // hmm, why didn't it fire?
5443                         if(shipp->targeting_laser_objnum < 0){
5444                                 Int3();
5445                                 ship_stop_targeting_laser(shipp);
5446                         }
5447                 }
5448         }
5449 }
5450
5451 //      Attempt to detonate weapon last fired by *shipp.
5452 //      Only used for weapons that support remote detonation.
5453 //      Return true if detonated, else return false.
5454 //      Calls weapon_hit() to detonate weapon.
5455 //      If it's a weapon that spawns particles, those will be released.
5456 int maybe_detonate_weapon(ship_weapon *swp, object *src)
5457 {
5458         int                     objnum = swp->last_fired_weapon_index;
5459         object          *objp;
5460         weapon_info     *wip;
5461
5462         objp = &Objects[objnum];
5463
5464         if (objp->type != OBJ_WEAPON){
5465                 return 0;
5466         }
5467
5468         if ((objp->instance < 0) || (objp->instance > MAX_WEAPONS)){
5469                 return 0;
5470         }
5471
5472         // check to make sure that the weapon to detonate still exists
5473         if ( swp->last_fired_weapon_signature != objp->signature ){
5474                 return 0;
5475         }
5476
5477         SDL_assert(Weapons[objp->instance].weapon_info_index != -1);
5478         wip = &Weapon_info[Weapons[objp->instance].weapon_info_index];
5479
5480         if (wip->wi_flags & WIF_REMOTE) {
5481
5482                 if ((objnum >= 0) && (objnum < MAX_OBJECTS)) {
5483                         int     weapon_sig;
5484
5485                         weapon_sig = objp->signature;
5486
5487                         if (swp->last_fired_weapon_signature == weapon_sig) {                           
5488                                 weapon_detonate(objp);
5489                                 swp->last_fired_weapon_index = -1;
5490
5491                                 /*
5492                                 if (src == Player_obj) {
5493                                         char missile_name[NAME_LENGTH];
5494                                         strcpy(missile_name, wip->name);
5495                                         hud_end_string_at_first_hash_symbol(missile_name);
5496                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Detonated %s!", 486), missile_name);
5497                                 }
5498                                 */
5499
5500                                 return 1;
5501                         }
5502                 }
5503         }
5504
5505         return 0;
5506 }
5507
5508 //      Maybe detonate secondary weapon that's already out.
5509 //      Return true if we detonate it, false if not.
5510 int ship_fire_secondary_detonate(object *obj, ship_weapon *swp)
5511 {
5512         if (swp->last_fired_weapon_index != -1)
5513                 if (timestamp_elapsed(swp->detonate_weapon_time)) {
5514                         object  *first_objp = &Objects[swp->last_fired_weapon_index];
5515                         if (maybe_detonate_weapon(swp, obj)) {
5516                                 //      If dual fire was set, there could be another weapon to detonate.  Scan all weapons.
5517                                 missile_obj     *mo;
5518
5519                                 //nprintf(("AI", "Weapon %i detonated\n", first_objp-Objects));
5520
5521                                 // check for currently locked missiles (highest precedence)
5522                                 for ( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
5523                                         object  *mobjp;
5524                                         SDL_assert(mo->objnum >= 0 && mo->objnum < MAX_OBJECTS);
5525                                         mobjp = &Objects[mo->objnum];
5526                                         if ((mobjp != first_objp) && (mobjp->parent_sig == obj->parent_sig)) {
5527                                                 if (Weapon_info[Weapons[mobjp->instance].weapon_info_index].wi_flags & WIF_REMOTE) {
5528                                                         //nprintf(("AI", "Also detonating weapon %i whose parent is %s\n", mobjp-Objects, Ships[Objects[mobjp->parent].instance].ship_name));
5529                                                         weapon_detonate(mobjp);
5530                                                 }
5531                                         }
5532                                 }
5533                                 
5534                                 return 1;
5535                         }
5536                 }
5537
5538         return 0;
5539 }
5540
5541 // Try to switch to a secondary bank that has ammo
5542 int ship_select_next_valid_secondary_bank(ship_weapon *swp)
5543 {
5544         int cycled=0;
5545
5546         int ns = swp->num_secondary_banks;
5547
5548         if ( ns > 1 ) {
5549                 int i,j=swp->current_secondary_bank+1;
5550                 for (i=0; i<ns; i++) {
5551                         if ( j >= ns ) {
5552                                 j=0;
5553                         }
5554
5555                         if ( swp->secondary_bank_ammo[j] > 0 ) {
5556                                 swp->current_secondary_bank=j;
5557                                 cycled = 1;
5558                                 break;
5559                         }
5560
5561                         j++;
5562                 }
5563         }
5564
5565         return cycled;
5566 }
5567
5568
5569 extern void ai_maybe_announce_shockwave_weapon(object *firing_objp, int weapon_index);
5570
5571 //      Object *obj fires its secondary weapon, if it can.
5572 //      If its most recently fired weapon is a remotely detonatable weapon, detonate it.
5573 //      Returns number of weapons fired.  Note, for swarmers, returns 1 if it is allowed
5574 //      to fire the missiles when allow_swarm is NOT set.  They don't actually get fired on a call here unless allow_swarm is set.
5575 //      When you want to fire swarmers, you call this function with allow_swarm NOT set and frame interval
5576 //      code comes aruond and fires it.
5577 // allow_swarm -> default value is 0... since swarm missiles are fired over several frames,
5578 //                need to avoid firing when normally called
5579 int ship_fire_secondary( object *obj, int allow_swarm )
5580 {
5581         int                     n, weapon, j, bank, have_timeout, starting_bank_count = -1, num_fired;
5582         ushort          starting_sig = 0;
5583         ship                    *shipp;
5584         ship_weapon *swp;
5585         ship_info       *sip;
5586         weapon_info     *wip;
5587         ai_info         *aip;
5588         polymodel       *po;
5589         vector          missile_point, pnt, firing_pos;
5590
5591         SDL_assert( obj != NULL );
5592
5593         // in the case where the server is an observer, he can fire (which would be bad) - unless we do this.
5594         if( obj->type == OBJ_OBSERVER ){
5595                 return 0;
5596         }
5597
5598         // in the case where the object is a ghost (a delayed fire packet from right before he died, for instance)
5599         if( (obj->type == OBJ_GHOST) || (obj->type == OBJ_NONE) ){
5600                 return 0;
5601         }
5602
5603         SDL_assert( obj->type == OBJ_SHIP );
5604         if(obj->type != OBJ_SHIP){
5605                 return 0;
5606         }
5607         n = obj->instance;
5608         SDL_assert( n >= 0 && n < MAX_SHIPS );
5609         if((n < 0) || (n >= MAX_SHIPS)){
5610                 return 0;
5611         }
5612         SDL_assert( Ships[n].objnum == OBJ_INDEX(obj));
5613         if(Ships[n].objnum != OBJ_INDEX(obj)){
5614                 return 0;
5615         }
5616         
5617         shipp = &Ships[n];
5618         swp = &shipp->weapons;
5619         sip = &Ship_info[shipp->ship_info_index];
5620         aip = &Ai_info[shipp->ai_index];
5621
5622         // if no secondary weapons are present on ship, return
5623         if ( swp->num_secondary_banks <= 0 ){
5624                 return 0;
5625         }
5626
5627         // If ship is being repaired/rearmed, it cannot fire missiles
5628         if ( aip->ai_flags & AIF_BEING_REPAIRED ) {
5629                 return 0;
5630         }
5631
5632         num_fired = 0;          // tracks how many missiles actually fired
5633
5634         bank = swp->current_secondary_bank;
5635         if ( bank < 0 ) {
5636                 return 0;
5637         }
5638
5639         weapon = swp->secondary_bank_weapons[bank];
5640         SDL_assert( (swp->secondary_bank_weapons[bank] >= 0) && (swp->secondary_bank_weapons[bank] < MAX_WEAPON_TYPES) );
5641         if((swp->secondary_bank_weapons[bank] < 0) || (swp->secondary_bank_weapons[bank] >= MAX_WEAPON_TYPES)){
5642                 return 0;
5643         }
5644         wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
5645
5646         have_timeout = 0;                       // used to help tell whether or not we have a timeout
5647         if ( MULTIPLAYER_MASTER ) {
5648                 starting_sig = multi_get_next_network_signature( MULTI_SIG_NON_PERMANENT );
5649                 starting_bank_count = swp->secondary_bank_ammo[bank];
5650         }
5651
5652         if (ship_fire_secondary_detonate(obj, swp)) {
5653                 // in multiplayer, master sends a secondary fired packet with starting signature of -1 -- indicates
5654                 // to client code to set the detonate timer to 0.
5655                 if ( MULTIPLAYER_MASTER ) {
5656                         // MWA -- 4/6/98  SDL_assert invalid since the bank count could have gone to 0.
5657                         //SDL_assert(starting_bank_count != 0);
5658                         send_secondary_fired_packet( shipp, 0, starting_bank_count, 1, allow_swarm );
5659                 }
5660         
5661                 //      For all banks, if ok to fire a weapon, make it wait a bit.
5662                 //      Solves problem of fire button likely being down next frame and
5663                 //      firing weapon despite fire causing detonation of existing weapon.
5664                 if (swp->current_secondary_bank >= 0) {
5665                         if (timestamp_elapsed(swp->next_secondary_fire_stamp[bank])){
5666                                 swp->next_secondary_fire_stamp[bank] = timestamp(max((int) flFrametime*3000, 250));
5667                         }
5668                 }
5669                 return 0;
5670         }
5671
5672         if ( swp->current_secondary_bank < 0 ){
5673                 return 0;
5674         }
5675
5676         if ( !timestamp_elapsed(swp->next_secondary_fire_stamp[bank]) && !allow_swarm) {
5677                 if (timestamp_until(swp->next_secondary_fire_stamp[bank]) > 60000){
5678                         swp->next_secondary_fire_stamp[bank] = timestamp(1000);
5679                 }
5680                 have_timeout = 1;
5681                 goto done_secondary;
5682         }
5683
5684         // Ensure if this is a "require-lock" missile, that a lock actually exists
5685         if ( wip->wi_flags & WIF_NO_DUMBFIRE ) {
5686                 if ( aip->current_target_is_locked <= 0 ) {
5687                         if ( obj == Player_obj ) {                      
5688                                 if ( !Weapon_energy_cheat ) {
5689                                         if ((aip->target_objnum != -1) && (vm_vec_dist_quick(&obj->pos, &Objects[aip->target_objnum].pos) > wip->lifetime * wip->max_speed)) {
5690                                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Too far from target to acquire lock", 487));
5691                                         } else {
5692                                                 char missile_name[NAME_LENGTH];
5693                                                 SDL_strlcpy(missile_name, wip->name, sizeof(missile_name));
5694                                                 hud_end_string_at_first_hash_symbol(missile_name);
5695                                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s without a lock", 488), missile_name);
5696                                         }
5697
5698                                         snd_play( &Snds[SND_OUT_OF_MISSLES] );
5699                                         swp->next_secondary_fire_stamp[bank] = timestamp(800);  // to avoid repeating messages
5700                                         return 0;
5701                                 }
5702                         } else {
5703                                 // multiplayer clients should always fire the weapon here, so return only if not
5704                                 // a multiplayer client.
5705                                 if ( !MULTIPLAYER_CLIENT ){
5706                                         return 0;
5707                                 }
5708                         }
5709                 }
5710         }
5711
5712         // if trying to fire a swarm missile, make sure being called from right place
5713         if ( (wip->wi_flags & WIF_SWARM) && !allow_swarm ) {
5714                 SDL_assert(wip->swarm_count > 0);
5715                 if(wip->swarm_count <= 0){
5716                         shipp->num_swarm_missiles_to_fire += SWARM_DEFAULT_NUM_MISSILES_FIRED;
5717                 } else {
5718                         shipp->num_swarm_missiles_to_fire += wip->swarm_count;
5719                 }
5720                 return 1;               //      Note: Missiles didn't get fired, but the frame interval code will fire them.
5721         }
5722
5723         // if trying to fire a corkscrew missile, make sure being called from right place       
5724         if ( (wip->wi_flags & WIF_CORKSCREW) && !allow_swarm ) {
5725                 shipp->num_corkscrew_to_fire = (ubyte)(shipp->num_corkscrew_to_fire + (ubyte)Corkscrew_num_missiles_fired);
5726                 return 1;               //      Note: Missiles didn't get fired, but the frame interval code will fire them.
5727         }       
5728
5729         swp->next_secondary_fire_stamp[bank] = timestamp((int)(Weapon_info[weapon].fire_wait * 1000.0f));       // They can fire 5 times a second
5730
5731         // Here is where we check if weapons subsystem is capable of firing the weapon.
5732         // do only in single plyaer or if I am the server of a multiplayer game
5733         if ( !(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_MASTER ) {
5734                 if ( ship_weapon_maybe_fail(shipp) ) {
5735                         if ( obj == Player_obj ) 
5736                                 if ( ship_maybe_play_secondary_fail_sound(wip) ) {
5737                                         char missile_name[NAME_LENGTH];
5738                                         SDL_strlcpy(missile_name, Weapon_info[weapon].name, sizeof(missile_name));
5739                                         hud_end_string_at_first_hash_symbol(missile_name);
5740                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s due to weapons system damage", 489), missile_name);
5741                                 }
5742                         goto done_secondary;
5743                 }
5744         }
5745
5746         po = model_get( Ship_info[shipp->ship_info_index].modelnum );
5747         if ( po->n_missiles > 0 ) {
5748                 int check_ammo;         // used to tell if we should check ammo counts or not
5749                 int num_slots;
5750
5751                 if ( bank > po->n_missiles ) {
5752                         nprintf(("WARNING","WARNING ==> Tried to fire bank %d, but ship has only %d banks\n", bank+1, po->n_missiles));
5753                         return 0;               // we can make a quick out here!!!
5754                 }
5755
5756                 num_slots = po->missile_banks[bank].num_slots;
5757
5758                 // determine if there is enough ammo left to fire weapons on this bank.  As with primary
5759                 // weapons, we might or might not check ammo counts depending on game mode, who is firing,
5760                 // and if I am a client in multiplayer
5761                 check_ammo = 1;
5762                 if ( MULTIPLAYER_CLIENT && (obj != Player_obj) ){
5763                         check_ammo = 0;
5764                 }
5765
5766                 if ( check_ammo && ( swp->secondary_bank_ammo[bank] <= 0) ) {
5767                         if ( shipp->objnum == OBJ_INDEX(Player_obj) ) {
5768                                 if ( ship_maybe_play_secondary_fail_sound(wip) ) {
5769 //                                      HUD_sourced_printf(HUD_SOURCE_HIDDEN, "No %s missiles left in bank", Weapon_info[swp->secondary_bank_weapons[bank]].name);
5770                                 }
5771                         }
5772                         else {
5773                                 // TODO:  AI switch secondary weapon / re-arm?
5774                         }
5775                         goto done_secondary;
5776                 }
5777
5778                 int start_slot, end_slot;
5779
5780                 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ) {
5781                         start_slot = swp->secondary_next_slot[bank];
5782                         // AL 11-19-97: Ensure enough ammo remains when firing linked secondary weapons
5783                         if ( check_ammo && (swp->secondary_bank_ammo[bank] < 2) ) {
5784                                 end_slot = start_slot;
5785                         } else {
5786                                 end_slot = start_slot+1;
5787                         }
5788                 } else {
5789                         start_slot = swp->secondary_next_slot[bank];
5790                         end_slot = start_slot;
5791                 }
5792
5793                 int pnt_index=start_slot;
5794                 for ( j = start_slot; j <= end_slot; j++ ) {
5795                         int     weapon_num;
5796
5797                         swp->secondary_next_slot[bank]++;
5798                         if ( swp->secondary_next_slot[bank] > (num_slots-1) ){
5799                                 swp->secondary_next_slot[bank] = 0;
5800                         }
5801
5802                         if ( pnt_index >= num_slots ){
5803                                 pnt_index = 0;
5804                         }
5805                         pnt = po->missile_banks[bank].pnt[pnt_index++];
5806                         vm_vec_unrotate(&missile_point, &pnt, &obj->orient);
5807                         vm_vec_add(&firing_pos, &missile_point, &obj->pos);
5808
5809                         if ( Game_mode & GM_MULTIPLAYER ) {
5810                                 SDL_assert( Weapon_info[weapon].subtype == WP_MISSILE );
5811                         }
5812
5813                         // create the weapon -- for multiplayer, the net_signature is assigned inside
5814                         // of weapon_create
5815                         weapon_num = weapon_create( &firing_pos, &obj->orient, weapon, OBJ_INDEX(obj), 0, -1, aip->current_target_is_locked);
5816                         weapon_set_tracking_info(weapon_num, OBJ_INDEX(obj), aip->target_objnum, aip->current_target_is_locked, aip->targeted_subsys);
5817
5818                         // create the muzzle flash effect
5819                         shipfx_flash_create( obj, shipp, &pnt, &obj->orient.v.fvec, 0, weapon );
5820
5821 /*
5822                         if ( weapon_num != -1 )
5823                                 Demo_fire_secondary_requests++; // testing for demo
5824 */
5825                         num_fired++;
5826                         swp->last_fired_weapon_index = weapon_num;
5827                         swp->detonate_weapon_time = timestamp(500);             //      Can detonate 1/2 second later.
5828                         if (weapon_num != -1) {
5829                                 swp->last_fired_weapon_signature = Objects[weapon_num].signature;
5830                         }
5831
5832                         // subtract the number of missiles fired
5833                         if ( Weapon_energy_cheat == 0 ){
5834                                 swp->secondary_bank_ammo[bank]--;
5835                         }
5836                 }
5837         }
5838
5839         if ( obj == Player_obj ) {
5840                 if ( Weapon_info[weapon].launch_snd != -1 ) {
5841                         weapon_info *wip;
5842                         ship_weapon *swp;
5843
5844                         snd_play( &Snds[Weapon_info[weapon].launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
5845                         swp = &Player_ship->weapons;
5846                         if (swp->current_secondary_bank >= 0) {
5847                                 wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
5848                                 if (Player_ship->flags & SF_SECONDARY_DUAL_FIRE){
5849                                         joy_ff_play_secondary_shoot((int) (wip->cargo_size * 2.0f));
5850                                 } else {
5851                                         joy_ff_play_secondary_shoot((int) wip->cargo_size);
5852                                 }
5853                         }
5854                 }
5855
5856         } else {
5857                 if ( Weapon_info[weapon].launch_snd != -1 ) {
5858                         snd_play_3d( &Snds[Weapon_info[weapon].launch_snd], &obj->pos, &View_position );
5859                 }
5860         }
5861
5862 done_secondary:
5863
5864         if(num_fired > 0){
5865                 // if I am the master of a multiplayer game, send a secondary fired packet along with the
5866                 // first network signatures for the newly created weapons.  if nothing got fired, send a failed
5867                 // packet if 
5868                 if ( MULTIPLAYER_MASTER ) {                     
5869                         SDL_assert(starting_sig != 0);
5870                         send_secondary_fired_packet( shipp, starting_sig, starting_bank_count, num_fired, allow_swarm );                        
5871                 }
5872
5873                 // STATS
5874                 if (obj->flags & OF_PLAYER_SHIP) {
5875                         // in multiplayer -- only the server needs to keep track of the stats.  Call the cool
5876                         // function to find the player given the object *.  It had better return a valid player
5877                         // or our internal structure as messed up.
5878                         if( Game_mode & GM_MULTIPLAYER ) {
5879                                 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
5880                                         int player_num;
5881
5882                                         player_num = multi_find_player_by_object ( obj );
5883                                         SDL_assert ( player_num != -1 );
5884
5885                                         Net_players[player_num].player->stats.ms_shots_fired += num_fired;
5886                                 }                               
5887                         } else
5888                                 Player->stats.ms_shots_fired += num_fired;
5889                 }
5890                 
5891                 // maybe announce a shockwave weapon
5892                 ai_maybe_announce_shockwave_weapon(obj, weapon);
5893         }
5894
5895         // AL 3-7-98: Move to next valid secondary bank if out of ammo
5896         if ( (obj->flags & OF_PLAYER_SHIP) && (swp->secondary_bank_ammo[bank] <= 0) ) {
5897                 int fire_wait = (int)(Weapon_info[weapon].fire_wait * 1000.0f);
5898                 if ( ship_select_next_valid_secondary_bank(swp) ) {
5899                         swp->next_secondary_fire_stamp[swp->current_secondary_bank] = max(timestamp(250),timestamp(fire_wait)); //      1/4 second delay until can fire
5900                         if ( obj == Player_obj ) {
5901                                 snd_play( &Snds[SND_SECONDARY_CYCLE] );
5902                         }
5903                 }
5904         }       
5905
5906         return num_fired;
5907 }
5908
5909 // ------------------------------------------------------------------------------
5910 // ship_select_next_primary()
5911 //
5912 //      Return true if a new index gets selected.
5913 //
5914 // parameters:          objp      => pointer to object for ship cycling primary
5915 //                direction => forward == CYCLE_PRIMARY_NEXT, backward == CYCLE_PRIMARY_PREV
5916 //
5917 // NOTE: This code can be called for any arbitrary ship.  HUD messages and sounds are only used
5918 //       for the player ship.
5919 int ship_select_next_primary(object *objp, int direction)
5920 {
5921         ship    *shipp;
5922         ship_weapon *swp;
5923
5924         SDL_assert(objp != NULL);
5925         SDL_assert(objp->type == OBJ_SHIP);
5926         SDL_assert(objp->instance >= 0 && objp->instance < MAX_SHIPS);
5927
5928         shipp = &Ships[objp->instance];
5929         swp = &shipp->weapons;
5930
5931         SDL_assert(direction == CYCLE_PRIMARY_NEXT || direction == CYCLE_PRIMARY_PREV);
5932
5933         switch ( swp->num_primary_banks ) {
5934
5935                 case 0:
5936                         if ( objp == Player_obj ) {
5937                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no primary weapons", 490));
5938                                 gamesnd_play_error_beep();
5939                         }
5940                         return 0;
5941                         break;          
5942
5943                 case 1:
5944                         if ( objp == Player_obj ) {
5945                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has only one primary weapon: %s", 491),Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]].name, swp->current_primary_bank + 1);
5946                                 gamesnd_play_error_beep();
5947                         }
5948                         return 0;
5949                         break;          
5950
5951                 case 2:
5952                         if ( shipp->flags & SF_PRIMARY_LINKED ) {
5953                                 shipp->flags &= ~SF_PRIMARY_LINKED;
5954                                 if ( direction == CYCLE_PRIMARY_NEXT ) {
5955                                         swp->current_primary_bank = 0;
5956                                 } else {
5957                                         swp->current_primary_bank = 1;
5958                                 }
5959                         } else {
5960                                 switch ( swp->current_primary_bank ) {
5961                                         case 0:
5962                                                 if ( direction == CYCLE_PRIMARY_NEXT ) {
5963                                                         swp->current_primary_bank = 1;
5964                                                 } else {
5965                                                         shipp->flags |= SF_PRIMARY_LINKED;
5966                                                 }
5967                                                 break;
5968
5969                                         case 1:
5970                                                 if ( direction == CYCLE_PRIMARY_NEXT ) {
5971                                                         shipp->flags |= SF_PRIMARY_LINKED;
5972                                                 } else {
5973                                                         swp->current_primary_bank = 0;
5974                                                 }
5975                                                 break;
5976
5977                                         default:
5978                                                 Int3(); // should never happen, get Alan if it does
5979                                                 return 0;
5980                                                 break;
5981                                 }
5982                         }
5983                         break;
5984                                         
5985                 default:
5986                         Int3();                         // should never happen, get Alan if it does
5987                         return 0;
5988                         break;
5989         }
5990
5991         if ( objp == Player_obj ) {
5992                 snd_play( &Snds[SND_PRIMARY_CYCLE], 0.0f );
5993         }
5994
5995         ship_primary_changed(shipp);
5996         return 1;
5997 }
5998
5999 // ------------------------------------------------------------------------------
6000 // ship_select_next_secondary() selects the next secondary bank with missles
6001 //
6002 //      returns:                1       => The secondary bank was switched
6003 //                                      0       => The secondary bank stayed the same
6004 //
6005 // If a secondary bank has no missles left, it is skipped.
6006 //
6007 // NOTE: This can be called for an arbitrary ship.  HUD messages and sounds are only used
6008 //                      for the player ship.
6009 int ship_select_next_secondary(object *objp)
6010 {
6011         SDL_assert(objp != NULL);
6012         SDL_assert(objp->type == OBJ_SHIP);
6013         SDL_assert(objp->instance >= 0 && objp->instance < MAX_SHIPS);
6014
6015         int     original_bank, new_bank, i;
6016         ship    *shipp;
6017         ship_weapon *swp;
6018
6019         shipp = &Ships[objp->instance];
6020         swp = &shipp->weapons;
6021
6022         switch ( swp->num_secondary_banks ) {
6023                 case 0:
6024                         if ( objp == Player_obj ) {
6025                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 492));
6026                                 gamesnd_play_error_beep();
6027                         }
6028                         return 0;
6029                         break;
6030
6031                 case 1:
6032                         if ( objp == Player_obj ) {
6033                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has only one secondary weapon: %s", 493), Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]].name, swp->current_secondary_bank + 1);
6034                                 gamesnd_play_error_beep();
6035                         }
6036                         return 0;
6037                         break;
6038
6039                 case 2:
6040                 case 3:
6041                         SDL_assert(swp->current_secondary_bank < swp->num_secondary_banks);
6042                         original_bank = swp->current_secondary_bank;
6043
6044                         for ( i = 1; i < swp->num_secondary_banks; i++ ) {
6045                                 new_bank = (swp->current_secondary_bank+i) % swp->num_secondary_banks;
6046                                 if ( swp->secondary_bank_ammo[new_bank] <= 0 )
6047                                         continue;
6048                                 swp->current_secondary_bank = new_bank;
6049                                 break;
6050                         }
6051
6052                         if ( swp->current_secondary_bank != original_bank ) {
6053                                 if ( objp == Player_obj ) {
6054                                         snd_play( &Snds[SND_SECONDARY_CYCLE], 0.0f );
6055                                 }
6056                                 ship_secondary_changed(shipp);
6057                                 return 1;
6058                         }
6059
6060                         break;
6061
6062                 default:
6063                         Int3(); // should never happen, get Alan if it does
6064                         return 0;
6065                         break;
6066         } // end switch
6067
6068         // If we've reached this point, must have failed
6069         return 0;
6070 }
6071
6072 //      Stuff list of weapon indices for object *objp in list *outlist.
6073 //      Return number of weapons in list.
6074 int get_available_secondary_weapons(object *objp, int *outlist, int *outbanklist)
6075 {
6076         int     count = 0;
6077         int     i;
6078         ship    *shipp;
6079
6080         SDL_assert(objp->type == OBJ_SHIP);
6081         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
6082         shipp = &Ships[objp->instance];
6083
6084         for (i=0; i<shipp->weapons.num_secondary_banks; i++)
6085                 if (shipp->weapons.secondary_bank_ammo[i]) {
6086                         outbanklist[count] = i;
6087                         outlist[count++] = shipp->weapons.secondary_bank_weapons[i];
6088                 }
6089
6090         return count;
6091 }
6092
6093 //      Return the object index of the ship with name *name.
6094 int wing_name_lookup(const char *name, int ignore_count)
6095 {
6096         int i, wing_limit;
6097
6098         if ( Fred_running )
6099                 wing_limit = MAX_WINGS;
6100         else
6101                 wing_limit = num_wings;
6102
6103         if (Fred_running || ignore_count ) {  // current_count not used for Fred..
6104                 for (i=0; i<wing_limit; i++)
6105                         if (Wings[i].wave_count && !SDL_strcasecmp(Wings[i].name, name))
6106                                 return i;
6107
6108         } else {
6109                 for (i=0; i<wing_limit; i++)
6110                         if (Wings[i].current_count && !SDL_strcasecmp(Wings[i].name, name))
6111                                 return i;
6112         }
6113
6114         return -1;
6115 }
6116
6117 // this function is needed in addition to wing_name_lookup because it does a straight lookup without
6118 // caring about how many ships are in the wing, etc.
6119 int wing_lookup(const char *name)
6120 {
6121    int idx;
6122         for(idx=0;idx<num_wings;idx++)
6123                 if(strcmp(Wings[idx].name,name)==0)
6124                    return idx;
6125
6126         return -1;
6127 }
6128
6129 //      Return the index of Ship_info[].name that is *name.
6130 int ship_info_lookup(const char *name)
6131 {
6132         int     i;
6133
6134         for (i=0; i < Num_ship_types; i++)
6135                 if (!SDL_strcasecmp(name, Ship_info[i].name))
6136                         return i;
6137
6138         return -1;
6139 }
6140
6141 //      Return the index of Ship_info[].name which is the *base* ship of a ship copy
6142 int ship_info_base_lookup(int si_index)
6143 {
6144         int     i;
6145         char name[NAME_LENGTH], *p;
6146
6147         SDL_strlcpy( name, Ship_info[si_index].name, sizeof(name) );
6148         p = SDL_strchr( name, '#' );
6149         SDL_assert( p );                                                // get allender -- something bogus with ship copy
6150         *p = '\0';
6151
6152         i = ship_info_lookup( name );
6153         SDL_assert( i != -1 );                          // get allender -- there had better be a base ship!
6154
6155         return i;
6156 }
6157
6158 //      Return the ship index of the ship with name *name.
6159 int ship_name_lookup(const char *name, int inc_players)
6160 {
6161         int     i;
6162
6163         // bogus
6164         if(name == NULL){
6165                 return -1;
6166         }
6167
6168         for (i=0; i<MAX_SHIPS; i++){
6169                 if (Ships[i].objnum >= 0){
6170                         if (Objects[Ships[i].objnum].type == OBJ_SHIP || (Objects[Ships[i].objnum].type == OBJ_START && inc_players)){
6171                                 if (!SDL_strcasecmp(name, Ships[i].ship_name)){
6172                                         return i;
6173                                 }
6174                         }
6175                 }
6176         }
6177         
6178         // couldn't find it
6179         return -1;
6180 }
6181
6182 int ship_type_name_lookup(const char *name)
6183 {
6184         int idx;
6185
6186         // bogus
6187         if(name == NULL){
6188                 return -1;
6189         }
6190
6191         // look through the Ship_type_names array
6192         for(idx=0; idx<MAX_SHIP_TYPE_COUNTS; idx++){
6193                 if(!SDL_strcasecmp(name, Ship_type_names[idx])){
6194                         return idx;
6195                 }
6196         }
6197
6198         // couldn't find it
6199         return -1;
6200 }
6201
6202 // checks the (arrival & departure) state of a ship.  Return values:
6203 // -1: has yet to arrive in mission
6204 //  0: is currently in mission
6205 //  1: has been destroyed, departed, or never existsed
6206 int ship_query_state(char *name)
6207 {
6208         int i;
6209         p_object *objp;
6210
6211         // bogus
6212         if(name == NULL){
6213                 return -1;
6214         }
6215
6216         for (i=0; i<MAX_SHIPS; i++){
6217                 if (Ships[i].objnum >= 0){
6218                         if ((Objects[Ships[i].objnum].type == OBJ_SHIP) || (Objects[Ships[i].objnum].type == OBJ_START)){
6219                                 if (!SDL_strcasecmp(name, Ships[i].ship_name)){
6220                                         return 0;
6221                                 }
6222                         }
6223                 }
6224         }
6225
6226         objp = GET_FIRST(&ship_arrival_list);
6227         while (objp != END_OF_LIST(&ship_arrival_list)) {
6228                 if (!SDL_strcasecmp(name, objp->name)){
6229                         return -1;
6230                 }
6231
6232                 objp = GET_NEXT(objp);
6233         }
6234
6235         return 1;
6236 }
6237
6238 //      Note: This is not a general purpose routine.
6239 //      It is specifically used for targeting.
6240 //      It only returns a subsystem position if it has shields.
6241 //      Return true/false for subsystem found/not found.
6242 //      Stuff vector *pos with absolute position.
6243 // subsysp is a pointer to the subsystem.
6244 int get_subsystem_pos(vector *pos, object *objp, ship_subsys *subsysp)
6245 {
6246         matrix  m;
6247         model_subsystem *psub;
6248         vector  pnt;
6249         ship            *shipp;
6250
6251         SDL_assert(objp->type == OBJ_SHIP);
6252         shipp = &Ships[objp->instance];
6253
6254         SDL_assert ( subsysp != NULL );
6255
6256         psub = subsysp->system_info;
6257         vm_copy_transpose_matrix(&m, &objp->orient);
6258
6259         vm_vec_rotate(&pnt, &psub->pnt, &m);
6260         vm_vec_add2(&pnt, &objp->pos);
6261
6262         if ( pos ){
6263                 *pos = pnt;
6264         }
6265
6266         return 1;
6267 }
6268
6269 //=================================================
6270 // Takes all the angle info from the ship structure and stuffs it
6271 // into the model data so that the model code has all the correct
6272 // angles and stuff that it needs.    This is a poorly designed 
6273 // system that should be re-engineered so that all the model functions
6274 // accept a list of angles and everyone passes them through, but
6275 // that would require some major code revision.
6276 // So, anytime you are using a model that has rotating parts, you
6277 // need to do a ship_model_start before any model_ functions are
6278 // called and a ship_model_stop after you're done.   Even for 
6279 // collision detection and stuff, not just rendering.
6280 // See John for details.
6281
6282 void ship_model_start(object *objp)
6283 {
6284         model_subsystem *psub;
6285         ship            *shipp;
6286         ship_subsys     *pss;
6287
6288         shipp = &Ships[objp->instance];
6289
6290         // First clear all the angles in the model to zero
6291         model_clear_instance(shipp->modelnum);
6292
6293         // Go through all subsystems and bash the model angles for all 
6294         // the subsystems that need it.
6295         for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
6296                 psub = pss->system_info;
6297                 switch (psub->type) {
6298                 case SUBSYSTEM_RADAR:
6299                 case SUBSYSTEM_NAVIGATION:
6300                 case SUBSYSTEM_COMMUNICATION:
6301                 case SUBSYSTEM_UNKNOWN:
6302                 case SUBSYSTEM_ENGINE:
6303                 case SUBSYSTEM_SENSORS:
6304                 case SUBSYSTEM_WEAPONS:
6305                 case SUBSYSTEM_SOLAR:
6306                 case SUBSYSTEM_GAS_COLLECT:
6307                 case SUBSYSTEM_ACTIVATION:
6308                         break;
6309                 case SUBSYSTEM_TURRET:
6310                         SDL_assert( !(psub->flags & MSS_FLAG_ROTATES) ); // Turrets can't rotate!!! See John!
6311                         break;
6312                 default:
6313                         Error(LOCATION, "Illegal subsystem type.\n");
6314                 }
6315
6316
6317                 if ( psub->subobj_num > -1 )    {
6318                         model_set_instance(shipp->modelnum, psub->subobj_num, &pss->submodel_info_1 );
6319                 }
6320
6321                 if ( (psub->subobj_num != psub->turret_gun_sobj) && (psub->turret_gun_sobj >-1) )               {
6322                         model_set_instance(shipp->modelnum, psub->turret_gun_sobj, &pss->submodel_info_2 );
6323                 }
6324
6325         }
6326 }
6327
6328 //==========================================================
6329 // Clears all the instance specific stuff out of the model info
6330 void ship_model_stop(object *objp)
6331 {
6332         ship            *shipp;
6333
6334         shipp = &Ships[objp->instance];
6335
6336         // Then, clear all the angles in the model to zero
6337         model_clear_instance(shipp->modelnum);
6338 }
6339
6340
6341 //==========================================================
6342 // Finds the number of crew points in a ship
6343 int ship_find_num_crewpoints(object *objp)
6344 {
6345         int n = 0;
6346         model_subsystem *psub;
6347         ship            *shipp;
6348         ship_subsys     *pss;
6349
6350         shipp = &Ships[objp->instance];
6351
6352         // Go through all subsystems and record the model angles for all 
6353         // the subsystems that need it.
6354         for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
6355                 psub = pss->system_info;
6356                 switch (psub->type) {
6357                 case SUBSYSTEM_TURRET:
6358                         if ( psub->flags & MSS_FLAG_CREWPOINT )
6359                                 n++; // fall through
6360
6361                 case SUBSYSTEM_RADAR:
6362                 case SUBSYSTEM_NAVIGATION:
6363                 case SUBSYSTEM_COMMUNICATION:
6364                 case SUBSYSTEM_UNKNOWN:
6365                 case SUBSYSTEM_ENGINE:
6366                 case SUBSYSTEM_GAS_COLLECT:
6367                 case SUBSYSTEM_ACTIVATION:
6368                         break;
6369                 default:
6370                         Error(LOCATION, "Illegal subsystem type.\n");
6371                 }
6372         }
6373         return n;
6374 }
6375
6376 //==========================================================
6377 // Finds the number of turrets in a ship
6378 int ship_find_num_turrets(object *objp)
6379 {
6380         int n = 0;
6381         model_subsystem *psub;
6382         ship            *shipp;
6383         ship_subsys     *pss;
6384
6385         shipp = &Ships[objp->instance];
6386
6387         // Go through all subsystems and record the model angles for all 
6388         // the subsystems that need it.
6389         for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
6390                 psub = pss->system_info;
6391                 switch (psub->type) {
6392                 case SUBSYSTEM_TURRET:
6393                         n++; // drop through
6394
6395                 case SUBSYSTEM_RADAR:
6396                 case SUBSYSTEM_NAVIGATION:
6397                 case SUBSYSTEM_COMMUNICATION:
6398                 case SUBSYSTEM_UNKNOWN:
6399                 case SUBSYSTEM_ENGINE:
6400                 case SUBSYSTEM_GAS_COLLECT:
6401                 case SUBSYSTEM_ACTIVATION:
6402                         break;
6403                 default:
6404                         Error(LOCATION, "Illegal subsystem type.\n");
6405                 }
6406         }
6407         return n;
6408 }
6409
6410 //      Modify the matrix orient by the slew angles a.
6411 void compute_slew_matrix(matrix *orient, angles *a)
6412 {
6413         matrix  tmp, tmp2;
6414         angles  t1, t2;
6415
6416         t1 = t2 = *a;
6417         t1.h = 0.0f;    t1.b = 0.0f;
6418         t2.p = 0.0f;    t2.b = 0.0f;
6419
6420         // put in p & b like normal
6421         vm_angles_2_matrix(&tmp, &t1 );
6422         vm_matrix_x_matrix( &tmp2, orient, &tmp);
6423
6424         // Put in heading separately
6425         vm_angles_2_matrix(&tmp, &t2 );
6426         vm_matrix_x_matrix( orient, &tmp2, &tmp );
6427
6428         vm_orthogonalize_matrix(orient);
6429 }
6430
6431 // calculates the eye position for this ship in the global reference frame.  Uses the
6432 // view_positions array in the model.  The 0th element is the noral viewing position.
6433 // the vector of the eye is returned in the parameter 'eye'.  The orientation of the
6434 // eye is returned in orient.  (NOTE: this is kind of bogus for now since non 0th element
6435 // eyes have no defined up vector)
6436 void ship_get_eye( vector *eye_pos, matrix *eye_orient, object *obj )
6437 {
6438         ship *shipp;
6439         polymodel *pm;
6440         eye *ep;
6441         // vector vec;
6442
6443         shipp = &Ships[obj->instance];
6444         pm = model_get( shipp->modelnum );
6445
6446         // check to be sure that we have a view eye to look at.....spit out nasty debug message
6447         if ( pm->n_view_positions == 0 ) {
6448 //              nprintf (("Warning", "No eye position found for model %s.  Find artist to get fixed.\n", pm->filename ));
6449                 *eye_pos = obj->pos;
6450                 *eye_orient = obj->orient;
6451                 return;
6452         }
6453         ep = &(pm->view_positions[0] );
6454
6455         // eye points are stored in an array -- the normal viewing position for a ship is the current_eye_index
6456         // element.
6457         model_find_world_point( eye_pos, &ep->pnt, shipp->modelnum, ep->parent, &obj->orient, &obj->pos );
6458         // if ( shipp->current_eye_index == 0 ) {
6459                 *eye_orient = obj->orient;
6460         //} else {
6461         //      model_find_world_dir( &vec, &ep->norm, shipp->modelnum, ep->parent, &obj->orient, &obj->pos );
6462                 // kind of bogus, but use the objects uvec to avoid totally stupid looking behavior.
6463         //      vm_vector_2_matrix(eye_orient,&vec,&obj->orient.v.uvec,NULL);
6464         //}
6465
6466         //      Modify the orientation based on head orientation.
6467         if ( Viewer_obj == obj ) {
6468                 if ( Viewer_mode & VM_PADLOCK_ANY ) {
6469                         player_get_padlock_orient(eye_orient);
6470                 } else {
6471                         compute_slew_matrix(eye_orient, &Viewer_slew_angles);
6472                 }
6473         }
6474 }
6475
6476 // of attackers to make this decision.
6477 //
6478 // NOTE: This function takes into account how many ships are attacking a subsystem, and will 
6479 //                      prefer an ignored subsystem over a subsystem that is in line of sight, if the in-sight
6480 //                      subsystem is attacked by more than MAX_SUBSYS_ATTACKERS
6481 // input:
6482 //                              sp                                      =>              ship pointer to parent of subsystem
6483 //                              subsys_type             =>              what kind of subsystem this is
6484 //                              attacker_pos    =>              the world coords of the attacker of this subsystem
6485 //
6486 // returns: pointer to subsystem if one found, NULL otherwise
6487 #define MAX_SUBSYS_ATTACKERS 3
6488 ship_subsys *ship_get_best_subsys_to_attack(ship *sp, int subsys_type, vector *attacker_pos)
6489 {
6490         ship_subsys     *ss;
6491         ship_subsys *best_in_sight_subsys, *lowest_attacker_subsys, *ss_return;
6492         int                     lowest_num_attackers, lowest_in_sight_attackers, num_attackers;
6493         vector          gsubpos;
6494         ship_obj                *sop;
6495
6496         lowest_in_sight_attackers = lowest_num_attackers = 1000;
6497         ss_return = best_in_sight_subsys = lowest_attacker_subsys = NULL;
6498
6499         for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
6500                 if ( (ss->system_info->type == subsys_type) && (ss->current_hits > 0) ) {
6501
6502                         // get world pos of subsystem
6503                         vm_vec_unrotate(&gsubpos, &ss->system_info->pnt, &Objects[sp->objnum].orient);
6504                         vm_vec_add2(&gsubpos, &Objects[sp->objnum].pos);
6505                         
6506                         // now find the number of ships attacking this subsystem by iterating through the ships list,
6507                         // and checking if aip->targeted_subsys matches the subsystem we're checking
6508                         num_attackers = 0;
6509                         sop = GET_FIRST(&Ship_obj_list);
6510                         while(sop != END_OF_LIST(&Ship_obj_list)){
6511                                 if ( Ai_info[Ships[Objects[sop->objnum].instance].ai_index].targeted_subsys == ss ) {
6512                                         num_attackers++;
6513                                 }
6514                                 sop = GET_NEXT(sop);
6515                         }
6516
6517                         if ( num_attackers < lowest_num_attackers ) {
6518                                 lowest_num_attackers = num_attackers;
6519                                 lowest_attacker_subsys = ss;
6520                         }
6521
6522                         if ( ship_subsystem_in_sight(&Objects[sp->objnum], ss, attacker_pos, &gsubpos) ) {
6523                                 if ( num_attackers < lowest_in_sight_attackers ) {
6524                                         lowest_in_sight_attackers = num_attackers;
6525                                         best_in_sight_subsys = ss;
6526                                 }
6527                         }
6528                 }
6529         }
6530
6531         if ( best_in_sight_subsys == NULL ) {
6532                 // no subsystems are in sight, so return the subsystem with the lowest # of attackers
6533                 ss_return =  lowest_attacker_subsys;
6534         } else {
6535                 if ( lowest_in_sight_attackers > MAX_SUBSYS_ATTACKERS ) {
6536                         ss_return = lowest_attacker_subsys;
6537                 } else {
6538                         ss_return =  best_in_sight_subsys;
6539                 }
6540         }
6541
6542         return ss_return;
6543 }
6544
6545 // function to return a pointer to the 'nth' ship_subsys structure in a ship's linked list
6546 // of ship_subsys'.
6547 // attacker_pos =>      world pos of attacker (default value NULL).  If value is non-NULL, try
6548 //                                                      to select the best subsystem to attack of that type (using line-of-sight)
6549 //                                                      and based on the number of ships already attacking the subsystem
6550 ship_subsys *ship_get_indexed_subsys( ship *sp, int index, vector *attacker_pos )
6551 {
6552         int count;
6553         ship_subsys *ss;
6554
6555         // first, special code to see if the index < 0.  If so, we are looking for one of several possible
6556         // engines or one of several possible turrets.  If we enter this if statement, we will always return
6557         // something.
6558         if ( index < 0 ) {
6559                 int subsys_type;
6560                 
6561                 subsys_type = -index;
6562                 if ( sp->subsys_info[subsys_type].current_hits == 0.0f )                // if there are no hits, no subsystem to attack.
6563                         return NULL;
6564
6565                 if ( attacker_pos != NULL ) {
6566                         ss = ship_get_best_subsys_to_attack(sp, subsys_type, attacker_pos);
6567                         return ss;
6568                 } else {
6569                         // next, scan the list of subsystems and search for the first subsystem of the particular
6570                         // type which has > 0 hits remaining.
6571                         for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
6572                                 if ( (ss->system_info->type == subsys_type) && (ss->current_hits > 0) )
6573                                         return ss;
6574                         }
6575                 }
6576                 
6577                 Int3();                         // maybe we shouldn't get here, but with possible floating point rounding, I suppose we could
6578                 return NULL;
6579         }
6580
6581
6582         count = 0;
6583         ss = GET_FIRST(&sp->subsys_list);
6584         while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
6585                 if ( count == index )
6586                         return ss;
6587                 count++;
6588                 ss = GET_NEXT( ss );
6589         }
6590         Int3();                 // get allender -- turret ref didn't fixup correctly!!!!
6591         return NULL;
6592 }
6593
6594 //      Given a pointer to a subsystem and an associated object, return the index.
6595 int ship_get_index_from_subsys(ship_subsys *ssp, int objnum, int error_bypass)
6596 {
6597         if (ssp == NULL)
6598                 return -1;
6599         else {
6600                 int     count;
6601                 ship    *shipp;
6602                 ship_subsys     *ss;
6603
6604                 SDL_assert(objnum >= 0);
6605                 SDL_assert(Objects[objnum].instance >= 0);
6606
6607                 shipp = &Ships[Objects[objnum].instance];
6608
6609                 count = 0;
6610                 ss = GET_FIRST(&shipp->subsys_list);
6611                 while ( ss != END_OF_LIST( &shipp->subsys_list ) ) {
6612                         if ( ss == ssp)
6613                                 return count;
6614                         count++;
6615                         ss = GET_NEXT( ss );
6616                 }
6617                 if ( !error_bypass )
6618                         Int3();                 // get allender -- turret ref didn't fixup correctly!!!!
6619                 return -1;
6620         }
6621 }
6622
6623 // function which returns the index number of the ship_subsys parameter
6624 int ship_get_subsys_index(ship *sp, char *ss_name, int error_bypass)
6625 {
6626         int count;
6627         ship_subsys *ss;
6628
6629         count = 0;
6630         ss = GET_FIRST(&sp->subsys_list);
6631         while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
6632                 if ( !SDL_strcasecmp(ss->system_info->subobj_name, ss_name) )
6633                         return count;
6634                 count++;
6635                 ss = GET_NEXT( ss );
6636         }
6637
6638         if (!error_bypass)
6639                 Int3();
6640
6641         return -1;
6642 }
6643
6644 // routine to return the strength of a subsystem.  We keep a total hit tally for all subsystems
6645 // which are similar (i.e. a total for all engines).  These routines will return a number between
6646 // 0.0 and 1.0 which is the relative combined strength of the given subsystem type.  The number
6647 // calculated for the engines is slightly different.  Once an engine reaches < 15% of it's hits, it's
6648 // output drops to that %.  A dead engine has no output.
6649 float ship_get_subsystem_strength( ship *shipp, int type )
6650 {
6651         float strength;
6652         ship_subsys *ssp;
6653
6654         SDL_assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
6655         if ( shipp->subsys_info[type].total_hits == 0.0f )
6656                 return 1.0f;
6657
6658         //      For a dying ship, all subsystem strengths are zero.
6659         if (Objects[shipp->objnum].hull_strength <= 0.0f)
6660                 return 0.0f;
6661
6662         strength = shipp->subsys_info[type].current_hits / shipp->subsys_info[type].total_hits;
6663
6664         if ( strength == 0.0f )         // short circuit 0
6665                 return strength;
6666
6667         if ( (type == SUBSYSTEM_ENGINE) && (strength < 1.0f) ) {
6668                 float percent;
6669
6670                 percent = 0.0f;
6671                 ssp = GET_FIRST(&shipp->subsys_list);
6672                 while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
6673
6674                         if ( ssp->system_info->type == SUBSYSTEM_ENGINE ) {
6675                                 float ratio;
6676
6677                                 ratio = ssp->current_hits / ssp->system_info->max_hits;
6678                                 if ( ratio < ENGINE_MIN_STR )
6679                                         ratio = ENGINE_MIN_STR;
6680
6681                                 percent += ratio;
6682                         }
6683                         ssp = GET_NEXT( ssp );
6684                 }
6685                 strength = percent / (float)shipp->subsys_info[type].num;
6686         }
6687
6688         return strength;
6689 }
6690
6691 // set the strength of a subsystem on a given ship.  The strength passed as a 
6692 // parameter is between 0.0 and 1.0
6693 //
6694 // NOTE: this function was made to be called by the debug function dcf_set_subsys().  If
6695 // you want to use this, be sure that you test it for all cases.
6696 void ship_set_subsystem_strength( ship *shipp, int type, float strength )
6697 {
6698         float total_current_hits, diff;
6699         ship_subsys *ssp;
6700
6701         SDL_assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
6702         if ( shipp->subsys_info[type].total_hits == 0.0f )
6703                 return;
6704
6705         total_current_hits = 0.0f;
6706         ssp = GET_FIRST(&shipp->subsys_list);
6707         while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
6708
6709                 if ( ssp->system_info->type == type ) {
6710                         ssp->current_hits = strength * ssp->system_info->max_hits;
6711                         total_current_hits += ssp->current_hits;
6712                 }
6713                 ssp = GET_NEXT( ssp );
6714         }
6715
6716         // update the objects integrity, needed since we've bashed the strength of a subsysem
6717         diff = total_current_hits - shipp->subsys_info[type].current_hits;
6718         Objects[shipp->objnum].hull_strength += diff;
6719         // fix up the shipp->subsys_info[type] current_hits value
6720         shipp->subsys_info[type].current_hits = total_current_hits;
6721 }
6722
6723 #define         SHIELD_REPAIR_RATE      0.20f                   //      Percent of shield repaired per second.
6724 #define         HULL_REPAIR_RATE                0.15f                   //      Percent of hull repaired per second.
6725 #define         SUBSYS_REPAIR_RATE      0.10f                   // Percent of subsystems repaired per second.
6726
6727 // ==================================================================================
6728 // ship_do_rearm_frame()
6729 //
6730 // function to rearm a ship.  This function gets called from the ai code ai_do_rearm_frame (or
6731 // some function of a similar name).  Returns 1 when ship is fully repaired and rearmed, 0 otherwise
6732 //
6733
6734 #define REARM_NUM_MISSILES_PER_BATCH 4          // how many missiles are dropped in per load sound
6735
6736 int ship_do_rearm_frame( object *objp, float frametime )
6737 {
6738         int                     i, banks_full, subsys_type, subsys_all_ok;
6739         float                   shield_str, repair_delta, repair_allocated;
6740         ship                    *shipp;
6741         ship_weapon     *swp;
6742         ship_info       *sip;
6743         ship_subsys     *ssp;
6744         ai_info         *aip;
6745
6746         shipp = &Ships[objp->instance];
6747         swp = &shipp->weapons;
6748         sip = &Ship_info[shipp->ship_info_index];
6749         aip = &Ai_info[shipp->ai_index];
6750
6751         // AL 10-31-97: Add missing primary weapons to the ship.  This is required since designers
6752         //              want to have ships that start with no primaries, but can get them through
6753         //                                       rearm/repair
6754         if ( swp->num_primary_banks < sip->num_primary_banks ) {
6755                 for ( i = swp->num_primary_banks; i < sip->num_primary_banks; i++ ) {
6756                         swp->primary_bank_weapons[i] = sip->primary_bank_weapons[i];
6757                 }
6758                 swp->num_primary_banks = sip->num_primary_banks;
6759         }
6760         
6761         // AL 12-30-97: Repair broken warp drive
6762         if ( shipp->flags & SF_WARP_BROKEN ) {
6763                 // TODO: maybe do something here like informing player warp is fixed?
6764                 shipp->flags &= ~SF_WARP_BROKEN;
6765         }
6766
6767         // AL 1-16-97: Replenish countermeasures
6768         shipp->cmeasure_count = sip->cmeasure_max;
6769
6770         // Do shield repair here
6771         if ( !(objp->flags & OF_NO_SHIELDS) ) {
6772                 shield_str = get_shield_strength(objp);
6773                 if ( shield_str < sip->shields ) {
6774                         if ( objp == Player_obj ) {
6775                                 player_maybe_start_repair_sound();
6776                         }
6777                         shield_str += sip->shields * frametime * SHIELD_REPAIR_RATE;
6778                         if ( shield_str > sip->shields ) {
6779                                  shield_str = sip->shields;
6780                         }
6781                         set_shield_strength(objp, shield_str);
6782                 }
6783         }
6784
6785         // Repair the ship integrity (subsystems + hull).  This works by applying the repair points
6786         // to the subsystems.  Ships integrity is stored is objp->hull_strength, so that always is 
6787         // incremented by repair_allocated
6788         repair_allocated = sip->initial_hull_strength * frametime * HULL_REPAIR_RATE;
6789
6790 /*
6791         AL 11-24-97: remove increase to hull integrity
6792
6793         objp->hull_strength += repair_allocated;
6794         if ( objp->hull_strength > sip->initial_hull_strength ) {
6795                 repair_allocated -= ( sip->initial_hull_strength - objp->hull_strength);
6796                 objp->hull_strength = sip->initial_hull_strength;
6797         }
6798 */
6799
6800         // check the subsystems of the ship.
6801         subsys_all_ok = 1;
6802         ssp = GET_FIRST(&shipp->subsys_list);
6803         while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
6804
6805                 if ( ssp->current_hits < ssp->system_info->max_hits && repair_allocated > 0 ) {
6806                         subsys_all_ok = 0;
6807                         subsys_type = ssp->system_info->type;
6808
6809                         if ( objp == Player_obj ) {
6810                                 player_maybe_start_repair_sound();
6811                         }
6812                         
6813                         repair_delta = ssp->system_info->max_hits - ssp->current_hits;
6814                         if ( repair_delta > repair_allocated ) {
6815                                 repair_delta = repair_allocated;
6816                         }
6817                         repair_allocated -= repair_delta;
6818                         SDL_assert(repair_allocated >= 0.0f);
6819
6820                         // add repair to current strength of single subsystem
6821                         ssp->current_hits += repair_delta;
6822                         if ( ssp->current_hits > ssp->system_info->max_hits ) {
6823                                 ssp->current_hits = ssp->system_info->max_hits;
6824                         }
6825
6826                         // add repair to aggregate strength of subsystems of that type
6827                         shipp->subsys_info[subsys_type].current_hits += repair_delta;
6828                         if ( shipp->subsys_info[subsys_type].current_hits > shipp->subsys_info[subsys_type].total_hits )
6829                                 shipp->subsys_info[subsys_type].current_hits = shipp->subsys_info[subsys_type].total_hits;
6830
6831                         if ( ssp->current_hits > ssp->system_info->max_hits )
6832                                 ssp->current_hits = ssp->system_info->max_hits;
6833
6834                         // check to see if this subsystem was totally non functional before -- if so, then
6835                         // reset the flags
6836                         if ( (ssp->system_info->type == SUBSYSTEM_ENGINE) && (shipp->flags & SF_DISABLED) ) {
6837                                 shipp->flags &= ~SF_DISABLED;
6838                                 ship_reset_disabled_physics(objp, shipp->ship_info_index);
6839                         }
6840                         break;
6841                 }
6842                 ssp = GET_NEXT( ssp );
6843         }
6844
6845         // now deal with rearming the player.  All secondary weapons have a certain rate at which
6846         // they can be rearmed.  We can rearm multiple banks at once.
6847         banks_full = 0;
6848         if ( subsys_all_ok ) {
6849                 for (i = 0; i < swp->num_secondary_banks; i++ ) {
6850                         if ( swp->secondary_bank_ammo[i] < swp->secondary_bank_start_ammo[i] ) {
6851                                 float rearm_time;
6852
6853                                 if ( objp == Player_obj ) {
6854                                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
6855                                 }
6856
6857                                 if ( timestamp_elapsed(swp->secondary_bank_rearm_time[i]) ) {
6858
6859                                         // Have to do some gymnastics to play the sound effects properly.  There is a
6860                                         // one time sound effect which is the missile loading start, then for each missile
6861                                         // loaded there is a sound effect.  These are only played for the player.
6862                                         //
6863                                         rearm_time = Weapon_info[swp->secondary_bank_weapons[i]].rearm_rate;
6864                                         if ( aip->rearm_first_missile == TRUE ) {
6865                                                 rearm_time *= 3;
6866                                         }
6867
6868                                         swp->secondary_bank_rearm_time[i] = timestamp( (int)(rearm_time * 1000.f) );
6869
6870                                         // Acutal loading of missiles is preceded by a sound effect which is the missile
6871                                         // loading equipment moving into place
6872                                         if ( aip->rearm_first_missile == TRUE ) {
6873                                                 snd_play_3d( &Snds[SND_MISSILE_START_LOAD], &objp->pos, &View_position );
6874                                                 aip->rearm_first_missile = FALSE;
6875
6876                                         } else {
6877                                                 snd_play_3d( &Snds[SND_MISSILE_LOAD], &objp->pos, &View_position );
6878                                                 if (objp == Player_obj)
6879                                                         joy_ff_play_reload_effect();
6880
6881                                                 swp->secondary_bank_ammo[i] += REARM_NUM_MISSILES_PER_BATCH;
6882                                                 if ( swp->secondary_bank_ammo[i] > swp->secondary_bank_start_ammo[i] ) 
6883                                                         swp->secondary_bank_ammo[i] = swp->secondary_bank_start_ammo[i]; 
6884                                         }
6885                                 }
6886
6887                         } else
6888                                 banks_full++;
6889                 }
6890         } // end if (subsys_all_ok)
6891
6892         if ( banks_full == swp->num_secondary_banks ) {
6893                 aip->rearm_first_missile = TRUE;
6894         }
6895
6896         int shields_full = 0;
6897         if ( (objp->flags & OF_NO_SHIELDS) ) {
6898                 shields_full = 1;
6899         } else {
6900                 if ( get_shield_strength(objp) >= sip->shields ) 
6901                         shields_full = 1;
6902         }
6903
6904         // return 1 if at end of subsystem list, hull damage at 0, and shields full and all secondary banks full.
6905 //      if ( ((ssp = END_OF_LIST(&shipp->subsys_list)) != NULL )&&(objp->hull_strength == sip->initial_hull_strength)&&(shields_full) ) {
6906         if ( subsys_all_ok && shields_full ) {
6907
6908                 if ( objp == Player_obj ) {
6909                         player_stop_repair_sound();
6910                 }
6911
6912                 if (!aip->rearm_release_delay)
6913                         aip->rearm_release_delay = timestamp(1200);
6914
6915                 if ( banks_full == swp->num_secondary_banks ) {
6916
6917                         if ( timestamp_elapsed(aip->rearm_release_delay) )
6918                                 return 1;
6919                 }
6920                 else {
6921                         aip->rearm_release_delay = timestamp(1200);
6922                 }
6923         }
6924
6925         return 0;
6926 }
6927
6928 // function which is used to find a repair ship to repair requester_obj.  the way repair ships will work
6929 // is:
6930 // if repair ship present and available, return pointer to that object.
6931 // If repair ship present and busy, possibly return that object if he can satisfy the request soon enough.
6932 // If repair ship present and busy and cannot satisfy request, return NULL to warp a new one in if below max number
6933 // if no repair ship present, return NULL to force a new one to be warped in.
6934 #define MAX_SUPPORT_SHIPS_PER_TEAM              1
6935
6936 object *ship_find_repair_ship( object *requester_obj )
6937 {
6938         object *objp;
6939         ship *requester_ship;
6940         int     num_support_ships, num_available_support_ships;
6941         float   min_dist = 99999.0f;
6942         object  *nearest_support_ship = NULL;
6943         int             support_ships[MAX_SUPPORT_SHIPS_PER_TEAM];
6944
6945         SDL_assert(requester_obj->type == OBJ_SHIP);
6946         SDL_assert((requester_obj->instance >= 0) && (requester_obj->instance < MAX_OBJECTS));
6947
6948         // if support ships are not allowed, then no support ship can repair!
6949         if ( !is_support_allowed(requester_obj) )
6950                 return NULL;
6951
6952         num_support_ships = 0;
6953         num_available_support_ships = 0;
6954
6955         requester_ship = &Ships[requester_obj->instance];
6956         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
6957                 if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD)) {
6958                         ship                    *shipp;
6959                         ship_info       *sip;
6960                         float                   dist;
6961
6962                         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
6963
6964                         shipp = &Ships[objp->instance];
6965                         sip = &Ship_info[shipp->ship_info_index];
6966
6967                         if ( shipp->team != requester_ship->team )
6968                                 continue;
6969
6970                         if ( !(sip->flags & SIF_SUPPORT) )
6971                                 continue;
6972
6973                         // don't deal with dying support ships
6974                         if ( shipp->flags & (SF_DYING | SF_DEPARTING) )
6975                                 continue;
6976
6977                         dist = vm_vec_dist_quick(&objp->pos, &requester_obj->pos);
6978                         support_ships[num_support_ships] = objp-Objects;
6979
6980                         if (!(Ai_info[shipp->ai_index].ai_flags & AIF_REPAIRING)) {
6981                                 num_available_support_ships++;
6982                                 if (dist < min_dist) {
6983                                         min_dist = dist;
6984                                         nearest_support_ship = objp;
6985                                 }
6986                         }
6987
6988                         if ( num_support_ships >= MAX_SUPPORT_SHIPS_PER_TEAM ) {
6989                                 mprintf(("Why is there more than %d support ships in this mission?\n",MAX_SUPPORT_SHIPS_PER_TEAM));
6990                                 break;
6991                         } else {
6992                                 support_ships[num_support_ships] = OBJ_INDEX(objp);
6993                                 num_support_ships++;
6994                         }
6995                 }
6996         }
6997
6998         if (nearest_support_ship != NULL)
6999                 return nearest_support_ship;
7000         else if (num_support_ships >= MAX_SUPPORT_SHIPS_PER_TEAM) {
7001                 SDL_assert(&Objects[support_ships[0]] != NULL);
7002                 return &Objects[support_ships[0]];
7003         } else {
7004                 SDL_assert(num_support_ships < MAX_SUPPORT_SHIPS_PER_TEAM);
7005                 return NULL;
7006         }
7007 }
7008
7009
7010
7011 // -------------------------------------------------------------------------------------------------
7012 // ship_close()
7013 //
7014 // called in game_shutdown() to free malloced memory
7015 //
7016 // NOTE: do not call this function.  It is only called from game_shutdown()
7017 void ship_close()
7018 {
7019         int i;
7020
7021         for (i=0; i<MAX_SHIPS; i++ )    {
7022                 if ( Ships[i].shield_integrity != NULL && Ships[i].objnum != -1 ) {
7023                         free( Ships[i].shield_integrity );
7024                         Ships[i].shield_integrity = NULL;
7025                 }
7026         }
7027
7028         // free memory alloced for subsystem storage
7029         for ( i = 0; i < Num_ship_types; i++ ) {
7030                 if ( Ship_info[i].subsystems != NULL ) {
7031                         free(Ship_info[i].subsystems);
7032                 }
7033         }
7034
7035         // free info from parsed table data
7036         for (i=0; i<MAX_SHIP_TYPES; i++) {
7037                 if(Ship_info[i].type_str != NULL){
7038                         free(Ship_info[i].type_str);
7039                         Ship_info[i].type_str = NULL;
7040                 }
7041                 if(Ship_info[i].maneuverability_str != NULL){
7042                         free(Ship_info[i].maneuverability_str);
7043                         Ship_info[i].maneuverability_str = NULL;
7044                 }
7045                 if(Ship_info[i].armor_str != NULL){
7046                         free(Ship_info[i].armor_str);
7047                         Ship_info[i].armor_str = NULL;
7048                 }
7049                 if(Ship_info[i].manufacturer_str != NULL){
7050                         free(Ship_info[i].manufacturer_str);
7051                         Ship_info[i].manufacturer_str = NULL;
7052                 }
7053                 if(Ship_info[i].desc != NULL){
7054                         free(Ship_info[i].desc);
7055                         Ship_info[i].desc = NULL;
7056                 }
7057                 if(Ship_info[i].tech_desc != NULL){
7058                         free(Ship_info[i].tech_desc);
7059                         Ship_info[i].tech_desc = NULL;
7060                 }
7061                 if(Ship_info[i].ship_length != NULL){
7062                         free(Ship_info[i].ship_length);
7063                         Ship_info[i].ship_length = NULL;
7064                 }
7065                 if(Ship_info[i].gun_mounts != NULL){
7066                         free(Ship_info[i].gun_mounts);
7067                         Ship_info[i].gun_mounts = NULL;
7068                 }
7069                 if(Ship_info[i].missile_banks != NULL){
7070                         free(Ship_info[i].missile_banks);
7071                         Ship_info[i].missile_banks = NULL;
7072                 }
7073         }
7074         
7075         // NOTE: pm->ship_bay is free'd is modelread.cpp, model_unload().
7076
7077                 
7078 }       
7079
7080 // -------------------------------------------------------------------------------------------------
7081 // ship_assign_sound()
7082 //
7083 //      Assign object-linked sound to a particular ship
7084 //
7085 void ship_assign_sound(ship *sp)
7086 {
7087         ship_info       *sip;   
7088         object *objp;
7089         vector engine_pos;
7090         ship_subsys *moveup;
7091
7092         SDL_assert( sp->objnum >= 0 );
7093         if(sp->objnum < 0){
7094                 return;
7095         }
7096         objp = &Objects[sp->objnum];
7097         sip = &Ship_info[sp->ship_info_index];
7098
7099         if ( sip->engine_snd != -1 ) {
7100                 vm_vec_copy_scale(&engine_pos, &objp->orient.v.fvec, -objp->radius/2.0f);               
7101
7102                 obj_snd_assign(sp->objnum, sip->engine_snd, &engine_pos, 1);
7103         }
7104
7105         // if he's got any specific engine subsystems. go for it.       
7106         moveup = GET_FIRST(&sp->subsys_list);
7107         while(moveup != END_OF_LIST(&sp->subsys_list)){
7108                 // check the name of the subsystem
7109                 if(strstr(moveup->system_info->name, "enginelarge")){
7110                         obj_snd_assign(sp->objnum, SND_ENGINE_LOOP_LARGE, &moveup->system_info->pnt, 0);
7111                 } else if(strstr(moveup->system_info->name, "enginehuge")){
7112                         obj_snd_assign(sp->objnum, SND_ENGINE_LOOP_HUGE, &moveup->system_info->pnt, 0);
7113                 }
7114
7115                 // next
7116                 moveup = GET_NEXT(moveup);
7117         }       
7118 }
7119
7120 // -------------------------------------------------------------------------------------------------
7121 // ship_assign_sound_all()
7122 //
7123 //      Assign object-linked sounds to all ships currently in the obj_used_list
7124 //
7125 void ship_assign_sound_all()
7126 {
7127         object *objp;
7128         int idx, has_sounds;
7129
7130         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {           
7131                 if ( objp->type == OBJ_SHIP && Player_obj != objp) {
7132                         has_sounds = 0;
7133
7134                         // check to make sure this guy hasn't got sounds already assigned to him
7135                         for(idx=0; idx<MAX_OBJECT_SOUNDS; idx++){
7136                                 if(objp->objsnd_num[idx] != -1){
7137                                         // skip
7138                                         has_sounds = 1;
7139                                         break;
7140                                 }
7141                         }
7142
7143                         // actually assign the sound
7144                         if(!has_sounds){
7145                                 ship_assign_sound(&Ships[objp->instance]);
7146                         }
7147                 }
7148         }
7149 }
7150
7151
7152 // ---------------------------------------------------------------------------------------
7153 // dcf_set_shield()
7154 //
7155 // Debug console function to set the shield for the player ship
7156 //
7157 DCF(set_shield,"Change player ship shield strength")
7158 {
7159         ship_info       *sip;
7160         
7161         sip = &Ship_info[Ships[Player_obj->instance].ship_info_index];
7162         if ( Dc_command )       {
7163                 dc_get_arg(ARG_FLOAT|ARG_NONE);
7164
7165                 if ( Dc_arg_type & ARG_FLOAT ) {
7166                         if ( Dc_arg_float < 0 ) 
7167                                 Dc_arg_float = 0.0f;
7168                         if ( Dc_arg_float > 1.0 )
7169                                 Dc_arg_float = 1.0f;
7170                         set_shield_strength(Player_obj, Dc_arg_float * sip->shields);
7171                         dc_printf("Shields set to %.2f\n", get_shield_strength(Player_obj) );
7172                 }
7173         }
7174
7175         if ( Dc_help ) {
7176                 dc_printf ("Usage: set_shield [num]\n");
7177                 dc_printf ("[num] --  shield percentage 0.0 -> 1.0 of max\n");
7178                 dc_printf ("with no parameters, displays shield strength\n");
7179                 Dc_status = 0;
7180         }
7181
7182         if ( Dc_status )        {
7183                 dc_printf( "Shields are currently %.2f", get_shield_strength(Player_obj) );
7184         }
7185 }
7186
7187 // ---------------------------------------------------------------------------------------
7188 // dcf_set_hull()
7189 //
7190 // Debug console function to set the hull for the player ship
7191 //
7192 DCF(set_hull, "Change player ship hull strength")
7193 {
7194         ship_info       *sip;
7195         
7196         sip = &Ship_info[Ships[Player_obj->instance].ship_info_index];
7197         if ( Dc_command )       {
7198                 dc_get_arg(ARG_FLOAT|ARG_NONE);
7199
7200                 if ( Dc_arg_type & ARG_FLOAT ) {
7201                         if ( Dc_arg_float < 0 ) 
7202                                 Dc_arg_float = 0.0f;
7203                         if ( Dc_arg_float > 1.0 )
7204                                 Dc_arg_float = 1.0f;
7205                         Player_obj->hull_strength = Dc_arg_float * sip->initial_hull_strength;
7206                         dc_printf("Hull set to %.2f\n", Player_obj->hull_strength );
7207                 }
7208         }
7209
7210         if ( Dc_help ) {
7211                 dc_printf ("Usage: set_hull [num]\n");
7212                 dc_printf ("[num] --  hull percentage 0.0 -> 1.0 of max\n");
7213                 dc_printf ("with no parameters, displays hull strength\n");
7214                 Dc_status = 0;
7215         }
7216
7217         if ( Dc_status )        {
7218                 dc_printf( "Hull is currently %.2f", Player_obj->hull_strength );
7219         }
7220 }
7221
7222 // ---------------------------------------------------------------------------------------
7223 // dcf_set_subsys()
7224 //
7225 // Debug console function to set the strength of a particular subsystem
7226 //
7227 //XSTR:OFF
7228 DCF(set_subsys, "Set the strength of a particular subsystem on player ship" )
7229 {
7230         if ( Dc_command )       {
7231                 dc_get_arg(ARG_STRING);
7232                 if ( !SDL_strcasecmp( Dc_arg, "weapons" ))      {
7233                         dc_get_arg(ARG_FLOAT);
7234                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7235                                 Dc_help = 1;
7236                         } else {
7237                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_WEAPONS, Dc_arg_float );
7238                         } 
7239                 } else if ( !SDL_strcasecmp( Dc_arg, "engine" ))        {
7240                         dc_get_arg(ARG_FLOAT);
7241                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7242                                 Dc_help = 1;
7243                         } else {
7244                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_ENGINE, Dc_arg_float );
7245                                 if ( Dc_arg_float < ENGINE_MIN_STR )    {
7246                                         Player_ship->flags |= SF_DISABLED;                              // add the disabled flag
7247                                 } else {
7248                                         Player_ship->flags &= (~SF_DISABLED);                           // add the disabled flag
7249                                 }
7250                         } 
7251                 } else if ( !SDL_strcasecmp( Dc_arg, "sensors" ))       {
7252                         dc_get_arg(ARG_FLOAT);
7253                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7254                                 Dc_help = 1;
7255                         } else {
7256                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_SENSORS, Dc_arg_float );
7257                         } 
7258                 } else if ( !SDL_strcasecmp( Dc_arg, "communication" )) {
7259                         dc_get_arg(ARG_FLOAT);
7260                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7261                                 Dc_help = 1;
7262                         } else {
7263                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_COMMUNICATION, Dc_arg_float );
7264                         } 
7265                 } else if ( !SDL_strcasecmp( Dc_arg, "navigation" ))    {
7266                         dc_get_arg(ARG_FLOAT);
7267                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7268                                 Dc_help = 1;
7269                         } else {
7270                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_NAVIGATION, Dc_arg_float );
7271                         } 
7272                 } else if ( !SDL_strcasecmp( Dc_arg, "radar" )) {
7273                         dc_get_arg(ARG_FLOAT);
7274                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
7275                                 Dc_help = 1;
7276                         } else {
7277                                 ship_set_subsystem_strength( Player_ship, SUBSYSTEM_RADAR, Dc_arg_float );
7278                         } 
7279                 } else {
7280                         // print usage
7281                         Dc_help = 1;
7282                 }
7283         }
7284
7285         if ( Dc_help )  {
7286                 dc_printf( "Usage: set_subsys type X\nWhere X is value between 0 and 1.0, and type can be:\n" );
7287                 dc_printf( "weapons\n" );
7288                 dc_printf( "engine\n" );
7289                 dc_printf( "sensors\n" );
7290                 dc_printf( "communication\n" );
7291                 dc_printf( "navigation\n" );
7292                 dc_printf( "radar\n" );
7293                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
7294         }
7295 }
7296 //XSTR:ON
7297
7298 // console function to toggle whether auto-repair for subsystems is active
7299 #ifndef NDEBUG
7300 DCF_BOOL( auto_repair, Ship_auto_repair );
7301 #endif
7302
7303 // two functions to keep track of counting ships of particular types.  Maybe we should be rolling this
7304 // thing into the stats section??  The first function adds a ship of a particular type to the overall
7305 // count of ships of that type (called from MissionParse.cpp).  The second function adds to the kill total
7306 // of ships of a particular type.  Note that we use the ship_info flags structure member to determine
7307 // what is happening.
7308 void ship_add_ship_type_count( int ship_info_flag, int num )
7309 {
7310         if ( ship_info_flag & SIF_CARGO )
7311                 Ship_counts[SHIP_TYPE_CARGO].total += num;
7312         else if ( (ship_info_flag & SIF_FIGHTER) || (ship_info_flag & SIF_BOMBER) )
7313                 Ship_counts[SHIP_TYPE_FIGHTER_BOMBER].total += num;
7314         else if ( ship_info_flag & SIF_CRUISER )
7315                 Ship_counts[SHIP_TYPE_CRUISER].total += num;
7316         else if ( ship_info_flag & SIF_CORVETTE )
7317                 Ship_counts[SHIP_TYPE_CORVETTE].total += num;
7318         else if ( ship_info_flag & SIF_GAS_MINER )
7319                 Ship_counts[SHIP_TYPE_GAS_MINER].total += num;
7320         else if ( ship_info_flag & SIF_AWACS )
7321                 Ship_counts[SHIP_TYPE_AWACS].total += num;
7322         else if ( ship_info_flag & SIF_FREIGHTER )
7323                 Ship_counts[SHIP_TYPE_FREIGHTER].total += num;
7324         else if ( ship_info_flag & SIF_CAPITAL )
7325                 Ship_counts[SHIP_TYPE_CAPITAL].total += num;
7326         else if ( ship_info_flag & SIF_TRANSPORT )
7327                 Ship_counts[SHIP_TYPE_TRANSPORT].total += num;
7328         else if ( ship_info_flag & SIF_SUPPORT )
7329                 Ship_counts[SHIP_TYPE_REPAIR_REARM].total += num;
7330         else if ( ship_info_flag & SIF_NO_SHIP_TYPE )
7331                 Ship_counts[SHIP_TYPE_NONE].total += num;
7332         else if ( ship_info_flag & SIF_NAVBUOY ) {
7333                 Ship_counts[SHIP_TYPE_NAVBUOY].total += num;
7334         } else if ( ship_info_flag & SIF_SENTRYGUN ) {
7335                 Ship_counts[SHIP_TYPE_SENTRYGUN].total += num;
7336         } else if ( ship_info_flag & SIF_ESCAPEPOD ) {
7337                 Ship_counts[SHIP_TYPE_ESCAPEPOD].total += num;
7338         } else if ( ship_info_flag & SIF_SUPERCAP ) {
7339                 Ship_counts[SHIP_TYPE_SUPERCAP].total += num;
7340         } else if ( ship_info_flag & SIF_DRYDOCK ) {
7341                 Ship_counts[SHIP_TYPE_DRYDOCK].total += num;
7342         } else if ( ship_info_flag & SIF_KNOSSOS_DEVICE){
7343                 Ship_counts[SHIP_TYPE_KNOSSOS_DEVICE].total += num;
7344         }
7345         else
7346                 Int3();         //get allender -- unknown ship type
7347 }
7348
7349 void ship_add_ship_type_kill_count( int ship_info_flag )
7350 {
7351         if ( ship_info_flag & SIF_CARGO )
7352                 Ship_counts[SHIP_TYPE_CARGO].killed++;
7353         else if ( (ship_info_flag & SIF_FIGHTER) || (ship_info_flag & SIF_BOMBER) )
7354                 Ship_counts[SHIP_TYPE_FIGHTER_BOMBER].killed++;
7355         else if ( ship_info_flag & SIF_CRUISER )
7356                 Ship_counts[SHIP_TYPE_CRUISER].killed++;
7357         else if ( ship_info_flag & SIF_CORVETTE )
7358                 Ship_counts[SHIP_TYPE_CORVETTE].killed++;
7359         else if ( ship_info_flag & SIF_AWACS )
7360                 Ship_counts[SHIP_TYPE_AWACS].killed++;
7361         else if ( ship_info_flag & SIF_GAS_MINER )
7362                 Ship_counts[SHIP_TYPE_GAS_MINER].killed++;
7363         else if ( ship_info_flag & SIF_FREIGHTER )
7364                 Ship_counts[SHIP_TYPE_FREIGHTER].killed++;
7365         else if ( ship_info_flag & SIF_CAPITAL )
7366                 Ship_counts[SHIP_TYPE_CAPITAL].killed++;
7367         else if ( ship_info_flag & SIF_TRANSPORT )
7368                 Ship_counts[SHIP_TYPE_TRANSPORT].killed++;
7369         else if ( ship_info_flag & SIF_SUPPORT )
7370                 Ship_counts[SHIP_TYPE_REPAIR_REARM].killed++;
7371         else if ( ship_info_flag & SIF_SENTRYGUN )
7372                 Ship_counts[SHIP_TYPE_SENTRYGUN].killed++;
7373         else if ( ship_info_flag & SIF_ESCAPEPOD )
7374                 Ship_counts[SHIP_TYPE_ESCAPEPOD].killed++;
7375         else if ( ship_info_flag & SIF_NO_SHIP_TYPE )
7376                 Ship_counts[SHIP_TYPE_NONE].killed++;
7377         else if ( ship_info_flag & SIF_SUPERCAP ) 
7378                 Ship_counts[SHIP_TYPE_SUPERCAP].killed++;
7379         else if ( ship_info_flag & SIF_DRYDOCK ) 
7380                 Ship_counts[SHIP_TYPE_DRYDOCK].killed++;
7381         else if ( ship_info_flag & SIF_KNOSSOS_DEVICE )
7382                 Ship_counts[SHIP_TYPE_KNOSSOS_DEVICE].killed++;
7383         else
7384                 Int3();         //get allender -- unknown ship type
7385 }
7386
7387 int ship_query_general_type(int ship)
7388 {
7389         return ship_query_general_type(&Ships[ship]);
7390 }
7391
7392 int ship_query_general_type(ship *shipp)
7393 {
7394         int flags;
7395
7396         flags = Ship_info[shipp->ship_info_index].flags;
7397         switch (flags & SIF_ALL_SHIP_TYPES) {
7398                 case SIF_CARGO:
7399                         return SHIP_TYPE_CARGO;
7400
7401                 case SIF_FIGHTER:
7402                 case SIF_BOMBER:
7403                         return SHIP_TYPE_FIGHTER_BOMBER;
7404
7405                 case SIF_CRUISER:
7406                         return SHIP_TYPE_CRUISER;
7407
7408                 case SIF_FREIGHTER:
7409                         return SHIP_TYPE_FREIGHTER;
7410
7411                 case SIF_CAPITAL:
7412                         return SHIP_TYPE_CAPITAL;
7413
7414                 case SIF_TRANSPORT:
7415                         return SHIP_TYPE_TRANSPORT;
7416
7417                 case SIF_NO_SHIP_TYPE:
7418                         return SHIP_TYPE_NONE;
7419
7420                 case SIF_SUPPORT:
7421                         return SHIP_TYPE_REPAIR_REARM;
7422
7423                 case SIF_NAVBUOY:
7424                         return SHIP_TYPE_NAVBUOY;
7425
7426                 case SIF_SENTRYGUN:
7427                         return SHIP_TYPE_SENTRYGUN;
7428
7429                 case SIF_ESCAPEPOD:
7430                         return SHIP_TYPE_ESCAPEPOD;
7431
7432                 case SIF_SUPERCAP:
7433                         return SHIP_TYPE_SUPERCAP;
7434
7435                 case SIF_DRYDOCK:
7436                         return SHIP_TYPE_DRYDOCK;
7437
7438                 case SIF_CORVETTE:
7439                         return SHIP_TYPE_CORVETTE;
7440                 
7441                 case SIF_AWACS:
7442                         return SHIP_TYPE_AWACS;
7443
7444                 case SIF_GAS_MINER:
7445                         return SHIP_TYPE_GAS_MINER;
7446
7447                 case SIF_KNOSSOS_DEVICE:
7448                         return SHIP_TYPE_KNOSSOS_DEVICE;
7449         }
7450
7451         Error(LOCATION, "Ship type flag is unknown.  Flags value is 0x%x", flags);
7452         return SHIP_TYPE_NONE;
7453 }
7454
7455 // returns true if the docker can (is allowed) to dock with dockee
7456 int ship_docking_valid(int docker, int dockee)
7457 {
7458         int docker_type, dockee_type;
7459
7460         SDL_assert(docker >= 0 && docker < MAX_SHIPS);
7461         SDL_assert(dockee >= 0 && dockee < MAX_SHIPS);
7462         docker_type = ship_query_general_type(docker);
7463         dockee_type = ship_query_general_type(dockee);
7464
7465         // escape pods can dock with transports, freighters, cruisers.
7466         if ( docker_type == SHIP_TYPE_ESCAPEPOD ) {
7467                 if ( (dockee_type == SHIP_TYPE_TRANSPORT) || (dockee_type == SHIP_TYPE_CRUISER) || (dockee_type == SHIP_TYPE_FREIGHTER) || (dockee_type == SHIP_TYPE_DRYDOCK) || (dockee_type == SHIP_TYPE_CORVETTE) || (dockee_type == SHIP_TYPE_GAS_MINER) || (dockee_type == SHIP_TYPE_AWACS)){
7468                         return 1;
7469                 }
7470         }
7471
7472         // docket == freighter
7473         if (docker_type == SHIP_TYPE_FREIGHTER) {
7474                 if ( (dockee_type == SHIP_TYPE_CARGO) || (dockee_type == SHIP_TYPE_CRUISER) || (dockee_type == SHIP_TYPE_CAPITAL) || (dockee_type == SHIP_TYPE_SUPERCAP) || (dockee_type == SHIP_TYPE_DRYDOCK) || (dockee_type == SHIP_TYPE_CORVETTE) || (dockee_type == SHIP_TYPE_GAS_MINER) || (dockee_type == SHIP_TYPE_AWACS)){
7475                         return 1;
7476                 }
7477         }
7478
7479         // docker == cruiser
7480         if ( (docker_type == SHIP_TYPE_CRUISER) || (docker_type == SHIP_TYPE_CORVETTE) || (docker_type == SHIP_TYPE_GAS_MINER) || (docker_type == SHIP_TYPE_AWACS)){
7481                 if ( (dockee_type == SHIP_TYPE_CARGO) || (dockee_type == SHIP_TYPE_CRUISER) || (dockee_type == SHIP_TYPE_CAPITAL) || (dockee_type == SHIP_TYPE_SUPERCAP) || (dockee_type == SHIP_TYPE_DRYDOCK) || (dockee_type == SHIP_TYPE_CORVETTE) || (dockee_type == SHIP_TYPE_GAS_MINER) || (dockee_type == SHIP_TYPE_AWACS)){
7482                         return 1;
7483                 }
7484         }
7485
7486         if (docker_type == SHIP_TYPE_TRANSPORT) {
7487                 if ( (dockee_type == SHIP_TYPE_CARGO) || (dockee_type == SHIP_TYPE_CRUISER)
7488                         || (dockee_type == SHIP_TYPE_FREIGHTER) || (dockee_type == SHIP_TYPE_TRANSPORT)
7489                         || (dockee_type == SHIP_TYPE_CAPITAL) || (dockee_type == SHIP_TYPE_ESCAPEPOD) 
7490                         || (dockee_type == SHIP_TYPE_SUPERCAP) || (dockee_type == SHIP_TYPE_DRYDOCK) || (dockee_type == SHIP_TYPE_CORVETTE) || (dockee_type == SHIP_TYPE_GAS_MINER) || (dockee_type == SHIP_TYPE_AWACS)){
7491                                 return 1;
7492                 }
7493         }
7494
7495         if (docker_type == SHIP_TYPE_REPAIR_REARM) {
7496                 if ((dockee_type == SHIP_TYPE_FIGHTER_BOMBER) || (dockee_type == SHIP_TYPE_STEALTH)){
7497                         return 1;
7498                 }
7499         }
7500
7501         return 0;
7502 }
7503
7504 // function to return a random ship in a starting player wing.  Returns -1 if a suitable
7505 // one cannot be found
7506 // input:       max_dist        =>      OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
7507 // input:   persona  => OPTIONAL PARAMETER (default to -1) which persona to get
7508 int ship_get_random_player_wing_ship( int flags, float max_dist, int persona_index, int get_first, int multi_team )
7509 {
7510         int i, j, ship_index, count;
7511         int slist[MAX_SHIPS_PER_WING * MAX_STARTING_WINGS], which_one;
7512
7513         // iterate through starting wings of player.  Add ship indices of ships which meet
7514         // given criteria
7515         count = 0;
7516         for (i = 0; i < num_wings; i++ ) {
7517                 int wingnum;
7518
7519                 wingnum = -1;
7520
7521                 // multi-team?
7522                 if(multi_team >= 0){
7523                         if(!SDL_strcasecmp(Wings[i].name, multi_team == 0 ? "alpha" : "zeta")){
7524                                 wingnum = i;
7525                         } else {
7526                                 continue;
7527                         }
7528                 } else {
7529                         // first check for a player starting wing (alpha, beta, gamma)
7530                         for ( j = 0; j < MAX_PLAYER_WINGS; j++ ) {
7531                                 if ( i == Starting_wings[j] ) {
7532                                         wingnum = i;
7533                                         break;
7534                                 }
7535                         }
7536
7537                         // if not found, the delta and epsilon count too
7538                         if ( wingnum == -1 ) {
7539                                 if ( !SDL_strcasecmp(Wings[i].name, NOX("delta")) || !SDL_strcasecmp(Wings[i].name, NOX("epsilon")) ) {
7540                                         wingnum = i;
7541                                 }
7542                         }
7543
7544                         if ( wingnum == -1 ){
7545                                 continue;
7546                         }
7547                 }
7548
7549                 for ( j = 0; j < Wings[wingnum].current_count; j++ ) {
7550                         ship_index = Wings[wingnum].ship_index[j];
7551                         SDL_assert( ship_index != -1 );
7552
7553                         if ( Ships[ship_index].flags & SF_DYING ) {
7554                                 continue;
7555                         }
7556
7557                         // see if ship meets our criterea
7558                         if ( (flags == SHIP_GET_NO_PLAYERS) && (Objects[Ships[ship_index].objnum].flags & OF_PLAYER_SHIP) ){
7559                                 continue;
7560                         }
7561
7562                         // don't process ships on a different team
7563                         if(multi_team < 0){
7564                                 if ( Player_ship->team != Ships[ship_index].team ){
7565                                         continue;
7566                                 }
7567                         }
7568
7569                         // see if ship is within max_dist units
7570                         if ( (max_dist > 0) && (multi_team < 0) ) {
7571                                 float dist;
7572                                 dist = vm_vec_dist_quick(&Objects[Ships[ship_index].objnum].pos, &Player_obj->pos);
7573                                 if ( dist > max_dist ) {
7574                                         continue;
7575                                 }
7576                         }
7577
7578                         // if we should be checking persona's, then don't add ships that don't have the proper persona
7579                         if ( persona_index != -1 ) {
7580                                 if ( Ships[ship_index].persona_index != persona_index ){
7581                                         continue;
7582                                 }
7583                         }
7584
7585                         // return the first ship with correct persona
7586                         if (get_first) {
7587                                 return ship_index;
7588                         }
7589
7590                         slist[count] = ship_index;
7591                         count++;
7592                 }
7593         }
7594
7595         if ( count == 0 ){
7596                 return -1;
7597         }
7598
7599         // now get a random one from the list
7600         which_one = (rand() % count);
7601         ship_index = slist[which_one];
7602
7603         SDL_assert ( Ships[ship_index].objnum != -1 );
7604
7605         return ship_index;
7606 }
7607
7608 // like above function, but returns a random ship in the given wing -- no restrictions
7609 // input:       max_dist        =>      OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
7610 int ship_get_random_ship_in_wing(int wingnum, int flags, float max_dist, int get_first)
7611 {
7612         int i, ship_index, slist[MAX_SHIPS_PER_WING], count, which_one;
7613
7614         count = 0;
7615         for ( i = 0; i < Wings[wingnum].current_count; i++ ) {
7616                 ship_index = Wings[wingnum].ship_index[i];
7617                 SDL_assert( ship_index != -1 );
7618
7619                 if ( Ships[ship_index].flags & SF_DYING ) {
7620                         continue;
7621                 }
7622
7623                 // see if ship meets our criterea
7624                 if ( (flags == SHIP_GET_NO_PLAYERS) && (Objects[Ships[ship_index].objnum].flags & OF_PLAYER_SHIP) )
7625                         continue;
7626
7627                 // see if ship is within max_dist units
7628                 if ( max_dist > 0 ) {
7629                         float dist;
7630                         dist = vm_vec_dist_quick(&Objects[Ships[ship_index].objnum].pos, &Player_obj->pos);
7631                         if ( dist > max_dist ) {
7632                                 continue;
7633                         }
7634                 }
7635
7636                 // return the first ship in wing
7637                 if (get_first) {
7638                         return ship_index;
7639                 }
7640
7641                 slist[count] = ship_index;
7642                 count++;
7643         }
7644
7645         if ( count == 0 ) {
7646                 return -1;
7647         }
7648
7649         // now get a random one from the list
7650         which_one = (rand() % count);
7651         ship_index = slist[which_one];
7652
7653         SDL_assert ( Ships[ship_index].objnum != -1 );
7654
7655         return ship_index;
7656 }
7657
7658
7659 // this function returns a random index into the Ship array of a ship of the given team
7660 // cargo containers are not counted as ships for the purposes of this function.  Why???
7661 // because now it is only used for getting a random ship for a message and cargo containers
7662 // can't send mesages.  This function is an example of kind of bad coding :-(
7663 // input:       max_dist        =>      OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
7664 int ship_get_random_team_ship( int team, int flags, float max_dist )
7665 {
7666         int num, which_one;
7667         object *objp, *obj_list[MAX_SHIPS];
7668
7669         // for any allied, go through the ships list and find all of the ships on that team
7670         num = 0;
7671         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
7672                 if ( objp->type != OBJ_SHIP )
7673                         continue;
7674
7675                 // series of conditionals one per line for easy reading
7676                 // don't process ships on wrong team
7677                 // don't process cargo's or navbuoys
7678                 // don't process player ships if flags are set
7679                 if ( Ships[objp->instance].team != team )
7680                         continue;
7681                 else if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_NOT_FLYABLE )
7682                         continue;
7683                 else if ( (flags == SHIP_GET_NO_PLAYERS) && (objp->flags & OF_PLAYER_SHIP) )
7684                         continue;
7685                 else if ( (flags == SHIP_GET_ONLY_PLAYERS) && !(objp->flags & OF_PLAYER_SHIP) )
7686                         continue;
7687
7688                 if ( Ships[objp->instance].flags & SF_DYING ) {
7689                         continue;
7690                 }
7691
7692                 // see if ship is within max_dist units
7693                 if ( max_dist > 0 ) {
7694                         float dist;
7695                         dist = vm_vec_dist_quick(&objp->pos, &Player_obj->pos);
7696                         if ( dist > max_dist ) {
7697                                 continue;
7698                         }
7699                 }
7700
7701                 obj_list[num] = objp;
7702                 num++;
7703         }
7704
7705         if ( num == 0 )
7706                 return -1;
7707
7708         which_one = (rand() % num);
7709         objp = obj_list[which_one];
7710
7711         SDL_assert ( objp->instance != -1 );
7712
7713         return objp->instance;
7714 }
7715
7716 // -----------------------------------------------------------------------
7717 // ship_secondary_bank_has_ammo()
7718 //
7719 // check if currently selected secondary bank has ammo
7720 //
7721 // input:       shipnum =>      index into Ships[] array for ship to check
7722 //
7723 int ship_secondary_bank_has_ammo(int shipnum)
7724 {
7725         ship_weapon     *swp;
7726
7727         SDL_assert(shipnum >= 0 && shipnum < MAX_SHIPS);
7728         swp = &Ships[shipnum].weapons;
7729         
7730         if ( swp->current_secondary_bank == -1 )
7731                 return 0;
7732
7733         SDL_assert(swp->current_secondary_bank >= 0 && swp->current_secondary_bank < MAX_SECONDARY_BANKS );
7734         if ( swp->secondary_bank_ammo[swp->current_secondary_bank] <= 0 )
7735                 return 0;
7736
7737         return 1;
7738 }
7739
7740 // see if there is enough engine power to allow the ship to warp
7741 // returns 1 if ship is able to warp, otherwise return 0
7742 int ship_can_warp(ship *sp)
7743 {
7744         float   engine_str;
7745
7746         engine_str = ship_get_subsystem_strength( sp, SUBSYSTEM_ENGINE );
7747         // Note that ship can always warp at lowest skill level
7748         if ( (Game_skill_level > 0) && (engine_str >= SHIP_MIN_ENGINES_TO_WARP) ){
7749                 return 1;
7750         } else {
7751                 return 0;
7752         }
7753 }
7754
7755
7756 // Calculate the normal vector from a subsystem position and it's first path point
7757 // input:       sp      =>      pointer to ship that is parent of subsystem
7758 //                              ss =>   pointer to subsystem of interest
7759 //                              norm    => output parameter... vector from subsys to first path point
7760 //
7761 //      exit:           0       =>      a valid vector was placed in norm
7762 //                              !0      => an path normal could not be calculated
7763 //                              
7764 int ship_return_subsys_path_normal(ship *sp, ship_subsys *ss, vector *gsubpos, vector *norm)
7765 {
7766         if ( ss->system_info->path_num >= 0 ) {
7767                 polymodel       *pm;
7768                 model_path      *mp;
7769                 vector          *path_point;
7770                 vector          gpath_point;
7771                 pm = model_get(sp->modelnum);
7772                 mp = &pm->paths[ss->system_info->path_num];
7773                 if ( mp->nverts >= 2 ) {
7774 //                      path_point = &mp->verts[mp->nverts-1].pos;
7775                         path_point = &mp->verts[0].pos;
7776                         // get path point in world coords
7777                         vm_vec_unrotate(&gpath_point, path_point, &Objects[sp->objnum].orient);
7778                         vm_vec_add2(&gpath_point, &Objects[sp->objnum].pos);
7779                         // get unit vector pointing from subsys pos to first path point
7780                         vm_vec_normalized_dir(norm, &gpath_point, gsubpos);
7781                         return 0;
7782                 }
7783         }
7784         return 1;
7785 }
7786
7787
7788 //      Determine if the subsystem can be viewed from eye_pos.  The method is to check where the
7789 // vector from eye_pos to the subsystem hits the ship.  If distance from the hit position and
7790 // the center of the subsystem is within a range (currently the subsystem radius) it is considered
7791 // in view (return true).  If not in view, return false.
7792 //
7793 // input:       objp            =>              object that is the ship with the subsystem on it
7794 //                              subsys  =>              pointer to the subsystem of interest
7795 //                              eye_pos =>              world coord for the eye looking at the subsystem
7796 //                              subsys_pos                      =>      world coord for the center of the subsystem of interest
7797 //                              do_facing_check =>      OPTIONAL PARAMETER (default value is 1), do a dot product check to see if subsystem fvec is facing
7798 //                                                                                      towards the eye position        
7799 //                              dot_out =>              OPTIONAL PARAMETER, output parameter, will return dot between subsys fvec and subsys_to_eye_vec
7800 //                                                                      (only filled in if do_facing_check is true)
7801 //                              vec_out =>              OPTIONAL PARAMETER, vector from eye_pos to absolute subsys_pos.  (only filled in if do_facing_check is true)
7802 int ship_subsystem_in_sight(object* objp, ship_subsys* subsys, vector *eye_pos, vector* subsys_pos, int do_facing_check, float *dot_out, vector *vec_out)
7803 {
7804         float           dist, dot;
7805         mc_info mc;
7806         vector  terminus, eye_to_pos, subsys_fvec, subsys_to_eye_vec;
7807
7808         if (objp->type != OBJ_SHIP)
7809                 return 0;
7810
7811         // See if we are at least facing the subsystem
7812         if ( do_facing_check ) {
7813                 if ( ship_return_subsys_path_normal(&Ships[objp->instance], subsys, subsys_pos, &subsys_fvec) ) {
7814                         // non-zero return value means that we couldn't generate a normal from path info... so use inaccurate method
7815                         vm_vec_normalized_dir(&subsys_fvec, subsys_pos, &objp->pos);
7816                 }
7817
7818                 vm_vec_normalized_dir(&subsys_to_eye_vec, eye_pos, subsys_pos);
7819                 dot = vm_vec_dot(&subsys_fvec, &subsys_to_eye_vec);
7820                 if ( dot_out ) {
7821                         *dot_out = dot;
7822                 }
7823
7824                 if (vec_out) {
7825                         *vec_out = subsys_to_eye_vec;
7826                         vm_vec_negate(vec_out);
7827                 }
7828
7829                 if ( dot < 0 )
7830                         return 0;
7831         }
7832
7833         // See if ray from eye to subsystem actually hits close enough to the subsystem position
7834         vm_vec_normalized_dir(&eye_to_pos, subsys_pos, eye_pos);
7835         vm_vec_scale_add(&terminus, eye_pos, &eye_to_pos, 100000.0f);
7836
7837         ship_model_start(objp);
7838
7839         mc.model_num = Ships[objp->instance].modelnum;                  // Fill in the model to check
7840         mc.orient = &objp->orient;                                                                              // The object's orientation
7841         mc.pos = &objp->pos;                                                                                            // The object's position
7842         mc.p0 = eye_pos;                                                                                                        // Point 1 of ray to check
7843         mc.p1 = &terminus;                                                                                              // Point 2 of ray to check
7844         mc.flags = MC_CHECK_MODEL;      
7845
7846         model_collide(&mc);
7847
7848         ship_model_stop(objp);
7849
7850         if ( !mc.num_hits ) {
7851                 return 0;
7852         }       
7853
7854         // determine if hitpos is close enough to subsystem
7855         dist = vm_vec_dist(&mc.hit_point_world, subsys_pos);
7856
7857         if ( dist <= subsys->system_info->radius ) {
7858                 return 1;
7859         }
7860         
7861         return 0;
7862 }
7863
7864 // try to find a subsystem matching 'type' inside the ship, and that is 
7865 // not destroyed.  If cannot find one, return NULL.
7866 ship_subsys *ship_return_next_subsys(ship *shipp, int type, vector *attacker_pos)
7867 {
7868         ship_subsys     *ssp;
7869
7870         SDL_assert ( type >= 0 && type < SUBSYSTEM_MAX );
7871
7872         // If aggregate total is 0, that means no subsystem is alive of that type
7873         if ( shipp->subsys_info[type].total_hits <= 0.0f )
7874                 return NULL;
7875
7876         // loop through all the subsystems, if we find a match that has some strength, return it
7877         ssp = ship_get_best_subsys_to_attack(shipp, type, attacker_pos);
7878
7879         return ssp;
7880 }
7881
7882 // Return the shield strength in the quadrant hit on hit_objp, based on global hitpos
7883 //
7884 // input:       hit_objp        =>      object pointer to ship getting hit
7885 //                              hitpos  => global position of impact
7886 //
7887 // exit:                strength of shields in the quadrant that was hit as a percentage, between 0 and 1.0
7888 //
7889 // Assumes: that hitpos is a valid global hit position
7890 float ship_quadrant_shield_strength(object *hit_objp, vector *hitpos)
7891 {
7892         int                     quadrant_num, i;
7893         float                   max_quadrant;
7894         vector          tmpv1, tmpv2;
7895
7896         // If ship doesn't have shield mesh, then return
7897         if ( hit_objp->flags & OF_NO_SHIELDS ) {
7898                 return 0.0f;
7899         }
7900
7901         // Check if all the shield quadrants are all already 0, if so return 0
7902         for ( i = 0; i < 4; i++ ) {
7903                 if ( hit_objp->shields[i] > 0 )
7904                         break;
7905         }
7906
7907         if ( i == 4 ) {
7908                 return 0.0f;
7909         }
7910
7911         // convert hitpos to position in model coordinates
7912         vm_vec_sub(&tmpv1, hitpos, &hit_objp->pos);
7913         vm_vec_rotate(&tmpv2, &tmpv1, &hit_objp->orient);
7914         quadrant_num = get_quadrant(&tmpv2);
7915         //nprintf(("Alan","Quadrant hit: %d\n", quadrant_num));
7916
7917         if ( quadrant_num < 0 )
7918                 quadrant_num = 0;
7919
7920         max_quadrant = Ship_info[Ships[hit_objp->instance].ship_info_index].shields / 4.0f;
7921         if ( max_quadrant <= 0 ) {
7922                 return 0.0f;
7923         }
7924
7925         SDL_assert(hit_objp->shields[quadrant_num] <= max_quadrant);
7926
7927         return hit_objp->shields[quadrant_num]/max_quadrant;
7928 }
7929
7930 // Determine if a ship is threatened by any dumbfire projectiles (laser or missile)
7931 // input:       sp      =>      pointer to ship that might be threatened
7932 // exit:                0 =>    no dumbfire threats
7933 //                              1 =>    at least one dumbfire threat
7934 //
7935 // NOTE: Currently this function is only called periodically from the HUD code for the 
7936 //       player ship.
7937 int ship_dumbfire_threat(ship *sp)
7938 {
7939         if ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) ) {
7940                 return 0;
7941         }
7942
7943         if (ai_endangered_by_weapon(&Ai_info[sp->ai_index]) > 0) {
7944                 return 1;
7945         } 
7946
7947         return 0;
7948 }
7949
7950 // Return !0 if there is a missile in the air homing on shipp
7951 int ship_has_homing_missile_locked(ship *shipp)
7952 {
7953         object          *locked_objp, *A;
7954         weapon          *wp;
7955         weapon_info     *wip;
7956         missile_obj     *mo;
7957
7958         SDL_assert(shipp->objnum >= 0 && shipp->objnum < MAX_OBJECTS);
7959         locked_objp = &Objects[shipp->objnum];
7960
7961         // check for currently locked missiles (highest precedence)
7962         for ( mo = GET_NEXT(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
7963                 SDL_assert(mo->objnum >= 0 && mo->objnum < MAX_OBJECTS);
7964                 A = &Objects[mo->objnum];
7965
7966                 if (A->type != OBJ_WEAPON)
7967                         continue;
7968
7969                 SDL_assert((A->instance >= 0) && (A->instance < MAX_WEAPONS));
7970                 wp = &Weapons[A->instance];
7971                 wip = &Weapon_info[wp->weapon_info_index];
7972
7973                 if ( wip->subtype != WP_MISSILE )
7974                         continue;
7975
7976                 if ( !(wip->wi_flags & (WIF_HOMING_ASPECT|WIF_HOMING_HEAT) ) )
7977                         continue;
7978
7979                 if (wp->homing_object == locked_objp) {
7980                         return 1;
7981                 }
7982         }       // end for 
7983
7984         return 0;
7985 }
7986
7987 // Return !0 if there is some ship attempting to lock onto shipp
7988 int ship_is_getting_locked(ship *shipp)
7989 {
7990         ship_obj        *so;
7991         object  *objp;
7992         ai_info *aip;
7993
7994         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
7995                 objp = &Objects[so->objnum];
7996                 aip = &Ai_info[Ships[objp->instance].ai_index];
7997
7998                 if ( aip->target_objnum == shipp->objnum ) {
7999                         if ( aip->aspect_locked_time > 0.1f ) {
8000                                 float dist, wep_range;
8001                                 dist = vm_vec_dist_quick(&objp->pos, &Objects[shipp->objnum].pos);
8002                                 wep_range = ship_get_secondary_weapon_range(&Ships[objp->instance]);
8003                                 if ( wep_range > dist ) {
8004                                         nprintf(("Alan","AI ship is seeking lock\n"));
8005                                         return 1;
8006                                 }
8007                         }
8008                 }
8009         }
8010
8011         return 0;
8012 }
8013
8014 // Determine if a ship is threatened by attempted lock or actual lock
8015 // input:       sp      =>      pointer to ship that might be threatened
8016 // exit:                0 =>    no lock threats of any kind
8017 //                              1 =>    at least one attempting lock (no actual locks)
8018 //                              2 =>    at least one lock (possible other attempting locks)
8019 //
8020 // NOTE: Currently this function is only called periodically from the HUD code for the 
8021 //       player ship.
8022 int ship_lock_threat(ship *sp)
8023 {
8024         if ( ship_has_homing_missile_locked(sp) ) {
8025                 return 2;
8026         }
8027
8028         if ( ship_is_getting_locked(sp) ) {
8029                 return 1;
8030         }
8031
8032         return 0;
8033 }
8034
8035 // converts a bitmask, such as 0x08, into the bit number this would be (3 in this case)
8036 // NOTE: Should move file to something like Math_utils.
8037 int bitmask_2_bitnum(int num)
8038 {
8039         int i;
8040
8041         for (i=0; i<32; i++)
8042                 if (num & (1 << i))
8043                         return i;
8044
8045         return -1;
8046 }
8047
8048 // Get a text description of a ships orders. 
8049 //
8050 //      input:  outbuf  =>              buffer to hold orders string
8051 //                              sp                      =>              ship pointer to extract orders from
8052 //
8053 // exit:                NULL            =>              printable orders are not applicable
8054 //                              non-NULL        =>              pointer to string that was passed in originally
8055 //
8056 // This function is called from HUD code to get a text description
8057 // of what a ship's orders are.  Feel free to use this function if 
8058 // it suits your needs for something.
8059 //
8060 char *ship_return_orders(char *outbuf, const int max_outbuf, ship *sp)
8061 {
8062         ai_info *aip;
8063         ai_goal *aigp;
8064         const char      *order_text;
8065         
8066         SDL_assert(sp->ai_index >= 0);
8067         aip = &Ai_info[sp->ai_index];
8068
8069         // The active goal is always in the first element of aip->goals[]
8070         aigp = &aip->goals[0];
8071
8072         if ( aigp->ai_mode < 0 ) 
8073                 return NULL;
8074
8075         order_text = Ai_goal_text(bitmask_2_bitnum(aigp->ai_mode));
8076         if ( order_text == NULL )
8077                 return NULL;
8078
8079         SDL_strlcpy(outbuf, order_text, max_outbuf);
8080         switch (aigp->ai_mode ) {
8081
8082                 case AI_GOAL_FORM_ON_WING:
8083                 case AI_GOAL_GUARD_WING:
8084                 case AI_GOAL_CHASE_WING:
8085                         if ( aigp->ship_name ) {
8086                                 SDL_strlcat(outbuf, aigp->ship_name, max_outbuf);
8087                                 SDL_strlcat(outbuf, XSTR( " Wing", 494), max_outbuf);
8088                         } else {
8089                                 SDL_strlcpy(outbuf, XSTR( "no orders", 495), max_outbuf);
8090                         }
8091                         break;
8092         
8093                 case AI_GOAL_CHASE:
8094                 case AI_GOAL_DOCK:
8095                 case AI_GOAL_UNDOCK:
8096                 case AI_GOAL_GUARD:
8097                 case AI_GOAL_DISABLE_SHIP:
8098                 case AI_GOAL_DISARM_SHIP:
8099                 case AI_GOAL_EVADE_SHIP:
8100                 case AI_GOAL_REARM_REPAIR:
8101                         if ( aigp->ship_name ) {
8102                                 SDL_strlcat(outbuf, aigp->ship_name, max_outbuf);
8103                         } else {
8104                                 SDL_strlcpy(outbuf, XSTR( "no orders", 495), max_outbuf);
8105                         }
8106                         break;
8107
8108                 case AI_GOAL_DESTROY_SUBSYSTEM: {
8109                         char name[NAME_LENGTH];
8110                         if ( aip->targeted_subsys != NULL ) {
8111                                 SDL_snprintf(outbuf, max_outbuf, XSTR( "atk %s %s", 496), aigp->ship_name, hud_targetbox_truncate_subsys_name(aip->targeted_subsys->system_info->name, sizeof(aip->targeted_subsys->system_info->name)));
8112                                 SDL_strlcat(outbuf, name, max_outbuf);
8113                         } else {
8114                                 SDL_strlcpy(outbuf, XSTR( "no orders", 495), max_outbuf);
8115                         }
8116                         break;
8117                 }
8118
8119                 case AI_GOAL_WAYPOINTS:
8120                 case AI_GOAL_WAYPOINTS_ONCE:
8121                         // don't do anything, all info is in order_text
8122                         break;
8123
8124                 default:
8125                         return NULL;
8126         }
8127
8128         return outbuf;
8129 }
8130
8131 // return the amount of time until ship reaches it's goal (in MM:SS format)
8132 //      input:  outbuf  =>              buffer to hold orders string
8133 //                              sp                      =>              ship pointer to extract orders from
8134 //
8135 // exit:                NULL            =>              printable orders are not applicable
8136 //                              non-NULL        =>              pointer to string that was passed in originally
8137 //
8138 // This function is called from HUD code to get a text description
8139 // of what a ship's orders are.  Feel free to use this function if 
8140 // it suits your needs for something.
8141 char *ship_return_time_to_goal(char *outbuf, const int max_outbuf, ship *sp)
8142 {
8143         ai_info *aip;
8144         int             time, seconds, minutes;
8145         float           dist = 0.0f;
8146         object  *objp;  
8147         float           min_speed;
8148
8149         objp = &Objects[sp->objnum];
8150         aip = &Ai_info[sp->ai_index];
8151
8152         min_speed = objp->phys_info.speed;
8153
8154         if ( aip->mode == AIM_WAYPOINTS ) {
8155                 waypoint_list   *wpl;
8156                 min_speed = 0.9f * sp->current_max_speed;
8157                 if (aip->wp_list >= 0) {
8158                         wpl = &Waypoint_lists[aip->wp_list];
8159                         dist += vm_vec_dist_quick(&objp->pos, &wpl->waypoints[aip->wp_index]);
8160                         for (int i=aip->wp_index; i<wpl->count-1; i++) {
8161                                 dist += vm_vec_dist_quick(&wpl->waypoints[i], &wpl->waypoints[i+1]);
8162                         }
8163                 }
8164
8165                 if ( dist < 1.0f) {
8166                         return NULL;
8167                 }       
8168
8169                 if ( (Objects[sp->objnum].phys_info.speed <= 0) || (sp->current_max_speed <= 0.0f) ) {
8170                         time = -1;
8171                 } else {
8172                         float   speed;
8173
8174                         speed = objp->phys_info.speed;
8175
8176                         if (speed < min_speed)
8177                                 speed = min_speed;
8178                         time = fl2i(dist/speed);
8179                 }
8180
8181         } else if ( (aip->mode == AIM_DOCK) && (aip->submode < AIS_DOCK_4) ) {
8182                 time = hud_support_get_dock_time( OBJ_INDEX(objp) );
8183         } else {
8184                 // don't return anytime for time to except for waypoints and actual docking.
8185                 return NULL;
8186         }
8187
8188 /*
8189         } else if ( aip->goal_objnum >= 0 ) {
8190                 dist = vm_vec_dist_quick(&Objects[aip->goal_objnum].pos, &objp->pos);
8191                 min_speed = sip->max_speed/4.0f;
8192         } else if ( aip->target_objnum >= 0 ) {
8193                 if ( aip->guard_objnum < 0 ) {
8194                         dist = vm_vec_dist_quick(&Objects[aip->target_objnum].pos, &objp->pos);
8195                         min_speed = sip->max_speed/4.0f;
8196                 }
8197         }
8198 */
8199
8200         if ( time >= 0 ) {
8201                 minutes = time/60;
8202                 seconds = time%60;
8203                 if ( minutes > 99 ) {
8204                         minutes = 99;
8205                         seconds = 99;
8206                 }
8207                 SDL_snprintf(outbuf, max_outbuf, NOX("%02d:%02d"), minutes, seconds);
8208         } else {
8209                 SDL_strlcpy( outbuf, XSTR( "Unknown", 497), max_outbuf );
8210         }
8211
8212         return outbuf;
8213 }
8214
8215
8216 // Called to check if any AI ships might reveal the cargo of any cargo containers.
8217 //
8218 // This is called once a frame, but a global timer 'Ship_cargo_check_timer' will limit this
8219 // function to being called every SHIP_CARGO_CHECK_INTERVAL ms.  I think that should be sufficient.
8220 //
8221 // NOTE: This function uses CARGO_REVEAL_DISTANCE from the HUD code... which is a multiple of
8222 //       the ship radius that is used to determine when cargo is detected.  AI ships do not 
8223 //       have to have the ship targeted to reveal cargo.  The player is ignored in this function.
8224 #define SHIP_CARGO_CHECK_INTERVAL       1000
8225 void ship_check_cargo_all()
8226 {
8227         object  *cargo_objp;
8228         ship_obj        *cargo_so, *ship_so;
8229         ship            *cargo_sp, *ship_sp;
8230         float           dist_squared, limit_squared;
8231
8232         // I don't want to do this check every frame, so I made a global timer to limit check to
8233         // every SHIP_CARGO_CHECK_INTERVAL ms.
8234         if ( !timestamp_elapsed(Ship_cargo_check_timer) ) {
8235                 return;
8236         } else {
8237                 Ship_cargo_check_timer = timestamp(SHIP_CARGO_CHECK_INTERVAL);
8238         }
8239
8240         // Check all friendly fighter/bombers against all non-friendly cargo containers that don't have
8241         // cargo revealed
8242
8243         // for now just locate a captial ship on the same team:
8244         cargo_so = GET_FIRST(&Ship_obj_list);
8245         while(cargo_so != END_OF_LIST(&Ship_obj_list)){
8246                 cargo_sp = &Ships[Objects[cargo_so->objnum].instance];
8247                 if ( (Ship_info[cargo_sp->ship_info_index].flags & SIF_CARGO) && !(cargo_sp->team & TEAM_FRIENDLY) ) {
8248                         
8249                         // If the cargo is revealed, continue on to next hostile cargo
8250                         if ( cargo_sp->flags & SF_CARGO_REVEALED ) {
8251                                 goto next_cargo;
8252                         }
8253
8254                         // check against friendly fighter/bombers + cruiser/freighter/transport
8255                         // IDEA: could cull down to fighter/bomber if we want this to run a bit quicker
8256                         for ( ship_so=GET_FIRST(&Ship_obj_list); ship_so != END_OF_LIST(&Ship_obj_list); ship_so=GET_NEXT(ship_so) ) {
8257                                 ship_sp = &Ships[Objects[ship_so->objnum].instance];
8258                                 // only consider friendly ships
8259                                 if ( !(ship_sp->team & TEAM_FRIENDLY) ) {
8260                                         continue;
8261                                 }
8262
8263                                 // ignore the player
8264                                 if ( ship_so->objnum == OBJ_INDEX(Player_obj) ) {
8265                                         continue;
8266                                 }
8267
8268                                 // if this ship is a small or big ship
8269                                 if ( Ship_info[ship_sp->ship_info_index].flags & (SIF_SMALL_SHIP|SIF_BIG_SHIP) ) {
8270                                         cargo_objp = &Objects[cargo_sp->objnum];
8271                                         // use square of distance, faster than getting real distance (which will use sqrt)
8272                                         dist_squared = vm_vec_dist_squared(&cargo_objp->pos, &Objects[ship_sp->objnum].pos);
8273                                         limit_squared = (cargo_objp->radius+CARGO_RADIUS_DELTA)*(cargo_objp->radius+CARGO_RADIUS_DELTA);
8274                                         if ( dist_squared <= max(limit_squared, CARGO_REVEAL_MIN_DIST*CARGO_REVEAL_MIN_DIST) ) {
8275                                                 ship_do_cargo_revealed( cargo_sp );
8276                                                 break;  // break out of for loop, move on to next hostile cargo
8277                                         }
8278                                 }
8279                         } // end for
8280                 }
8281 next_cargo:
8282                 cargo_so = GET_NEXT(cargo_so);
8283         } // end while
8284 }
8285
8286
8287 // Maybe warn player about this attacking ship.  This is called once per frame, and the
8288 // information about the closest attacking ship comes for free, since this function is called
8289 // from HUD code which has already determined the closest enemy attacker and the distance.
8290 //
8291 // input:       enemy_sp        =>      ship pointer to the TEAM_ENEMY ship attacking the player
8292 //                              dist            =>      the distance of the enemy to the player
8293 //
8294 // NOTE: there are no filters on enemy_sp, so it could be any ship type
8295 //
8296 #define PLAYER_ALLOW_WARN_INTERVAL              60000           // minimum time between warnings
8297 #define PLAYER_CHECK_WARN_INTERVAL              300             // how often we check for warnings
8298 #define PLAYER_MAX_WARNINGS                             2                       // max number of warnings player can receive in a mission
8299 #define PLAYER_MIN_WARN_DIST                            100             // minimum distance attacking ship can be from player and still allow warning
8300 #define PLAYER_MAX_WARN_DIST                            1000            // maximum distance attacking ship can be from plyaer and still allow warning
8301
8302 void ship_maybe_warn_player(ship *enemy_sp, float dist)
8303 {
8304         float           fdot; //, rdot, udot;
8305         vector  vec_to_target;
8306         int             msg_type; //, on_right;
8307
8308         // First check if the player has reached the maximum number of warnings for a mission
8309         if ( Player->warn_count >= PLAYER_MAX_WARNINGS ) {
8310                 return;
8311         }
8312
8313         // Check if enough time has elapsed since last warning, if not - leave
8314         if ( !timestamp_elapsed(Player->allow_warn_timestamp) ) {
8315                 return;
8316         }
8317
8318         // Check to see if check timer has elapsed.  Necessary, since we don't want to check each frame
8319         if ( !timestamp_elapsed(Player->check_warn_timestamp ) ) {
8320                 return;
8321         }
8322         Player->check_warn_timestamp = timestamp(PLAYER_CHECK_WARN_INTERVAL);
8323
8324         // only allow warnings if within a certain distance range
8325         if ( dist < PLAYER_MIN_WARN_DIST || dist > PLAYER_MAX_WARN_DIST ) {
8326                 return;
8327         }
8328
8329         // only warn if a fighter or bomber is attacking the player
8330         if ( !(Ship_info[enemy_sp->ship_info_index].flags & SIF_SMALL_SHIP) ) {
8331                 return;
8332         }
8333
8334         // get vector from player to target
8335         vm_vec_normalized_dir(&vec_to_target, &Objects[enemy_sp->objnum].pos, &Eye_position);
8336
8337         // ensure that enemy fighter is oriented towards player
8338         fdot = vm_vec_dot(&Objects[enemy_sp->objnum].orient.v.fvec, &vec_to_target);
8339         if ( fdot > -0.7 ) {
8340                 return;
8341         }
8342
8343         fdot = vm_vec_dot(&Player_obj->orient.v.fvec, &vec_to_target);
8344
8345         msg_type = -1;
8346
8347         // check if attacking ship is on six.  return if not far enough behind player.
8348         if ( fdot > -0.7 )
8349                 return;
8350
8351         msg_type = MESSAGE_CHECK_6;
8352 /*
8353                 goto warn_player_done;
8354         }
8355
8356         // see if attacking ship is in front of ship (then do nothing)
8357         if ( fdot > 0.7 ) {
8358                 return;
8359         }
8360
8361         // ok, ship is on 3 or 9.  Find out which
8362         rdot = vm_vec_dot(&Player_obj->orient.v.rvec, &vec_to_target);
8363         if ( rdot > 0 ) {
8364                 on_right = 1;
8365         } else {
8366                 on_right = 0;
8367         }
8368
8369         // now determine if ship is high or low
8370         udot = vm_vec_dot(&Player_obj->orient.v.uvec, &vec_to_target);
8371         if ( udot < -0.8 ) {
8372                 return; // if ship is attacking from directly below, no warning given
8373         }
8374
8375         if ( udot > 0 ) {
8376                 if ( on_right ) {
8377                         msg_type = MESSAGE_CHECK_3_HIGH;
8378                 } else {
8379                         msg_type = MESSAGE_CHECK_9_HIGH;
8380                 }
8381         } else {
8382                 if ( on_right ) {
8383                         msg_type = MESSAGE_CHECK_3_LOW;
8384                 } else {
8385                         msg_type = MESSAGE_CHECK_9_LOW;
8386                 }
8387         }
8388
8389 warn_player_done:
8390 */
8391
8392         if ( msg_type != -1 ) {
8393                 int ship_index;
8394
8395                 // multiplayer tvt - this is client side.
8396                 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL)){
8397                         ship_index = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS, 0.0f, -1, 0, Net_player->p_info.team );
8398                 } else {
8399                         ship_index = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
8400                 }
8401
8402                 if ( ship_index >= 0 ) {
8403                         // multiplayer - make sure I just send to myself
8404                         if(Game_mode & GM_MULTIPLAYER){
8405                                 message_send_builtin_to_player(msg_type, &Ships[ship_index], MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, MY_NET_PLAYER_NUM, -1);
8406                         } else {
8407                                 message_send_builtin_to_player(msg_type, &Ships[ship_index], MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, -1);
8408                         }
8409                         Player->allow_warn_timestamp = timestamp(PLAYER_ALLOW_WARN_INTERVAL);
8410                         Player->warn_count++;
8411 //                      nprintf(("Alan","Warning given for ship name: %s\n", enemy_sp->ship_name));
8412                 }
8413         }
8414 }
8415
8416 // player has just killed a ship, maybe offer send a 'good job' message
8417 #define PLAYER_MAX_PRAISES                                      10                      // max number of praises player can receive in a mission
8418 void ship_maybe_praise_player(ship *deader_sp)
8419 {
8420         if ( myrand()&1 ) {
8421                 return;
8422         }
8423
8424         // First check if the player has reached the maximum number of praises for a mission
8425         if ( Player->praise_count >= PLAYER_MAX_PRAISES ) {
8426                 return;
8427         }
8428
8429         // Check if enough time has elapsed since last praise, if not - leave
8430         if ( !timestamp_elapsed(Player->allow_praise_timestamp) ) {
8431                 return;
8432         }
8433
8434         if ( !(Player_ship->team & TEAM_FRIENDLY) ) {
8435                 return;
8436         }
8437
8438         if ( deader_sp->team == Player_ship->team ) {   // only praise if killing an enemy!
8439                 return;
8440         }
8441
8442         // don't praise the destruction of navbuoys, cargo or other non-flyable ship types
8443         if ( Ship_info[deader_sp->ship_info_index].flags & SIF_NOT_FLYABLE ) {
8444                 return;
8445         }
8446
8447         // There is already a praise pending
8448         if ( Player->praise_delay_timestamp ) {
8449                 return;
8450         }
8451
8452         // We don't want to praise the player right away.. it is more realistic to wait a moment
8453         Player->praise_delay_timestamp = timestamp_rand(1000, 2000);
8454 }
8455
8456 // player has just killed a ship, maybe offer send a 'good job' message
8457 #define PLAYER_ASK_HELP_INTERVAL                        60000           // minimum time between praises
8458 #define PLAYER_MAX_ASK_HELP                             10                      // max number of warnings player can receive in a mission
8459 #define ASK_HELP_SHIELD_PERCENT                 0.1             // percent shields at which ship will ask for help
8460 #define ASK_HELP_HULL_PERCENT                           0.3             // percent hull at which ship will ask for help
8461 #define AWACS_HELP_HULL_HI                                      0.75            // percent hull at which ship will ask for help
8462 #define AWACS_HELP_HULL_LOW                             0.25            // percent hull at which ship will ask for help
8463
8464 // -----------------------------------------------------------------------------
8465 void awacs_maybe_ask_for_help(ship *sp, int multi_team_filter)
8466 {
8467         object *objp;
8468         int message = -1;
8469         objp = &Objects[sp->objnum];
8470
8471         if ( objp->hull_strength < ( (AWACS_HELP_HULL_LOW + 0.01f *(static_rand(objp-Objects) & 5)) * Ship_info[sp->ship_info_index].initial_hull_strength) ) {
8472                 // awacs ship below 25 + (0-4) %
8473                 if (!(sp->awacs_warning_flag & AWACS_WARN_25)) {
8474                         message = MESSAGE_AWACS_25;
8475                         sp->awacs_warning_flag |=  AWACS_WARN_25;
8476                 }
8477         } else if ( objp->hull_strength < ( (AWACS_HELP_HULL_HI + 0.01f*(static_rand(objp-Objects) & 5)) * Ship_info[sp->ship_info_index].initial_hull_strength) ) {
8478                 // awacs ship below 75 + (0-4) %
8479                 if (!(sp->awacs_warning_flag & AWACS_WARN_75)) {
8480                         message = MESSAGE_AWACS_75;
8481                         sp->awacs_warning_flag |=  AWACS_WARN_75;
8482                 }
8483         }
8484
8485         if (message >= 0) {
8486                 message_send_builtin_to_player(message, sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, multi_team_filter);
8487                 Player->allow_ask_help_timestamp = timestamp(PLAYER_ASK_HELP_INTERVAL);
8488                 Player->ask_help_count++;
8489         }
8490 }
8491
8492 // -----------------------------------------------------------------------------
8493 void ship_maybe_ask_for_help(ship *sp)
8494 {
8495         object *objp;
8496         int multi_team_filter = -1;
8497
8498         // First check if the player has reached the maximum number of ask_help's for a mission
8499         if ( Player->ask_help_count >= PLAYER_MAX_ASK_HELP ) {
8500                 return;
8501         }
8502
8503         // Check if enough time has elapsed since last help request, if not - leave
8504         if ( !timestamp_elapsed(Player->allow_ask_help_timestamp) ) {
8505                 return;
8506         }
8507
8508         if ( !(Player_ship->team & TEAM_FRIENDLY) ) {
8509                 return;
8510         }
8511
8512         SDL_assert(sp->team & TEAM_FRIENDLY );
8513         objp = &Objects[sp->objnum];
8514
8515         if ( objp->flags & OF_PLAYER_SHIP )     {// don't let the player ask for help!
8516                 return;
8517         }
8518
8519         // determine team filter if TvT
8520         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
8521                 if(sp->team == TEAM_FRIENDLY){
8522                         multi_team_filter = 0;
8523                 } else if(sp->team == TEAM_HOSTILE){
8524                         multi_team_filter = 1;
8525                 }
8526         }
8527
8528         // handle awacs ship as a special case
8529         if (Ship_info[sp->ship_info_index].flags & SIF_HAS_AWACS) {
8530                 awacs_maybe_ask_for_help(sp, multi_team_filter);
8531                 return;
8532         }
8533
8534         // for now, only have wingman ships request help
8535         if ( !(sp->flags & SF_FROM_PLAYER_WING) ) {
8536                 return;
8537         }
8538
8539         // first check if hull is at a critical level
8540         if ( objp->hull_strength < ASK_HELP_HULL_PERCENT * Ship_info[sp->ship_info_index].initial_hull_strength ) {
8541                 goto play_ask_help;
8542         }
8543
8544         // check if shields are near critical level
8545         if ( objp->flags & OF_NO_SHIELDS ) {
8546                 return; // no shields on ship, no don't check shield levels
8547         }
8548
8549         if ( get_shield_strength(objp) > (ASK_HELP_SHIELD_PERCENT * Ship_info[sp->ship_info_index].shields) ) {
8550                 return;
8551         }
8552
8553 play_ask_help:
8554
8555         SDL_assert(Ship_info[sp->ship_info_index].flags & (SIF_FIGHTER|SIF_BOMBER) );   // get Alan
8556         message_send_builtin_to_player(MESSAGE_HELP, sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, multi_team_filter);
8557         Player->allow_ask_help_timestamp = timestamp(PLAYER_ASK_HELP_INTERVAL);
8558
8559         if ( timestamp_until(Player->allow_scream_timestamp) < 15000 ) {
8560                 Player->allow_scream_timestamp = timestamp(15000);      // prevent overlap with death message
8561         }
8562
8563         Player->ask_help_count++;
8564 }
8565
8566 // The player has just entered death roll, maybe have wingman mourn the loss of the player
8567 void ship_maybe_lament()
8568 {
8569         int ship_index;
8570
8571         // no. because in multiplayer, its funny
8572         if(Game_mode & GM_MULTIPLAYER){
8573                 return;
8574         }
8575
8576         if ( rand()%4 == 0 ) {
8577                 ship_index = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
8578                 if ( ship_index >= 0 ) {
8579                         message_send_builtin_to_player(MESSAGE_PLAYED_DIED, &Ships[ship_index], MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, -1);
8580                 }
8581         }
8582 }
8583
8584 #define PLAYER_SCREAM_INTERVAL          60000
8585 #define PLAYER_MAX_SCREAMS                              10
8586
8587 // play a death scream for a ship
8588 void ship_scream(ship *sp)
8589 {
8590         int multi_team_filter = -1;
8591
8592         // bogus
8593         if(sp == NULL){
8594                 return;
8595         }
8596
8597         // multiplayer tvt
8598         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
8599                 if(sp->team == TEAM_FRIENDLY){
8600                         multi_team_filter = 0;
8601                 } else if(sp->team == TEAM_HOSTILE){
8602                         multi_team_filter = 1;
8603                 }
8604         }
8605
8606         message_send_builtin_to_player(MESSAGE_WINGMAN_SCREAM, sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, multi_team_filter);
8607         Player->allow_scream_timestamp = timestamp(PLAYER_SCREAM_INTERVAL);
8608         Player->scream_count++;
8609         sp->flags |= SF_SHIP_HAS_SCREAMED;
8610
8611         // prevent overlap with help messages
8612         if ( timestamp_until(Player->allow_ask_help_timestamp) < 15000 ) {
8613                 Player->allow_ask_help_timestamp = timestamp(15000);    // prevent overlap with death message
8614         }
8615 }
8616
8617 // ship has just died, maybe play a scream.
8618 //
8619 // NOTE: this is only called for ships that are in a player wing (and not player ship)
8620 void ship_maybe_scream(ship *sp)
8621 {
8622         if ( rand()&1 )
8623                 return;
8624
8625         // First check if the player has reached the maximum number of screams for a mission
8626         if ( Player->scream_count >= PLAYER_MAX_SCREAMS ) {
8627                 return;
8628         }
8629
8630         // if on different teams (i.e. team v. team games in multiplayer), no scream
8631         if ( sp->team != Player_ship->team ) {
8632                 return;
8633         }
8634
8635         // Check if enough time has elapsed since last scream, if not - leave
8636         if ( !timestamp_elapsed(Player->allow_scream_timestamp) ) {
8637                 return;
8638         }
8639
8640         ship_scream(sp);
8641 }
8642
8643 // maybe tell player that we've requested a support ship
8644 #define PLAYER_REQUEST_REPAIR_MSG_INTERVAL      240000
8645 void ship_maybe_tell_about_rearm(ship *sp)
8646 {
8647         if ( !timestamp_elapsed(Player->request_repair_timestamp) ) {
8648                 return;
8649         }
8650
8651         if ( !(Player_ship->team & TEAM_FRIENDLY) ) {
8652                 return;
8653         }
8654
8655         // AL 1-4-98:   If ship integrity is low, tell player you want to get repaired.  Otherwise, tell
8656         // the player you want to get re-armed.
8657
8658         int message_type = -1;
8659         int heavily_damaged = 0;
8660         if ( Objects[sp->objnum].hull_strength/Ship_info[sp->ship_info_index].initial_hull_strength < 0.4 ) {
8661                 heavily_damaged = 1;
8662         }
8663
8664         if ( heavily_damaged || (sp->flags & SF_DISABLED) ) {
8665                 message_type = MESSAGE_REPAIR_REQUEST;
8666         } else {
8667                 int i;
8668                 ship_weapon *swp;
8669
8670                 swp = &sp->weapons;
8671                 for ( i = 0; i < swp->num_secondary_banks; i++ ) {
8672                         if (swp->secondary_bank_start_ammo[i] > 0) {
8673                                 if ( swp->secondary_bank_ammo[i]/swp->secondary_bank_start_ammo[i] < 0.5f ) {
8674                                         message_type = MESSAGE_REARM_REQUEST;
8675                                         break;
8676                                 }
8677                         }
8678                 }
8679         }
8680
8681         int multi_team_filter = -1;
8682
8683         // multiplayer tvt
8684         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
8685                 if(sp->team == TEAM_FRIENDLY){
8686                         multi_team_filter = 0;
8687                 } else if(sp->team == TEAM_HOSTILE){
8688                         multi_team_filter = 1;
8689                 }
8690         }
8691
8692         if ( message_type >= 0 ) {
8693                 if ( rand() & 1 ) {
8694                         message_send_builtin_to_player(message_type, sp, MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter);
8695                 }
8696                 Player->request_repair_timestamp = timestamp(PLAYER_REQUEST_REPAIR_MSG_INTERVAL);
8697         }
8698 }
8699
8700 // The current primary weapon or link status for a ship has changed.. notify clients if multiplayer
8701 //
8702 // input:       sp                      =>      pointer to ship that modified primaries
8703 void ship_primary_changed(ship *sp)
8704 {
8705 #if 0
8706         ship_weapon     *swp;
8707
8708         // we only need to deal with multiplayer issues for now, so bail it not multiplayer
8709         if ( !(Game_mode & GM_MULTIPLAYER) )
8710                 return;
8711
8712         SDL_assert(sp);
8713         swp = &sp->weapons;
8714
8715         
8716         if ( MULTIPLAYER_MASTER )
8717                 send_ship_weapon_change( sp, MULTI_PRIMARY_CHANGED, swp->current_primary_bank, (sp->flags & SF_PRIMARY_LINKED)?1:0 );
8718 #endif
8719 }
8720
8721 // The current secondary weapon or dual-fire status for a ship has changed.. notify clients if multiplayer
8722 //
8723 // input:       sp                                      =>      pointer to ship that modified secondaries
8724 void ship_secondary_changed(ship *sp)
8725 {
8726 #if 0
8727         ship_weapon     *swp;
8728
8729         // we only need to deal with multiplayer issues for now, so bail it not multiplayer
8730         if ( !(Game_mode & GM_MULTIPLAYER) ){
8731                 return;
8732         }
8733
8734         SDL_assert(sp);
8735         swp = &sp->weapons;
8736
8737         if ( MULTIPLAYER_MASTER )
8738                 send_ship_weapon_change( sp, MULTI_SECONDARY_CHANGED, swp->current_secondary_bank, (sp->flags & SF_SECONDARY_DUAL_FIRE)?1:0 );
8739 #endif
8740 }
8741
8742 int ship_get_SIF(ship *shipp)
8743 {
8744         return Ship_info[shipp->ship_info_index].flags;
8745 }
8746
8747 int ship_get_SIF(int sh)
8748 {
8749         return Ship_info[Ships[sh].ship_info_index].flags;
8750 }
8751
8752 int ship_get_by_signature(int signature)
8753 {
8754         ship_obj *so;
8755                 
8756         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
8757                 // if we found a matching ship object signature
8758                 if((Objects[so->objnum].signature == signature) && (Objects[so->objnum].type == OBJ_SHIP)){
8759                         return Objects[so->objnum].instance;
8760                 }
8761         }
8762
8763         // couldn't find the ship
8764         return -1;
8765 }
8766
8767 // function which gets called when the cargo of a ship is revealed.  Happens at two different locations
8768 // (at least when this function was written), one for the player, and one for AI ships.  Need to send stuff
8769 // to clients in multiplayer game.
8770 void ship_do_cargo_revealed( ship *shipp, int from_network )
8771 {
8772         // don't do anything if we already know the cargo
8773         if ( shipp->flags & SF_CARGO_REVEALED ){
8774                 return;
8775         }
8776         
8777         nprintf(("Network", "Revealing cargo for %s\n", shipp->ship_name));
8778
8779         // send the packet if needed
8780         if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
8781                 send_cargo_revealed_packet( shipp );            
8782         }
8783
8784         shipp->flags |= SF_CARGO_REVEALED;
8785         shipp->time_cargo_revealed = Missiontime;       
8786
8787         // if the cargo is something other than "nothing", then make a log entry
8788         if ( SDL_strcasecmp(Cargo_names[shipp->cargo1 & CARGO_INDEX_MASK], NOX("nothing")) ){
8789                 mission_log_add_entry(LOG_CARGO_REVEALED, shipp->ship_name, NULL, (shipp->cargo1 & CARGO_INDEX_MASK) );
8790         }       
8791 }
8792
8793 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network )
8794 {
8795         if ( subsys->subsys_cargo_revealed ) {
8796                 return;
8797         }
8798
8799         
8800         nprintf(("Network", "Revealing cap ship subsys cargo for %s\n", shipp->ship_name));
8801
8802         // send the packet if needed
8803         if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
8804                 int subsystem_index = ship_get_index_from_subsys(subsys, shipp->objnum);
8805                 send_subsystem_cargo_revealed_packet( shipp, subsystem_index );         
8806         }
8807
8808         subsys->subsys_cargo_revealed = 1;
8809
8810         // if the cargo is something other than "nothing", then make a log entry
8811         if ( (subsys->subsys_cargo_name > 0) && SDL_strcasecmp(Cargo_names[subsys->subsys_cargo_name], NOX("nothing")) ){
8812                 mission_log_add_entry(LOG_CAP_SUBSYS_CARGO_REVEALED, shipp->ship_name, subsys->system_info->name, subsys->subsys_cargo_name );
8813         }       
8814 }
8815
8816
8817 // Return the range of the currently selected secondary weapon
8818 // NOTE: If there is no missiles left in the current bank, range returned is 0
8819 float ship_get_secondary_weapon_range(ship *shipp)
8820 {
8821         float srange=0.0f;
8822
8823         ship_weapon     *swp;
8824         swp = &shipp->weapons;
8825         if ( swp->current_secondary_bank >= 0 ) {
8826                 weapon_info     *wip;
8827                 int bank=swp->current_secondary_bank;
8828                 wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
8829                 if ( swp->secondary_bank_ammo[bank] > 0 ) {
8830                         srange = wip->max_speed * wip->lifetime;
8831                 }
8832         }
8833
8834         return srange;
8835 }
8836
8837 // Determine the number of secondary ammo units (missile/bomb) allowed max for a ship
8838 //
8839 int get_max_ammo_count_for_bank(int ship_class, int bank, int ammo_type)
8840 {
8841         float capacity, size;
8842
8843         capacity = (float) Ship_info[ship_class].secondary_bank_ammo_capacity[bank];
8844         size = (float) Weapon_info[ammo_type].cargo_size;
8845         return (int) (capacity / size);
8846 }
8847
8848
8849
8850 // Page in bitmaps for all the ships in this level
8851 void ship_page_in()
8852 {
8853         int i,j;
8854         int num_subsystems_needed = 0;
8855
8856         int ship_class_used[MAX_SHIP_TYPES];
8857
8858         // Mark all ship classes as not used
8859         for (i=0; i<MAX_SHIP_TYPES; i++ )       {
8860                 ship_class_used[i] = 0;
8861         }
8862
8863         // Mark any support ship types as used
8864         // 
8865         for (i=0; i<Num_ship_types; i++ )       {
8866                 if ( Ship_info[i].flags & SIF_SUPPORT ) {
8867                         nprintf(( "Paging", "Found support ship '%s'\n", Ship_info[i].name ));
8868                         ship_class_used[i]++;
8869
8870                         num_subsystems_needed += Ship_info[i].n_subsystems;
8871                 }
8872         }
8873         
8874         // Mark any ships in the mission as used
8875         //
8876         for (i=0; i<MAX_SHIPS; i++)     {
8877                 if (Ships[i].objnum > -1)       {
8878                         nprintf(( "Paging","Found ship '%s'\n", Ships[i].ship_name ));
8879                         ship_class_used[Ships[i].ship_info_index]++;
8880
8881                         num_subsystems_needed += Ship_info[Ships[i].ship_info_index].n_subsystems;
8882                 }
8883         }
8884
8885         // Mark any ships that might warp in in the future as used
8886         //
8887         p_object * p_objp;
8888         for( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) )     {
8889                 nprintf(( "Paging","Found future arrival ship '%s'\n", p_objp->name ));
8890                 ship_class_used[p_objp->ship_class]++;
8891
8892                 num_subsystems_needed += Ship_info[p_objp->ship_class].n_subsystems;
8893         }
8894
8895
8896         // Page in all the ship classes that are used on this level
8897         //
8898         int num_ship_types_used = 0;
8899
8900         for (i=0; i<MAX_SHIP_TYPES; i++ )       {
8901                 if ( ship_class_used[i]  )      {
8902                         ship_info *si = &Ship_info[i];
8903
8904                         num_ship_types_used++;
8905
8906                         // Page in the small hud icons for each ship
8907                         {
8908                                 extern void hud_ship_icon_page_in(ship_info *sip);
8909
8910                                 hud_ship_icon_page_in(si);
8911
8912                         }
8913
8914                         // See if this model was previously loaded by another ship
8915                         int model_previously_loaded = -1;
8916                         int ship_previously_loaded = -1;
8917                         for (j=0; j<MAX_SHIP_TYPES; j++ )       {
8918                                 if ( (Ship_info[j].modelnum > -1) && !SDL_strcasecmp(si->pof_file, Ship_info[j].pof_file) )     {
8919                                         // Model already loaded
8920                                         model_previously_loaded = Ship_info[j].modelnum;
8921                                         ship_previously_loaded = j;
8922                                         break;
8923                                 }
8924                         }
8925
8926                         // If the model is previously loaded...
8927                         if ( model_previously_loaded > -1 )     {
8928
8929                                 // If previously loaded model isn't the same ship class...)
8930                                 if ( ship_previously_loaded != i )      {
8931
8932                                         // update the model number.
8933                                         si->modelnum = model_previously_loaded;
8934
8935                                         for ( j = 0; j < si->n_subsystems; j++ )        {
8936                                                 si->subsystems[j].model_num = -1;
8937                                         }
8938
8939                                         ship_copy_subsystem_fixup(si);
8940
8941                                         #ifndef NDEBUG
8942                                                 for ( j = 0; j < si->n_subsystems; j++ )        {
8943                                                         SDL_assert( si->subsystems[j].model_num == si->modelnum );
8944                                                 }
8945                                         #endif
8946
8947                                 } else {
8948                                         // Just to be safe (I mean to check that my code works...)
8949                                         SDL_assert( si->modelnum > -1 );
8950                                         SDL_assert( si->modelnum == model_previously_loaded );
8951
8952                                         #ifndef NDEBUG
8953                                                 for ( j = 0; j < si->n_subsystems; j++ )        {
8954                                                         SDL_assert( si->subsystems[j].model_num == si->modelnum );
8955                                                 }
8956                                         #endif
8957                                 }
8958                         } else {
8959                                 // Model not loaded... so load it and page in its textures
8960                                 si->modelnum = model_load(si->pof_file, si->n_subsystems, &si->subsystems[0]);
8961
8962                                 SDL_assert( si->modelnum > -1 );
8963
8964                                 // Verify that all the subsystem model numbers are updated
8965                                 #ifndef NDEBUG
8966                                         for ( j = 0; j < si->n_subsystems; j++ )        {
8967                                                 SDL_assert( si->subsystems[j].model_num == si->modelnum );      // JAS
8968                                         }
8969                                 #endif
8970
8971                         }
8972         
8973                 }
8974         }
8975
8976         for (i=0; i<MAX_SHIP_TYPES; i++ )       {
8977                 if ( ship_class_used[i]  )      {
8978                         ship_info *si = &Ship_info[i];
8979
8980                         if ( si->modelnum > -1 )        {
8981                                 polymodel *pm = model_get(si->modelnum);
8982                                 
8983                                 nprintf(( "Paging", "Paging in textures for model '%s'\n", si->pof_file ));
8984
8985                                 for (j=0; j<pm->n_textures; j++ )       {
8986                                         int bitmap_num = pm->original_textures[j];
8987
8988                                         if ( bitmap_num > -1 )  {
8989                                                 bm_page_in_texture( bitmap_num );
8990                                         }
8991                                 }
8992
8993                         } else {
8994                                 nprintf(( "Paging", "Couldn't load model '%s'\n", si->pof_file ));
8995                         }
8996                 }
8997         }
8998
8999         nprintf(( "Paging", "There are %d ship classes used in this mission.\n", num_ship_types_used ));
9000         mprintf(( "This mission requires %d Ship_subsystems. See #define MAX_SHIP_SUBOBJECTS.\n", num_subsystems_needed ));
9001
9002         // JAS: If you hit this, then MAX_SHIP_SUBOBJECTS is set too low.
9003         // I added this code in to detect an error that wasn't getting detected any other
9004         // way.
9005         SDL_assert(num_subsystems_needed < MAX_SHIP_SUBOBJECTS );       
9006
9007         // Page in the thruster effects
9008         //
9009
9010         // Make sure thrusters are loaded
9011         if ( !Thrust_anim_inited )      ship_init_thrusters();
9012
9013         for ( i = 0; i < NUM_THRUST_ANIMS; i++ ) {
9014                 thrust_anim     *ta = &Thrust_anims[i];
9015                 for ( j = 0; j<ta->num_frames; j++ )    {
9016                         bm_page_in_texture( ta->first_frame + j );
9017                 }
9018         }
9019
9020         for ( i = 0; i < NUM_THRUST_GLOW_ANIMS; i++ ) {
9021                 thrust_anim     *ta = &Thrust_glow_anims[i];
9022                 // glows are really not anims
9023                 bm_page_in_texture( ta->first_frame );
9024         }
9025
9026         // page in insignia bitmaps
9027         if(Game_mode & GM_MULTIPLAYER){
9028                 for(i=0; i<MAX_PLAYERS; i++){
9029                         if(MULTI_CONNECTED(Net_players[i]) && (Net_players[i].player != NULL) && (Net_players[i].player->insignia_texture >= 0)){
9030                                 bm_page_in_xparent_texture(Net_players[i].player->insignia_texture);
9031                         }
9032                 }
9033         } else {
9034                 if((Player != NULL) && (Player->insignia_texture >= 0)){
9035                         bm_page_in_xparent_texture(Player->insignia_texture);
9036                 }
9037         }
9038 }
9039
9040 // function to return true if support ships are allowed in the mission for the given object.
9041 //      In single player, must be friendly and not Shivan.
9042 //      In multiplayer -- to be coded by Mark Allender after 5/4/98 -- MK, 5/4/98
9043 int is_support_allowed(object *objp)
9044 {
9045         if (The_mission.disallow_support){
9046                 return 0;
9047         }
9048
9049         if ( Game_mode & GM_NORMAL ) {
9050                 if (Ships[objp->instance].team != TEAM_FRIENDLY){
9051                         return 0;
9052                 }
9053
9054                 switch (Ship_info[Ships[objp->instance].ship_info_index].species) {
9055                 case SPECIES_TERRAN:
9056                         break;
9057                 case SPECIES_VASUDAN:
9058                         break;
9059                 case SPECIES_SHIVAN:
9060                         return 0;
9061                 case SPECIES_NONE:
9062                         break;
9063                 }
9064
9065                 return 1;
9066         } else {
9067                 // multiplayer version behaves differently.  Depending on mode:
9068                 // 1) coop mode -- only available to friendly
9069                 // 2) team v team mode -- availble to either side
9070                 // 3) dogfight -- never
9071
9072                 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
9073                         return 0;
9074                 }
9075
9076                 if ( IS_MISSION_MULTI_COOP ) {
9077                         if ( Ships[objp->instance].team != TEAM_FRIENDLY ){
9078                                 return 0;
9079                         }
9080                 }
9081
9082                 return 1;
9083         }
9084
9085 }
9086
9087 // return ship index
9088 int ship_get_random_ship()
9089 {
9090         int num_ships;
9091         int rand_ship;
9092         int idx;
9093         ship_obj *so;
9094
9095         // get the # of ships on the list
9096         num_ships = ship_get_num_ships();
9097
9098         // get a random ship on the list
9099         rand_ship = (int)frand_range(0.0f, (float)(num_ships - 1));
9100         if(rand_ship < 0){
9101                 rand_ship = 0;
9102         } 
9103         if(rand_ship > num_ships){
9104                 rand_ship = num_ships;
9105         }
9106
9107         // find this guy
9108         so = GET_FIRST(&Ship_obj_list);
9109         for(idx=0; idx<rand_ship; idx++) {
9110                 so = GET_NEXT(so);
9111         }
9112
9113         return Objects[so->objnum].instance;
9114 }
9115
9116 // forcible jettison cargo from a ship
9117 void ship_jettison_cargo(ship *shipp)
9118 {
9119         object *objp;
9120         object *cargo_objp;
9121         vector impulse, pos;
9122
9123         // make sure we are docked with a valid object
9124         if(shipp->objnum < 0){
9125                 return;
9126         }
9127         objp = &Objects[shipp->objnum];
9128         if(Ai_info[shipp->ai_index].dock_objnum == -1){
9129                 return;
9130         }
9131         if(Objects[Ai_info[shipp->ai_index].dock_objnum].type != OBJ_SHIP){
9132                 Int3();
9133                 return;
9134         }
9135         if(Ai_info[Ships[Objects[Ai_info[shipp->ai_index].dock_objnum].instance].ai_index].dock_objnum != OBJ_INDEX(objp)){
9136                 return;
9137         }
9138         cargo_objp = &Objects[Ai_info[shipp->ai_index].dock_objnum];
9139
9140         // undock the objects
9141         ai_do_objects_undocked_stuff( objp, cargo_objp );
9142         
9143         // physics stuff
9144         vm_vec_sub(&pos, &cargo_objp->pos, &objp->pos);
9145         impulse = pos;
9146         vm_vec_scale(&impulse, 100.0f);
9147         vm_vec_normalize(&pos);
9148
9149         // whack the ship
9150         physics_apply_whack(&impulse, &pos, &cargo_objp->phys_info, &cargo_objp->orient, cargo_objp->phys_info.mass);
9151 }
9152
9153 float ship_get_exp_damage(object* objp)
9154 {
9155         SDL_assert(objp->type == OBJ_SHIP);
9156         float damage; 
9157
9158         ship *shipp = &Ships[objp->instance];
9159
9160         if (shipp->special_exp_index != -1) {
9161                 damage = (float) atoi(Sexp_variables[shipp->special_exp_index+DAMAGE].text);
9162         } else {
9163                 damage = Ship_info[shipp->ship_info_index].damage;
9164         }
9165
9166         return damage;
9167 }
9168
9169 int ship_get_exp_propagates(ship *sp)
9170 {
9171         return Ship_info[sp->ship_info_index].explosion_propagates;
9172 }
9173
9174 float ship_get_exp_outer_rad(object *ship_objp)
9175 {
9176         float outer_rad;
9177         SDL_assert(ship_objp->type == OBJ_SHIP);
9178
9179         if (Ships[ship_objp->instance].special_exp_index == -1) {
9180                 outer_rad = Ship_info[Ships[ship_objp->instance].ship_info_index].outer_rad;
9181         } else {
9182                 outer_rad = (float) atoi(Sexp_variables[Ships[ship_objp->instance].special_exp_index+OUTER_RAD].text);
9183         }
9184
9185         return outer_rad;
9186 }
9187
9188 int valid_cap_subsys_cargo_list(char *subsys)
9189 {
9190         if (strstr(subsys, "nav")
9191                 || strstr(subsys, "comm")
9192                 || strstr(subsys, "engines")
9193                 || strstr(subsys, "fighter")    // fighter bays
9194                 || strstr(subsys, "sensors")
9195                 || strstr(subsys, "weapons")) {
9196
9197                 return 1;
9198         }
9199
9200         return 0;
9201 }
9202
9203 // determine turret status of a given subsystem, returns 0 for no turret, 1 for "fixed turret", 2 for "rotating" turret
9204 int ship_get_turret_type(ship_subsys *subsys)
9205 {
9206         // not a turret at all
9207         if(subsys->system_info->type != SUBSYSTEM_TURRET){
9208                 return 0;
9209         }
9210
9211         // if it rotates
9212         if(subsys->system_info->turret_turning_rate > 0.0f){
9213                 return 2;
9214         }
9215
9216         // if its fixed
9217         return 1;
9218 }
9219
9220 ship_subsys *ship_get_subsys(ship *shipp, char *subsys_name)
9221 {
9222         ship_subsys *lookup;
9223
9224         // sanity checks
9225         if((shipp == NULL) || (subsys_name == NULL)){
9226                 return NULL;
9227         }
9228
9229         lookup = GET_FIRST(&shipp->subsys_list);
9230         while(lookup != END_OF_LIST(&shipp->subsys_list)){
9231                 // turret
9232                 if(!strcmp(lookup->system_info->subobj_name, subsys_name)){
9233                         return lookup;
9234                 }
9235
9236                 // next
9237                 lookup = GET_NEXT(lookup);
9238         }
9239
9240         // didn't find it
9241         return NULL;
9242 }
9243
9244 // returns 0 if no conflict, 1 if conflict, -1 on some kind of error with wing struct
9245 int wing_has_conflicting_teams(int wing_index)
9246 {
9247         int first_team, idx;
9248
9249         // sanity checks
9250         SDL_assert((wing_index >= 0) && (wing_index < num_wings) && (Wings[wing_index].current_count > 0));
9251         if((wing_index < 0) || (wing_index >= num_wings) || (Wings[wing_index].current_count <= 0)){
9252                 return -1;
9253         }
9254
9255         // check teams
9256         SDL_assert(Wings[wing_index].ship_index[0] >= 0);
9257         if(Wings[wing_index].ship_index[0] < 0){
9258                 return -1;
9259         }
9260         first_team = Ships[Wings[wing_index].ship_index[0]].team;
9261         for(idx=1; idx<Wings[wing_index].current_count; idx++){
9262                 // more sanity checks
9263                 SDL_assert(Wings[wing_index].ship_index[idx] >= 0);
9264                 if(Wings[wing_index].ship_index[idx] < 0){
9265                         return -1;
9266                 }
9267
9268                 // if we've got a team conflict
9269                 if(first_team != Ships[Wings[wing_index].ship_index[idx]].team){
9270                         return 1;
9271                 }
9272         }
9273
9274         // no conflict
9275         return 0;
9276 }
9277
9278 // get the team of a reinforcement item
9279 int ship_get_reinforcement_team(int r_index)
9280 {
9281         int wing_index;
9282         p_object *objp;
9283
9284         // sanity checks
9285         SDL_assert((r_index >= 0) && (r_index < Num_reinforcements));
9286         if((r_index < 0) || (r_index >= Num_reinforcements)){
9287                 return -1;
9288         }
9289
9290         // if the reinforcement is a ship       
9291         objp = mission_parse_get_arrival_ship( Reinforcements[r_index].name );
9292         if(objp != NULL){
9293                 return objp->team;
9294         }
9295
9296         // if the reinforcement is a ship
9297         wing_index = wing_lookup(Reinforcements[r_index].name);
9298         if(wing_index >= 0){            
9299                 // go through the ship arrival list and find the first ship in this wing
9300                 objp = GET_FIRST(&ship_arrival_list);
9301                 while( objp != END_OF_LIST(&ship_arrival_list) )        {
9302                         // check by wingnum                     
9303                         if (objp->wingnum == wing_index) {
9304                                 return objp->team;
9305                         }
9306
9307                         // next
9308                         objp = GET_NEXT(objp);
9309                 }
9310         }
9311
9312         // no team ?
9313         return -1;
9314 }
9315
9316 // determine if the given texture is used by a ship type. return ship info index, or -1 if not used by a ship
9317 int ship_get_texture(int bitmap)
9318 {
9319         int idx;
9320
9321         // check all ship types
9322         for(idx=0; idx<Num_ship_types; idx++){
9323                 if((Ship_info[idx].modelnum >= 0) && model_find_texture(Ship_info[idx].modelnum, bitmap) == 1){
9324                         return idx;
9325                 }
9326         }
9327
9328         // couldn't find the texture
9329         return -1;
9330 }
9331
9332 extern void ssm_create(vector *target, vector *start, int ssm_index, ssm_firing_info *override);
9333
9334 // update artillery lock info
9335 #define CLEAR_ARTILLERY_AND_CONTINUE()  { if(aip != NULL){ aip->artillery_objnum = -1; aip->artillery_sig = -1; aip->artillery_lock_time = 0.0f;} continue; } 
9336 float artillery_dist = 10.0f;
9337 DCF(art, "")
9338 {
9339         dc_get_arg(ARG_FLOAT);
9340         artillery_dist = Dc_arg_float;
9341 }
9342 void ship_update_artillery_lock()
9343 {
9344 #if defined(MULTIPLAYER_BETA_BUILD) || defined(FS2_DEMO) || defined(FS1_DEMO)
9345         return;
9346 #else
9347         ai_info *aip = NULL;
9348         weapon_info *tlaser = NULL;
9349         mc_info *cinfo = NULL;
9350         int c_objnum;
9351         vector temp, local_hit;
9352         ship *shipp;
9353         ship_obj *so;
9354
9355         // update all ships
9356         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ){
9357                 // get the ship
9358                 if((so->objnum >= 0) && (Objects[so->objnum].type == OBJ_SHIP) && (Objects[so->objnum].instance >= 0)){
9359                         shipp = &Ships[Objects[so->objnum].instance];
9360                 } else {
9361                         continue;
9362                 }               
9363
9364                 // get ai info
9365                 if(shipp->ai_index >= 0){
9366                         aip = &Ai_info[shipp->ai_index];
9367                 }
9368
9369                 // if the ship has no targeting laser firing
9370                 if((shipp->targeting_laser_objnum < 0) || (shipp->targeting_laser_bank < 0)){
9371                         CLEAR_ARTILLERY_AND_CONTINUE();
9372                 }
9373
9374                 // if he didn't hit any objects this frame
9375                 if(beam_get_num_collisions(shipp->targeting_laser_objnum) <= 0){
9376                         CLEAR_ARTILLERY_AND_CONTINUE();
9377                 }
9378
9379                 // get weapon info for the targeting laser he's firing
9380                 SDL_assert((shipp->weapons.current_primary_bank >= 0) && (shipp->weapons.current_primary_bank < 2));
9381                 if((shipp->weapons.current_primary_bank < 0) || (shipp->weapons.current_primary_bank >= 2)){
9382                         continue;
9383                 }
9384                 SDL_assert(shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= 0);
9385                 if(shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0){
9386                         continue;
9387                 }
9388                 SDL_assert((Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags & WIF_BEAM) && (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].b_info.beam_type == BEAM_TYPE_C));
9389                 if(!(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags & WIF_BEAM) || (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].b_info.beam_type != BEAM_TYPE_C)){
9390                         continue;
9391                 }
9392                 tlaser = &Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]];        
9393
9394                 // get collision info
9395                 if(!beam_get_collision(shipp->targeting_laser_objnum, 0, &c_objnum, &cinfo)){
9396                         CLEAR_ARTILLERY_AND_CONTINUE();
9397                 }
9398                 if((c_objnum < 0) || (cinfo == NULL)){
9399                         CLEAR_ARTILLERY_AND_CONTINUE();
9400                 }
9401
9402                 // get the position we hit this guy with in his local coords
9403                 vm_vec_sub(&temp, &cinfo->hit_point_world, &Objects[c_objnum].pos);
9404                 vm_vec_rotate(&local_hit, &temp, &Objects[c_objnum].orient);
9405
9406                 // if we are hitting a different guy now, reset the lock
9407                 if((c_objnum != aip->artillery_objnum) || (Objects[c_objnum].signature != aip->artillery_sig)){
9408                         aip->artillery_objnum = c_objnum;
9409                         aip->artillery_sig = Objects[c_objnum].signature;
9410                         aip->artillery_lock_time = 0.0f;
9411                         aip->artillery_lock_pos = local_hit;
9412
9413                         // done
9414                         continue;
9415                 }       
9416
9417                 // otherwise we're hitting the same guy. check to see if we've strayed too far
9418                 if(vm_vec_dist_quick(&local_hit, &aip->artillery_lock_pos) > artillery_dist){
9419                         // hmmm. reset lock time, but don't reset the lock itself
9420                         aip->artillery_lock_time = 0.0f;
9421                         continue;
9422                 }
9423
9424                 // finally - just increment the lock time
9425                 aip->artillery_lock_time += flFrametime;
9426
9427                 // TEST CODE
9428                 if(aip->artillery_lock_time >= 2.0f){
9429
9430                         HUD_printf("Firing artillery");
9431
9432                         vector temp;
9433                         vm_vec_unrotate(&temp, &aip->artillery_lock_pos, &Objects[aip->artillery_objnum].orient);
9434                         vm_vec_add2(&temp, &Objects[aip->artillery_objnum].pos);                        
9435                         ssm_create(&temp, &Objects[so->objnum].pos, 0, NULL);                           
9436
9437                         // reset the artillery                  
9438                         aip->artillery_lock_time = 0.0f;                        
9439                 }
9440         }
9441 #endif
9442 }
9443
9444 // checks if a world point is inside the extended bounding box of a ship
9445 // may not work if delta box is large and negative (ie, adjusted box crosses over on itself - min > max)
9446 int check_world_pt_in_expanded_ship_bbox(vector *world_pt, object *objp, float delta_box)
9447 {
9448         SDL_assert(objp->type == OBJ_SHIP);
9449
9450         vector temp, ship_pt;
9451         polymodel *pm;
9452         vm_vec_sub(&temp, world_pt, &objp->pos);
9453         vm_vec_rotate(&ship_pt, &temp, &objp->orient);
9454
9455         pm = model_get(Ships[objp->instance].modelnum);
9456
9457         return (
9458                         (ship_pt.xyz.x > pm->mins.xyz.x - delta_box) && (ship_pt.xyz.x < pm->maxs.xyz.x + delta_box)
9459                 && (ship_pt.xyz.y > pm->mins.xyz.y - delta_box) && (ship_pt.xyz.y < pm->maxs.xyz.y + delta_box)
9460                 && (ship_pt.xyz.z > pm->mins.xyz.z - delta_box) && (ship_pt.xyz.z < pm->maxs.xyz.z + delta_box)
9461         );
9462 }
9463
9464
9465 // returns true when objp is ship and is tagged
9466 int ship_is_tagged(object *objp)
9467 {
9468         ship *shipp;
9469         if (objp->type == OBJ_SHIP) {
9470                 shipp = &Ships[objp->instance];
9471                 if ( (shipp->tag_left > 0) || (shipp->level2_tag_left > 0) ) {
9472                         return 1;
9473                 }
9474         }
9475
9476         return 0;
9477 }
9478
9479 // get maximum ship speed (when not warping in or out)
9480 float ship_get_max_speed(ship *shipp)
9481 {
9482         float max_speed;
9483
9484         int ship_info_index = shipp->ship_info_index;
9485
9486         // max overclodk
9487         max_speed = Ship_info[ship_info_index].max_overclocked_speed;
9488
9489         // normal max speed
9490         max_speed = max(max_speed, Ship_info[ship_info_index].max_vel.xyz.z);
9491
9492         // afterburn
9493         max_speed = max(max_speed, Ship_info[ship_info_index].afterburner_max_vel.xyz.z);
9494
9495         return max_speed;
9496 }
9497
9498 // determin warp speed of ship
9499 float ship_get_warp_speed(object *objp)
9500 {
9501         SDL_assert(objp->type == OBJ_SHIP);
9502         float shipfx_calculate_warp_speed(object *);
9503         return shipfx_calculate_warp_speed(objp);
9504 }
9505
9506 // returns true if ship is beginning to speed up in warpout 
9507 int ship_is_beginning_warpout_speedup(object *objp)
9508 {
9509         SDL_assert(objp->type == OBJ_SHIP);
9510
9511         ai_info *aip;
9512
9513         aip = &Ai_info[Ships[objp->instance].ai_index];
9514
9515         if (aip->mode == AIM_WARP_OUT) {
9516                 if ( (aip->submode == AIS_WARP_3) || (aip->submode == AIS_WARP_4) || (aip->submode == AIS_WARP_5) ) {
9517                         return 1;
9518                 }
9519         }
9520
9521         return 0;
9522 }
9523
9524 // given a ship info type, return a species
9525 int ship_get_species_by_type(int ship_info_index)
9526 {
9527         // sanity
9528         if((ship_info_index < 0) || (ship_info_index >= Num_ship_types)){
9529                 return -1;
9530         }
9531
9532         // return species
9533         return Ship_info[ship_info_index].species;
9534 }
9535
9536 // return the length of a ship
9537 float ship_get_length(ship* shipp)
9538 {
9539         polymodel *pm = model_get(shipp->modelnum);
9540         return (pm->maxs.xyz.z - pm->mins.xyz.z);
9541 }
9542