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