]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multimsgs.cpp
deal with static analyzer warnings
[taylor/freespace2.git] / src / network / multimsgs.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/Network/MultiMsgs.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C file that holds functions for the building and processing of multiplayer packets
16  *
17  * $Log$
18  * Revision 1.11  2006/04/26 19:48:58  taylor
19  * various big-endian fixes, mainly networking support related
20  *
21  * Revision 1.10  2005/10/02 09:30:10  taylor
22  * sync up rest of big-endian network changes.  it should at least be as good as what's in FS2_Open now, only better :)
23  *
24  * Revision 1.9  2005/08/12 08:59:17  taylor
25  * small endianess fix
26  *
27  * Revision 1.8  2004/09/20 01:31:44  theoddone33
28  * GCC 3.4 fixes.
29  *
30  * Revision 1.7  2004/06/11 01:49:45  tigital
31  * byte-swapping changes for bigendian systems
32  *
33  * Revision 1.6  2003/08/03 16:10:29  taylor
34  * cleanup; compile warning fixes
35  *
36  * Revision 1.5  2002/06/17 06:33:10  relnev
37  * ryan's struct patch for gcc 2.95
38  *
39  * Revision 1.4  2002/06/09 04:41:24  relnev
40  * added copyright header
41  *
42  * Revision 1.3  2002/05/26 20:49:54  theoddone33
43  * More progress
44  *
45  * Revision 1.2  2002/05/07 03:16:47  theoddone33
46  * The Great Newline Fix
47  *
48  * Revision 1.1.1.1  2002/05/03 03:28:10  root
49  * Initial import.
50  *
51  * 
52  * 83    9/14/99 2:21p Dave
53  * Fixed observer mode joining and ingame stuff.
54  * 
55  * 82    9/14/99 3:26a Dave
56  * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
57  * respawn-too-early problem. Made a few crash points safe.
58  * 
59  * 81    9/13/99 4:52p Dave
60  * RESPAWN FIX
61  * 
62  * 80    9/08/99 10:01p Dave
63  * Make sure game won't run in a drive's root directory. Make sure
64  * standalone routes suqad war messages properly to the host.
65  * 
66  * 79    8/28/99 4:54p Dave
67  * Fixed directives display for multiplayer clients for wings with
68  * multiple waves. Fixed hud threat indicator rendering color.
69  * 
70  * 78    8/27/99 12:32a Dave
71  * Allow the user to specify a local port through the launcher.
72  * 
73  * 77    8/26/99 8:51p Dave
74  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
75  * 
76  * 76    8/25/99 4:38p Dave
77  * Updated PXO stuff. Make squad war report stuff much more nicely.
78  * 
79  * 75    8/24/99 1:50a Dave
80  * Fixed client-side afterburner stuttering. Added checkbox for no version
81  * checking on PXO join. Made button info passing more friendly between
82  * client and server.
83  * 
84  * 74    8/22/99 5:53p Dave
85  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
86  * instead of ship designations for multiplayer players.
87  * 
88  * 73    8/22/99 1:55p Dave
89  * Cleaned up host/team-captain leaving code.
90  * 
91  * 72    8/22/99 1:19p Dave
92  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
93  * which d3d cards are detected.
94  * 
95  * 71    8/19/99 10:59a Dave
96  * Packet loss detection.
97  * 
98  * 70    8/17/99 1:12p Dave
99  * Send TvT update when a client has finished joining so he stays nice and
100  * synched.
101  * 
102  * 69    8/16/99 4:05p Dave
103  * Big honking checkin.
104  * 
105  * 68    8/11/99 5:54p Dave
106  * Fixed collision problem. Fixed standalone ghost problem.
107  * 
108  * 67    8/06/99 9:46p Dave
109  * Hopefully final changes for the demo.
110  * 
111  * 66    8/05/99 2:06a Dave
112  * Whee.
113  * 
114  * 65    7/30/99 7:01p Dave
115  * Dogfight escort gauge. Fixed up laser rendering in Glide.
116  * 
117  * 64    7/29/99 5:41p Jefff
118  * Sound hooks for cmeasure success
119  * 
120  * 63    7/28/99 5:34p Dave
121  * Nailed the missing stats bug to the wall. Problem was optimized build
122  * and using GET_DATA() with array elements. BLECH.
123  * 
124  * 62    7/26/99 5:50p Dave
125  * Revised ingame join. Better? We'll see....
126  * 
127  * 61    7/24/99 1:54p Dave
128  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
129  * missions.
130  * 
131  * 60    7/22/99 7:17p Dave
132  * Fixed excessive whacks in multiplayer.
133  * 
134  * 59    7/08/99 10:53a Dave
135  * New multiplayer interpolation scheme. Not 100% done yet, but still
136  * better than the old way.
137  * 
138  * 58    7/03/99 5:50p Dave
139  * Make rotated bitmaps draw properly in padlock views.
140  * 
141  * 57    7/03/99 4:08p Dave
142  * Fixed wss_slots size issues. Fixed potentially nasty bug in low level
143  * reliable code.
144  * 
145  * 56    6/21/99 7:24p Dave
146  * netplayer pain packet. Added type E unmoving beams.
147  * 
148  * 55    6/18/99 5:16p Dave
149  * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
150  * dialog to PXO screen.
151  * 
152  * 54    6/16/99 4:06p Dave
153  * New pilot info popup. Added new draw-bitmap-as-poly function.
154  * 
155  * 53    6/16/99 10:20a Dave
156  * Added send-message-list sexpression.
157  * 
158  * 52    6/04/99 3:52p Anoop
159  * Removed bogus assert.
160  * 
161  * 51    6/01/99 8:35p Dave
162  * Finished lockarm weapons. Added proper supercap weapons/damage. Added
163  * awacs-set-radius sexpression.
164  * 
165  * 50    5/21/99 5:03p Andsager
166  * Add code to display engine wash death.  Modify ship_kill_packet
167  * 
168  * 49    5/18/99 1:30p Dave
169  * Added muzzle flash table stuff.
170  * 
171  * 48    5/14/99 1:59p Andsager
172  * Multiplayer message for subsystem cargo revealed.
173  * 
174  * 47    5/14/99 12:15p Andsager
175  * Add vaporized to kill packet
176  * 
177  * 46    5/03/99 8:32p Dave
178  * New version of multi host options screen.
179  * 
180  * 45    4/30/99 12:18p Dave
181  * Several minor bug fixes.
182  * 
183  * 44    4/29/99 2:29p Dave
184  * Made flak work much better in multiplayer.
185  * 
186  * 43    4/28/99 11:13p Dave
187  * Temporary checkin of artillery code.
188  * 
189  * 42    4/16/99 5:54p Dave
190  * Support for on/off style "stream" weapons. Real early support for
191  * target-painting lasers.
192  * 
193  * 41    4/12/99 2:22p Dave
194  * More checks for dogfight stats.
195  * 
196  * 40    4/09/99 2:21p Dave
197  * Multiplayer beta stuff. CD checking.
198  * 
199  * 39    4/02/99 9:55a Dave
200  * Added a few more options in the weapons.tbl for beam weapons. Attempt
201  * at putting "pain" packets into multiplayer.
202  * 
203  * 38    4/01/99 3:41p Anoop
204  * Removed bogus Int3().
205  * 
206  * 37    3/19/99 9:51a Dave
207  * Checkin to repair massive source safe crash. Also added support for
208  * pof-style nebulae, and some new weapons code.
209  * 
210  * 38    3/12/99 2:32p Anoop
211  * Removed bogus asserts.
212  * 
213  * 37    3/11/99 11:41a Neilk
214  * Don't do multi_io_* operations in single-player
215  * 
216  * 36    3/10/99 6:50p Dave
217  * Changed the way we buffer packets for all clients. Optimized turret
218  * fired packets. Did some weapon firing optimizations.
219  * 
220  * 35    3/09/99 6:24p Dave
221  * More work on object update revamping. Identified several sources of
222  * unnecessary bandwidth.
223  * 
224  * 34    3/08/99 7:03p Dave
225  * First run of new object update system. Looks very promising.
226  * 
227  * 33    3/04/99 6:09p Dave
228  * Added in sexpressions for firing beams and checking for if a ship is
229  * tagged.
230  * 
231  * 32    3/01/99 10:00a Dave
232  * Fxied several dogfight related stats bugs.
233  * 
234  * 31    2/24/99 2:25p Dave
235  * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
236  * bug for dogfight more.
237  * 
238  * 30    2/23/99 2:29p Dave
239  * First run of oldschool dogfight mode. 
240  * 
241  * 29    2/21/99 6:01p Dave
242  * Fixed standalone WSS packets. 
243  * 
244  * 28    2/21/99 1:48p Dave
245  * Some code for monitoring datarate for multiplayer in detail.
246  * 
247  * 27    2/17/99 2:11p Dave
248  * First full run of squad war. All freespace and tracker side stuff
249  * works.
250  * 
251  * 26    2/12/99 6:16p Dave
252  * Pre-mission Squad War code is 95% done.
253  * 
254  * 25    2/11/99 3:08p Dave
255  * PXO refresh button. Very preliminary squad war support.
256  * 
257  * 24    1/29/99 5:07p Dave
258  * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
259  * missiles.
260  * 
261  * 23    1/27/99 9:56a Dave
262  * Temporary checkin of beam weapons for Dan to make cool sounds.
263  * 
264  * 22    1/26/99 6:33p Anoop
265  * Fixed multiplayer slot switching problem (be sure to remember that
266  * hinfo->id is player id# _not_ player index #)
267  * 
268  * 21    1/24/99 11:37p Dave
269  * First full rev of beam weapons. Very customizable. Removed some bogus
270  * Int3()'s in low level net code.
271  * 
272  * 20    1/15/99 4:37p Dave
273  * Potential fix for weapon pair problem.
274  * 
275  * 19    1/14/99 6:06p Dave
276  * 100% full squad logo support for single player and multiplayer.
277  * 
278  * 18    1/14/99 12:48a Dave
279  * Todo list bug fixes. Made a pass at putting briefing icons back into
280  * FRED. Sort of works :(
281  * 
282  * 17    1/12/99 5:45p Dave
283  * Moved weapon pipeline in multiplayer to almost exclusively client side.
284  * Very good results. Bandwidth goes down, playability goes up for crappy
285  * connections. Fixed object update problem for ship subsystems.
286  * 
287  * 16    1/08/99 4:56p Anoop
288  * Fixed a problem with wss request packets.
289  * 
290  * 15    12/18/98 12:24p Markm
291  * Fixed a dumb bug where player image_filenames were not being passed
292  * properly in new players packet.
293  * 
294  * 14    12/14/98 12:13p Dave
295  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
296  * Need to test now.
297  * 
298  * 13    11/30/98 1:07p Dave
299  * 16 bit conversion, first run.
300  * 
301  * 12    11/20/98 4:08p Dave
302  * Fixed flak effect in multiplayer.
303  * 
304  * 11    11/19/98 4:19p Dave
305  * Put IPX sockets back in psnet. Consolidated all multiplayer config
306  * files into one.
307  * 
308  * 10    11/19/98 8:04a Dave
309  * Full support for D3-style reliable sockets. Revamped packet lag/loss
310  * system, made it receiver side and at the lowest possible level.
311  * 
312  * 9     11/17/98 11:12a Dave
313  * Removed player identification by address. Now assign explicit id #'s.
314  * 
315  * 8     11/12/98 11:50a Dave
316  * Multiplayer clients set flak range to be very long.
317  * 
318  * 7     11/12/98 12:13a Dave
319  * Tidied code up for multiplayer test. Put in network support for flak
320  * guns.
321  * 
322  * 6     11/05/98 5:55p Dave
323  * Big pass at reducing #includes
324  * 
325  * 5     10/20/98 1:39p Andsager
326  * Make so sparks follow animated ship submodels.  Modify
327  * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
328  * submodel_num.  Add submodel_num to multiplayer hit packet.
329  * 
330  * 4     10/13/98 9:29a Dave
331  * Started neatening up freespace.h. Many variables renamed and
332  * reorganized. Added AlphaColors.[h,cpp]
333  * 
334  * 3     10/07/98 6:27p Dave
335  * Globalized mission and campaign file extensions. Removed Silent Threat
336  * special code. Moved \cache \players and \multidata into the \data
337  * directory.
338  * 
339  * 2     10/07/98 10:53a Dave
340  * Initial checkin.
341  * 
342  * 1     10/07/98 10:50a Dave
343  * 
344  * 506   10/02/98 3:22p Allender
345  * fix up the -connect option and fix the -port option
346  * 
347  * 505   10/02/98 11:45a Dave
348  * Fixed stupid chat message bug.
349  * 
350  * 504   9/29/98 1:33p Dave
351  * Remove standalone only conditional compiles for pre 1.04 stuff.
352  * 
353  * 503   9/28/98 1:54p Dave
354  * Make sure French and German don't xfer builtin files they don't have
355  * (to themselves)
356  * 
357  * 502   9/20/98 7:19p Dave
358  * Added CHANGE_IFF packet. 
359  * 
360  * 501   9/17/98 3:08p Dave
361  * PXO to non-pxo game warning popup. Player icon stuff in create and join
362  * game screens. Upped server count refresh time in PXO to 35 secs (from
363  * 20).
364  * 
365  * 
366  * $NoKeywords: $
367  */
368
369 #include <limits.h>
370 #ifndef PLAT_UNIX
371 #include <io.h>         // for findfirst/findnext, etc
372 #endif
373 #include "osapi.h"
374 #include "multimsgs.h"
375 #include "multiutil.h"
376 #include "multiui.h"
377 #include "multi.h"
378 #include "multiteamselect.h"
379 #include "linklist.h"
380 #include "gamesequence.h"
381 #include "hudmessage.h"
382 #include "hudsquadmsg.h"
383 #include "freespace.h"
384 #include "timer.h"
385 #include "psnet.h"
386 #include "player.h"
387 #include "missiongoals.h"
388 #include "missionparse.h"
389 #include "missionlog.h"
390 #include "missionmessage.h"
391 #include "missionbrief.h"
392 #include "physics.h"
393 #include "cmeasure.h"
394 #include "model.h"                              // for some limits
395 #include "afterburner.h"
396 #include "stand_server.h"
397 #include "multi_xfer.h"
398 #include "gamesnd.h"
399 #include "sexp.h"
400 #include "shiphit.h"
401 #include "chatbox.h"
402 #include "3d.h"
403 #include "managepilot.h"
404 #include "hudsquadmsg.h"
405 #include "debris.h"
406 #include "missionweaponchoice.h"
407 #include "missionshipchoice.h"
408 #include "fireballs.h"
409 #include "shipfx.h"
410 #include "popup.h"
411 #include "multi_ingame.h"
412 #include "multiteamselect.h"
413 #include "aigoals.h"
414 #include "multi_campaign.h"
415 #include "multi_team.h"
416 #include "multi_respawn.h"
417 #include "multi_observer.h"
418 #include "multi_voice.h"
419 #include "asteroid.h"
420 #include "multi_pmsg.h"
421 #include "multi_data.h"
422 #include "multi_options.h"
423 #include "objcollide.h"
424 #include "hudreticle.h"
425 #include "multi_pause.h"
426 #include "multi_endgame.h"
427 #include "missiondebrief.h"
428 #include "multi_obj.h"
429 #include "multi_log.h"
430 #include "emp.h"
431 #include "multi_kick.h"
432 #include "cmdline.h"
433 #include "flak.h"
434 #include "beam.h"
435 #include "multi_rate.h"
436 #include "neblightning.h"
437 #include "hudescort.h"
438
439 // #define _MULTI_SUPER_WACKY_COMPRESSION
440
441 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
442 #define BITS                       15
443 #define MAX_CODE                   ( ( 1 << BITS ) - 1 )
444 #define TABLE_SIZE                 35023L
445 #define END_OF_STREAM              256
446 #define BUMP_CODE                  257
447 #define FLUSH_CODE                 258
448 #define FIRST_CODE                 259
449 #define UNUSED                     -1
450
451 typedef struct {
452     int code_value;
453     int parent_code;
454     char character;
455 } DICTIONARY;
456
457 static DICTIONARY dict[TABLE_SIZE];
458 static char decode_stack[TABLE_SIZE];
459 static uint next_code;
460 static int current_code_bits;
461 static uint next_bump_code;
462
463 typedef struct BitBuf {
464         ubyte   mask;
465    int  rack;
466         ubyte *data;
467 } BitBuf;
468
469 void output_bits( BitBuf *bitbuf, uint code, int count ) 
470 {
471     uint mask;
472
473     mask = 1L << ( count - 1 );
474     while ( mask != 0) {
475         if ( mask & code )
476             bitbuf->rack |= bitbuf->mask;
477         bitbuf->mask >>= 1;
478         if ( bitbuf->mask == 0 ) {
479                                 *bitbuf->data++=(ubyte)bitbuf->rack;
480                                 bitbuf->rack = 0;
481             bitbuf->mask = 0x80;
482         }
483         mask >>= 1;
484     }
485 }
486
487 uint input_bits( BitBuf *bitbuf, int bit_count ) 
488 {
489         uint mask;
490         uint return_value;
491
492         mask = 1L << ( bit_count - 1 );
493         return_value = 0;
494         while ( mask != 0)      {
495                 if ( bitbuf->mask == 0x80 ) {
496                         bitbuf->rack = *bitbuf->data++;
497                         if ( bitbuf->rack == EOF ) 
498                                 return END_OF_STREAM;
499         }
500                 if ( bitbuf->rack & bitbuf->mask )
501                         return_value |= mask;
502                 mask >>= 1;
503                 bitbuf->mask >>= 1;
504                 if ( bitbuf->mask == 0 )
505                         bitbuf->mask = 0x80;
506         }
507         return( return_value );
508 }
509
510
511 static void InitializeDictionary()
512 {
513         uint i;
514
515         for ( i = 0 ; i < TABLE_SIZE ; i++ )
516                 dict[i].code_value = UNUSED;
517
518         next_code = FIRST_CODE;
519         current_code_bits = 9;
520         next_bump_code = 511;
521
522 }
523
524 static uint find_child_node( int parent_code, int child_character ) 
525 {
526     uint index;
527     int offset;
528
529     index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
530     if ( index == 0 )
531         offset = 1;
532     else
533         offset = TABLE_SIZE - index;
534     for ( ; ; ) {
535                 if ( dict[ index ].code_value == UNUSED )
536             return( (uint) index );
537                 if ( dict[ index ].parent_code == parent_code &&
538                          dict[ index ].character == (char) child_character )
539             return( index );
540         if ( (int) index >= offset )
541             index -= offset;
542         else
543             index += TABLE_SIZE - offset;
544     }
545 }
546
547
548 static uint decode_string( uint count, uint code ) 
549 {
550     while ( code > 255 ) {
551                 decode_stack[ count++ ] = dict[ code ].character;
552                 code = dict[ code ].parent_code;
553     }
554     decode_stack[ count++ ] = (char) code;
555     return( count );
556 }
557
558 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size ) 
559 {
560         BitBuf output;
561         int character;
562         int string_code;
563         uint index;
564         int i;
565
566         // Init output bit buffer
567         output.rack = 0;
568         output.mask = 0x80;
569         output.data = outputbuf;
570
571         InitializeDictionary();
572
573         string_code = *inputbuf++;
574
575         for ( i=1 ; i<input_size ; i++ ) {
576                 character = *inputbuf++;
577                 index = find_child_node( string_code, character );
578                 if ( dict[ index ].code_value != - 1 )
579                         string_code = dict[ index ].code_value;
580       else {
581                         dict[ index ].code_value = next_code++;
582                         dict[ index ].parent_code = string_code;
583                         dict[ index ].character = (char) character;
584                         output_bits( &output, (unsigned long) string_code, current_code_bits );
585                         string_code = character;
586          if ( next_code > MAX_CODE ) {
587                                 output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
588                                 InitializeDictionary();
589                         } else if ( next_code > next_bump_code ) {
590                 output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
591                                 current_code_bits++;
592                                 next_bump_code <<= 1;
593                                 next_bump_code |= 1;
594                         }
595                 }
596         }
597         output_bits( &output, (unsigned long) string_code, current_code_bits );
598         output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
599
600         if ( output.mask != 0x80 )
601         *output.data++ = (ubyte)output.rack;
602
603         return output.data-outputbuf;
604 }
605
606
607 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf ) 
608 {
609         BitBuf input;
610         uint new_code;
611         uint old_code;
612         int character;
613         uint count;
614         uint counter;
615
616         input.rack = 0; 
617         input.mask = 0x80;
618         input.data = inputbuf;
619         
620         counter = 0;
621         for ( ; ; ) {
622                 InitializeDictionary();
623                 old_code = (uint) input_bits( &input, current_code_bits );
624                 if ( old_code == END_OF_STREAM ) 
625                         return counter;
626                 character = old_code;
627                 outputbuf[counter++] = ( ubyte )old_code;
628                 for ( ; ; ) {
629                         new_code = (uint) input_bits( &input, current_code_bits );
630                         if ( new_code == END_OF_STREAM ) 
631                                 return counter;
632                         if ( new_code == FLUSH_CODE )
633                                 break;
634                         if ( new_code == BUMP_CODE ) {
635                                 current_code_bits++;
636                                 continue;
637                         }
638                         if ( new_code >= next_code ) {
639                                 decode_stack[ 0 ] = (char) character;
640                                 count = decode_string( 1, old_code );
641                         } else {
642                                 count = decode_string( 0, new_code );
643                         }
644                         character = decode_stack[ count - 1 ];
645                         while ( count > 0 )
646                                 outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
647                         dict[ next_code ].parent_code = old_code;
648                         dict[ next_code ].character = (char) character;
649                         next_code++;
650                         old_code = new_code;
651                 }
652         }
653 }
654 #endif
655
656 // process a join request packet add
657 void add_join_request(ubyte *data, int *size, join_request *jr)
658 {
659         int packet_size = *size;
660         join_request *jr_tmp = jr;
661
662         jr_tmp->tracker_id = INTEL_INT(jr->tracker_id);
663         jr_tmp->player_options.flags = INTEL_INT(jr->player_options.flags);
664         jr_tmp->player_options.obj_update_level = INTEL_INT(jr->player_options.obj_update_level);
665
666         ADD_DATA(*jr_tmp);
667
668         *size = packet_size;
669 }
670
671 // process a join request packet get
672 void get_join_request(ubyte *data, int *size, join_request jr)
673 {
674         int offset = *size;
675
676         GET_DATA(jr);
677
678         jr.tracker_id = INTEL_INT(jr.tracker_id);
679         jr.player_options.flags = INTEL_INT(jr.player_options.flags);
680         jr.player_options.obj_update_level = INTEL_INT(jr.player_options.obj_update_level);
681
682         *size = offset;
683 }
684
685 struct net_addr_compat {
686         uint type;
687         ubyte net_id[4];
688         ubyte addr[6];
689         short port;
690 };
691
692 SDL_COMPILE_TIME_ASSERT(net_addr_compat, sizeof(net_addr_compat) == 16);
693
694 void add_net_addr(ubyte *data, int &size, const net_addr *addr)
695 {
696         int packet_size = size;
697         net_addr_compat addr_c;
698
699         SDL_zero(addr_c);
700
701         addr_c.type = INTEL_INT(addr->type);
702         addr_c.port = INTEL_SHORT(addr->port);
703         memcpy(&addr_c.addr, &addr->addr, IP_ADDRESS_LENGTH);
704
705         ADD_DATA(addr_c);
706
707         size = packet_size;
708 }
709
710 void get_net_addr(const ubyte *data, int &size, net_addr &addr)
711 {
712         int offset = size;
713         net_addr_compat addr_c;
714
715         SDL_zero(addr);
716
717         GET_DATA(addr_c);
718
719         addr.type = INTEL_INT(addr_c.type);
720         addr.port = INTEL_SHORT(addr_c.port);
721         memcpy(&addr.addr, &addr_c.addr, IP_ADDRESS_LENGTH);
722
723         size = offset;
724 }
725
726 void add_vector_data(ubyte *data, int *size, vector vec)
727 {
728         int packet_size = *size;
729
730         ADD_FLOAT(vec.xyz.x);
731         ADD_FLOAT(vec.xyz.y);
732         ADD_FLOAT(vec.xyz.z);
733
734         *size = packet_size;
735 }
736
737 void get_vector_data(ubyte *data, int *size, vector vec)
738 {
739         int offset = *size;
740
741         GET_FLOAT(vec.xyz.x);
742         GET_FLOAT(vec.xyz.y);
743         GET_FLOAT(vec.xyz.z);
744
745         *size = offset;
746 }
747
748 // send the specified data packet to all players
749 void multi_io_send(net_player *pl, ubyte *data, int len)
750 {               
751         // invalid
752         if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
753                 return;
754         }
755
756         // don't do it for single player
757         if(!(Game_mode & GM_MULTIPLAYER)){
758                 return;
759         }
760
761         // sanity checks
762         if(MULTIPLAYER_CLIENT){
763                 // SDL_assert(pl == Net_player);
764                 if(pl != Net_player){
765                         return;
766                 }
767         } else {
768                 // SDL_assert(pl != Net_player);
769                 if(pl == Net_player){
770                         return;
771                 }
772         }
773
774         // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
775         if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {              
776                 multi_io_send_force(pl);
777                 pl->s_info.unreliable_buffer_size = 0;
778         }
779
780         SDL_assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
781
782         memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
783         pl->s_info.unreliable_buffer_size += len;
784 }
785
786 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
787 {       
788         int i;
789         SDL_assert(MULTIPLAYER_MASTER);
790
791         // need to check for i > 1, hmmm... and connected. I don't know.        
792         for (i = 0; i < MAX_PLAYERS; i++ ) {
793                 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
794                         continue;
795                 }
796
797                 // maybe ignore a player
798                 if((ignore != NULL) && (&Net_players[i] == ignore)){
799                         continue;
800                 }
801
802                 // ingame joiners not waiting to select a ship doesn't get any packets
803                 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
804                         continue;
805                 }
806
807                 // send it
808                 multi_io_send(&Net_players[i], data, length);
809    }
810 }
811
812 void multi_io_send_force(net_player *pl)
813 {       
814         // invalid
815         if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
816                 return;
817         }
818         
819         // don't do it for single player
820         if(!(Game_mode & GM_MULTIPLAYER)){
821                 return;
822         }
823
824         // send everything in 
825         if (MULTIPLAYER_MASTER) {
826                 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
827
828                 // add the bytes sent to this player
829                 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
830         } else {
831                 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));          
832         }               
833         pl->s_info.unreliable_buffer_size = 0;
834 }
835
836 // send the data packet to all players via their reliable sockets
837 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
838 {       
839         // invalid
840         if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
841                 return;
842         }
843
844         // don't do it for single player
845         if(!(Game_mode & GM_MULTIPLAYER)){
846                 return;
847         }
848         
849         // sanity checks
850         if(MULTIPLAYER_CLIENT){
851                 // SDL_assert(pl == Net_player);
852                 if(pl != Net_player){
853                         return;
854                 }
855         } else {
856                 // SDL_assert(pl != Net_player);
857                 if(pl == Net_player){
858                         return;
859                 }
860         }
861
862         // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
863         if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {                
864                 multi_io_send_reliable_force(pl);
865                 pl->s_info.reliable_buffer_size = 0;
866         }
867
868         SDL_assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
869
870         memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
871         pl->s_info.reliable_buffer_size += len;
872 }
873
874 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
875 {       
876         int i;
877         SDL_assert(MULTIPLAYER_MASTER);
878
879         // need to check for i > 1, hmmm... and connected. I don't know.        
880         for (i = 0; i < MAX_PLAYERS; i++ ) {
881                 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
882                         continue;
883                 }
884
885                 // maybe ignore a player
886                 if((ignore != NULL) && (&Net_players[i] == ignore)){
887                         continue;
888                 }
889
890                 // ingame joiners not waiting to select a ship doesn't get any packets
891                 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
892                         continue;
893                 }
894
895                 // send it
896                 multi_io_send_reliable(&Net_players[i], data, length);
897    }
898 }
899
900 void multi_io_send_reliable_force(net_player *pl)
901 {       
902         // invalid
903         if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
904                 return;
905         }               
906
907         // don't do it for single player
908         if(!(Game_mode & GM_MULTIPLAYER)){
909                 return;
910         }
911
912         // send everything in 
913         if(MULTIPLAYER_MASTER) {
914                 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
915         } else if(Net_player != NULL){
916                 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
917         }               
918         pl->s_info.reliable_buffer_size = 0;
919 }
920
921 // send all buffered packets
922 void multi_io_send_buffered_packets()   
923 {
924         int idx;
925
926         // don't do it for single player
927         if(!(Game_mode & GM_MULTIPLAYER)){
928                 return;
929         }
930
931         // server
932         if(MULTIPLAYER_MASTER){
933                 for(idx=0; idx<MAX_PLAYERS; idx++){
934                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
935                                 // force unreliable data
936                                 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
937                                         multi_io_send_force(&Net_players[idx]);
938                                         Net_players[idx].s_info.unreliable_buffer_size = 0;
939                                 }
940
941                                 // force reliable data
942                                 if(Net_players[idx].s_info.reliable_buffer_size > 0){
943                                         multi_io_send_reliable_force(&Net_players[idx]);
944                                         Net_players[idx].s_info.reliable_buffer_size = 0;
945                                 }
946                         }
947                 }
948         } 
949         // clients
950         else if(Net_player != NULL){
951                 // force unreliable data
952                 if(Net_player->s_info.unreliable_buffer_size > 0){
953                         multi_io_send_force(Net_player);
954                         Net_player->s_info.unreliable_buffer_size = 0;
955                 }
956
957                 // force reliable data
958                 if(Net_player->s_info.reliable_buffer_size > 0){
959                         multi_io_send_reliable_force(Net_player);
960                         Net_player->s_info.reliable_buffer_size = 0;
961                 }
962         }
963 }
964
965 // send a general game chat packet (if msg_mode == MULTI_MSG_TARGET, need to pass in "to", if == MULTI_MSG_EXPR, need to pass in expr)
966 void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
967 {
968         ubyte data[MAX_PACKET_SIZE],mode;
969         int packet_size,idx;
970         
971         BUILD_HEADER(GAME_CHAT);
972         
973         // add the id
974         ADD_SHORT(from->player_id);
975
976         // add the message mode and if in MSG_TARGET mode, add who the target is
977         ADD_INT(server_msg);
978         mode = (ubyte)msg_mode; 
979         ADD_DATA(mode);
980         switch(mode){
981         case MULTI_MSG_TARGET:  
982                 SDL_assert(to != NULL);
983                 ADD_SHORT(to->player_id);
984                 break;
985         case MULTI_MSG_EXPR:
986                 SDL_assert(expr != NULL);
987                 ADD_STRING(expr);
988                 break;
989         }
990         // add the message itself
991         ADD_STRING( msg );
992         
993         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
994                 switch(mode){
995                 // message all players
996                 case MULTI_MSG_ALL:                     
997                         for(idx=0;idx<MAX_PLAYERS;idx++){
998                                 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){                                    
999                                         multi_io_send_reliable(&Net_players[idx], data, packet_size);
1000                                 }
1001                         }
1002                         break;
1003
1004                 // message only friendly players
1005                 case MULTI_MSG_FRIENDLY:
1006                         for(idx=0;idx<MAX_PLAYERS;idx++){
1007                                 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team == from->p_info.team)){                                     
1008                                         multi_io_send_reliable(&Net_players[idx], data, packet_size);
1009                                 }
1010                         }
1011                         break;
1012
1013                 // message only hostile players
1014                 case MULTI_MSG_HOSTILE:
1015                         for(idx=0;idx<MAX_PLAYERS;idx++){
1016                                 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team != from->p_info.team)){                                     
1017                                         multi_io_send_reliable(&Net_players[idx], data, packet_size);
1018                                 }
1019                         }
1020                         break;
1021                 
1022                 // message the player's target
1023                 case MULTI_MSG_TARGET:
1024                         SDL_assert(to != NULL);
1025                         if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){                         
1026                                 multi_io_send_reliable(to, data, packet_size);
1027                         }
1028                         break;
1029
1030                 // message all players who match the expression string
1031                 case MULTI_MSG_EXPR:
1032                         SDL_assert(expr != NULL);
1033                         for(idx=0;idx<MAX_PLAYERS;idx++){
1034                                 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){                                 
1035                                         multi_io_send_reliable(&Net_players[idx], data, packet_size);
1036                                 }
1037                         }
1038                         break;
1039                 }               
1040         }
1041         // send to the server, who will take care of routing it
1042         else {          
1043                 multi_io_send_reliable(Net_player, data, packet_size);
1044         }
1045 }
1046
1047 // process a general game chat packet, if we're the standalone we should rebroadcast
1048 void process_game_chat_packet( ubyte *data, header *hinfo )
1049 {
1050         int offset;
1051         ubyte mode;
1052         int color_index,player_index,to_player_index,should_display,server_msg; 
1053         char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
1054         char expr[255];
1055         short from, to;
1056
1057         offset = HEADER_LENGTH;
1058
1059         // get the id of the sender
1060         GET_SHORT(from);
1061         
1062         // determine if this is a server message
1063         GET_INT(server_msg);
1064
1065         // get the mode
1066         GET_DATA(mode);
1067         
1068         // if targeting a specific player, get the address
1069         to = -1;
1070         switch(mode){
1071         case MULTI_MSG_TARGET:  
1072                 GET_SHORT(to);
1073                 break;
1074         case MULTI_MSG_EXPR:
1075                 GET_STRING(expr);
1076                 break;
1077         }
1078         // get the message itself
1079         GET_STRING(msg);
1080         PACKET_SET_SIZE();      
1081
1082    // get the index of the sending player
1083         color_index = find_player_id(from);
1084         player_index = color_index;
1085         
1086         // if we couldn't find the player - bail
1087         if(player_index == -1){
1088                 nprintf(("Network","Could not find player for processing game chat packet!\n"));
1089                 return;
1090         }
1091
1092         should_display = 0;
1093
1094         // if we're the server, determine what to do with the packet here
1095         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1096                 // if he's targeting a specific player, find out who it is
1097                 if(mode == MULTI_MSG_TARGET){
1098                         to_player_index = find_player_id(to);
1099                 } else {
1100                         to_player_index = -1;
1101                 }       
1102
1103                 // if we couldn't find who sent the message or who should be getting the message, the bail
1104                 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
1105                         return;
1106                 }
1107
1108                 // determine if _I_ should be seeing the text
1109                 if(Game_mode & GM_STANDALONE_SERVER){
1110                         should_display = 1;                     
1111                 } 
1112                 // check against myself for several specific cases
1113                 else {
1114                         if((mode == MULTI_MSG_ALL) || 
1115                                 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
1116                                 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
1117                                 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
1118                                 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
1119                                 should_display = 1;                     
1120                         }
1121                 }
1122         
1123                 // if we're the server of a game, we need to rebroadcast to all other players                   
1124                 switch(mode){
1125                 // individual target mission
1126                 case MULTI_MSG_TARGET:          
1127                         // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
1128                         if(to_player_index != MY_NET_PLAYER_NUM){
1129                                 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1130                         }
1131                         break;
1132                 // expression mode
1133                 case MULTI_MSG_EXPR:
1134                         send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1135                         break;
1136                 // all other modes
1137                 default :               
1138                         send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1139                         break;
1140                 }
1141         }
1142         // if a client receives this packet, its always ok for him to display it
1143         else {
1144                 should_display = 1;
1145         }
1146
1147         // if we're not on a standalone
1148         if(should_display){
1149                 if(server_msg == 2){
1150                         HUD_printf(msg);
1151                 } else {
1152                         multi_display_chat_msg(msg, player_index, !server_msg); 
1153                 }
1154         }       
1155 }
1156
1157 // broadcast a hud message to all players
1158 void send_hud_msg_to_all( char* msg )
1159 {
1160         ubyte data[MAX_PACKET_SIZE];
1161         int packet_size;
1162
1163         // only the server should be sending this packet        
1164         BUILD_HEADER(HUD_MSG);
1165
1166         ADD_STRING(msg);
1167
1168         multi_io_send_to_all( data, packet_size );
1169 }
1170
1171 // process an incoming hud message packet
1172 void process_hud_message(ubyte* data, header* hinfo)
1173 {
1174         int offset;
1175         char msg_buffer[255];
1176         
1177         offset = HEADER_LENGTH;
1178
1179         GET_STRING(msg_buffer);
1180         PACKET_SET_SIZE();
1181         
1182         // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1183         if(Game_mode & GM_IN_MISSION){
1184                 HUD_printf(msg_buffer);
1185         }       
1186 }
1187
1188 // send a join packet request to the specified address (should be a server)
1189 void send_join_packet(net_addr* addr,join_request *jr)
1190 {
1191         ubyte data[MAX_PACKET_SIZE];    
1192         int packet_size;
1193         
1194         // build the header and add the request
1195         BUILD_HEADER(JOIN);     
1196 //      ADD_DATA(*jr);
1197         add_join_request(data, &packet_size, jr);
1198         
1199         psnet_send(addr, data, packet_size);    
1200 }
1201
1202 // process an incoming join request packet
1203 void process_join_packet(ubyte* data, header* hinfo)
1204 {
1205         join_request jr;
1206         int offset;
1207         int ret_code;
1208         int host_restr_mode;
1209         // int team0_avail,team1_avail;
1210         char join_string[255];
1211         net_addr addr;  
1212
1213         // only the server of the game should ever receive this packet
1214         if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1215                 return;
1216
1217         offset = HEADER_LENGTH; 
1218         
1219         // read in the request info
1220         memset(&jr,0,sizeof(join_request));     
1221
1222         GET_DATA(jr);
1223         jr.tracker_id = INTEL_INT(jr.tracker_id);
1224         
1225         PACKET_SET_SIZE();      
1226
1227         // fill in the address information of where this came from
1228         fill_net_addr(&addr, hinfo->addr, hinfo->port);
1229
1230         // determine if we should accept this guy, or return a reason we should reject him
1231         // see the DENY_* codes in multi.h
1232         ret_code = multi_eval_join_request(&jr,&addr);
1233
1234         // evaluate the return code
1235         switch(ret_code){
1236         // he should be accepted
1237         case -1 :
1238                 break;
1239                 
1240         // we have to query the host because this is a restricted game
1241         case JOIN_QUERY_RESTRICTED :            
1242                 if(!(Game_mode & GM_STANDALONE_SERVER)){                        
1243                         // notify the host of the event
1244                         snd_play(&Snds[SND_CUE_VOICE]);
1245                 }
1246
1247                 // set the query timestamp
1248                 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1249                 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1250
1251                 // determine what mode we're in
1252 //              host_restr_mode = -1;
1253                 memset(join_string,0,255);
1254 //              if(Netgame.type == NG_TYPE_TEAM){
1255 //                      multi_player_ships_available(&team0_avail,&team1_avail);
1256 //
1257 //                      if(team0_avail && team1_avail){
1258 //                              host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1259 //                              sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1260 //                      } else if(team0_avail && !team1_avail){
1261 //                              host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1262 //                              sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1263 //                      } else if(!team0_avail && team1_avail){
1264 //                              host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1265 //                              sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1266 //                      }
1267 //              } else if(Netgame.mode == NG_MODE_RESTRICTED){
1268                         host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1269                         SDL_snprintf(join_string,SDL_arraysize(join_string),XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1270 //              }
1271                 SDL_assert(host_restr_mode != -1);
1272
1273                 // store the request info
1274                 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1275                 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1276                 Multi_join_restr_mode = host_restr_mode;
1277
1278                 // if i'm the standalone server, I need to send a query to the host
1279                 if(Game_mode & GM_STANDALONE_SERVER){
1280                         send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1281                 } else {
1282                         HUD_printf(join_string);
1283                 }
1284
1285                 // NETLOG
1286                 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1287
1288                 return;
1289         
1290         // he'e being denied for some reason
1291         default :       
1292                 // send him the reason he is being denied
1293                 send_deny_packet(&addr,ret_code);
1294                 return;
1295         } 
1296
1297         // process the rest of the request
1298         multi_process_valid_join_request(&jr,&addr);
1299 }
1300
1301 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1302 void send_new_player_packet(int new_player_num,net_player *target)
1303 {
1304         ubyte data[MAX_PACKET_SIZE], val;
1305         int packet_size = 0;    
1306         
1307         BUILD_HEADER( NOTIFY_NEW_PLAYER );
1308
1309         // add the new player's info
1310         ADD_INT(new_player_num);
1311 //      ADD_DATA(Net_players[new_player_num].p_info.addr);
1312
1313         add_net_addr(data, packet_size, &Net_players[new_player_num].p_info.addr);
1314
1315         ADD_SHORT(Net_players[new_player_num].player_id);
1316         ADD_INT(Net_players[new_player_num].flags);
1317         ADD_STRING(Net_players[new_player_num].player->callsign);
1318         ADD_STRING(Net_players[new_player_num].player->image_filename);
1319         ADD_STRING(Net_players[new_player_num].player->squad_filename);
1320         ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1321
1322         val = (ubyte)Net_players[new_player_num].p_info.team;
1323         ADD_DATA(val);
1324
1325         // broadcast the data
1326         if(target != NULL){
1327                 multi_io_send_reliable(target, data, packet_size);
1328         } else {
1329                 multi_io_send_to_all_reliable(data, packet_size);       
1330         }
1331 }
1332
1333 // process a notification for a new player who has joined the game
1334 void process_new_player_packet(ubyte* data, header* hinfo)
1335 {
1336         int already_in_game = 0;
1337         int offset, new_player_num,player_num,new_flags;
1338         net_addr new_addr;      
1339         char new_player_name[CALLSIGN_LEN+2] = "";
1340         char new_player_image[MAX_FILENAME_LEN+1] = "";
1341         char new_player_squad[MAX_FILENAME_LEN+1] = "";
1342         char new_player_pxo_squad[LOGIN_LEN+1] = "";
1343         char notify_string[256];
1344         ubyte team;
1345         short new_id;
1346
1347         offset = HEADER_LENGTH;
1348
1349         // get the new players information
1350         GET_INT(new_player_num);
1351         memset(&new_addr, 0, sizeof(net_addr));
1352         get_net_addr(data, offset, new_addr);
1353
1354         GET_SHORT(new_id);
1355         GET_INT(new_flags);
1356         GET_STRING(new_player_name);    
1357         GET_STRING(new_player_image);
1358         GET_STRING(new_player_squad);
1359         GET_STRING(new_player_pxo_squad);
1360         GET_DATA(team);
1361         PACKET_SET_SIZE();
1362
1363         player_num = multi_find_open_player_slot();
1364         SDL_assert(player_num != -1);
1365         
1366         // note that this new code does not check for duplicate IPs. It merely checks to see if
1367         // the slot referenced by new_player_num is already occupied by a connected player
1368         if(MULTI_CONNECTED(Net_players[new_player_num])){
1369                 already_in_game=1;
1370         }
1371
1372         // if he's not alreayd in the game for one reason or another
1373         if ( !already_in_game ) {
1374                 if ( Game_mode & GM_IN_MISSION ){
1375                         HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1376                 }
1377
1378                 // create the player
1379                 if(new_flags & NETINFO_FLAG_OBSERVER){
1380                         multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1381                         Net_players[new_player_num].flags |= new_flags;
1382                 } else {
1383                         multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1384                         Net_players[new_player_num].flags |= new_flags;
1385                 }
1386
1387                 // copy in the filename
1388                 if(strlen(new_player_image) > 0){
1389                         SDL_strlcpy(Net_players[new_player_num].player->image_filename, new_player_image, MAX_FILENAME_LEN);
1390                 } else {
1391                         SDL_strlcpy(Net_players[new_player_num].player->image_filename, "", MAX_FILENAME_LEN);
1392                 }
1393                 // copy his pilot squad filename
1394                 Net_players[new_player_num].player->insignia_texture = -1;
1395                 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);                          
1396
1397                 // copy in his pxo squad name
1398                 SDL_strlcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad, LOGIN_LEN);
1399
1400                 // since we just created the player, set the last_heard_time here.
1401                 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1402
1403                 Net_players[new_player_num].p_info.team = team;
1404
1405                 Net_players[new_player_num].player_id = new_id;
1406
1407                 // zero out this players ping
1408                 multi_ping_reset(&Net_players[new_player_num].s_info.ping);             
1409
1410                 // add a chat message
1411                 if(Net_players[new_player_num].player->callsign[0]){
1412                         SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1413                         multi_display_chat_msg(notify_string,0,0);
1414                 }
1415         }               
1416
1417         // NETLOG
1418         ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1419         
1420         // let the current ui screen know someone joined
1421         switch(gameseq_get_state()){
1422         case GS_STATE_MULTI_HOST_SETUP :
1423                 multi_create_handle_join(&Net_players[new_player_num]);
1424                 break;
1425         case GS_STATE_MULTI_CLIENT_SETUP :
1426                 multi_jw_handle_join(&Net_players[new_player_num]);
1427                 break;
1428         }
1429 }
1430
1431 #define PLAYER_DATA_SLOP        100
1432
1433 void send_accept_player_data( net_player *npp, int is_ingame )
1434 {
1435         int packet_size;        
1436         int i;
1437         ubyte data[MAX_PACKET_SIZE], stop;
1438
1439         BUILD_HEADER(ACCEPT_PLAYER_DATA);
1440
1441         // add in the netplayer data for all players    
1442         stop = APD_NEXT;
1443         for (i=0; i<MAX_PLAYERS; i++) {
1444                 // skip non connected players
1445                 if ( !MULTI_CONNECTED(Net_players[i]) ){
1446                         continue;
1447                 }
1448                 
1449                 // skip this new player's entry
1450                 if ( npp->player_id == Net_players[i].player_id ){
1451                         continue;
1452                 }
1453                 
1454                 // add the stop byte
1455                 ADD_DATA(stop);
1456
1457                 // add the player's number
1458                 ADD_INT(i);             
1459
1460                 // add the player's address
1461         //      ADD_DATA(Net_players[i].p_info.addr);
1462                 add_net_addr(data, packet_size, &Net_players[i].p_info.addr);
1463
1464                 // add his id#
1465                 ADD_SHORT(Net_players[i].player_id);
1466
1467                 // add his callsign
1468                 ADD_STRING(Net_players[i].player->callsign);
1469
1470                 // add his image filename
1471                 ADD_STRING(Net_players[i].player->image_filename);
1472
1473                 // add his squad filename
1474                 ADD_STRING(Net_players[i].player->squad_filename);
1475
1476                 // add his PXO squad name
1477                 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1478                 
1479                 // add his flags
1480                 ADD_INT(Net_players[i].flags);          
1481
1482                 // add his object's net sig
1483                 if ( is_ingame ) {
1484                         ADD_USHORT( Objects[Net_players[i].player->objnum].net_signature );
1485                 }
1486
1487                 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1488                         stop = APD_END_PACKET;
1489                         ADD_DATA(stop);                 
1490                         multi_io_send_reliable( npp, data, packet_size );
1491                         BUILD_HEADER(ACCEPT_PLAYER_DATA);
1492                         stop = APD_NEXT;
1493                 }
1494
1495         }
1496
1497         // add the stop byte
1498         stop = APD_END_DATA;
1499         ADD_DATA(stop); 
1500         multi_io_send_reliable(npp, data, packet_size);
1501 }
1502
1503 // send an accept packet to a client in response to a request to join the game
1504 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1505 {
1506         int packet_size = 0, i;
1507         ubyte data[MAX_PACKET_SIZE],val;
1508         char notify_string[256];
1509
1510         // sanity
1511         SDL_assert(new_player_num >= 0);
1512
1513         // setup his "reliable" socket
1514         Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1515
1516         // build the packet header
1517         BUILD_HEADER(ACCEPT);   
1518         
1519         // add the accept code
1520         ADD_INT(code);
1521         
1522         // add code specific accept data
1523         if (code & ACCEPT_INGAME) {
1524                 // the game filename
1525                 ADD_STRING(Game_current_mission_filename);
1526
1527                 // if he is joining on a specific team, mark it here
1528                 if(ingame_join_team != -1){
1529                         val = 1;
1530                         ADD_DATA(val);
1531                         val = (ubyte)ingame_join_team;
1532                         ADD_DATA(val);
1533                 } else {
1534                         val = 0;
1535                         ADD_DATA(val);
1536                 }
1537         } 
1538
1539         if (code & ACCEPT_OBSERVER) {
1540                 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1541         }
1542
1543         if (code & ACCEPT_HOST) {
1544                 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1545         }
1546
1547         if (code & ACCEPT_CLIENT) {
1548                 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1549         }
1550
1551         // add the current skill level setting on the host
1552         ADD_INT(Game_skill_level);
1553
1554         // add this guys player num 
1555         ADD_INT(new_player_num);
1556
1557         // add his player id
1558         ADD_SHORT(Net_players[new_player_num].player_id);
1559
1560         // add netgame type flags
1561         ADD_INT(Netgame.type_flags);
1562         
1563 //#ifndef NDEBUG
1564         // char buffer[100];
1565         // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1566 //#endif
1567
1568         // actually send the packet     
1569         psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1570
1571    // if he's not an observer, inform all the other players in the game about him       
1572         // inform the other players in the game about this new player
1573         for (i=0; i<MAX_PLAYERS; i++) {
1574                 // skip unconnected players as well as this new guy himself
1575                 if ( !MULTI_CONNECTED(Net_players[i]) || psnet_same(&Net_players[new_player_num].p_info.addr, &(Net_players[i].p_info.addr)) || (Net_player == &Net_players[i])) {
1576                         continue;
1577                 }
1578
1579                 // send the new packet
1580                 send_new_player_packet(new_player_num,&Net_players[i]);
1581         }
1582
1583         // add a chat message
1584         if(Net_players[new_player_num].player->callsign[0]){
1585                 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1586                 multi_display_chat_msg(notify_string, 0, 0);
1587         }       
1588
1589         // handle any team vs. team details
1590         if (!(code & ACCEPT_OBSERVER)) {                
1591                 multi_team_handle_join(&Net_players[new_player_num]);           
1592         }               
1593
1594         // NETLOG
1595         if(Net_players[new_player_num].tracker_player_id >= 0){
1596                 ml_printf(NOX("Server accepted %s (tracker id %d) as new client"), Net_players[new_player_num].player->callsign, Net_players[new_player_num].tracker_player_id);
1597         } else {
1598                 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1599         }
1600 }
1601
1602
1603 // process the player data from the server
1604 void process_accept_player_data( ubyte *data, header *hinfo )
1605 {
1606         int offset, player_num, player_slot_num, new_flags;
1607         char name[CALLSIGN_LEN + 1] = "";
1608         char image_name[MAX_FILENAME_LEN + 1] = "";
1609         char squad_name[MAX_FILENAME_LEN + 1] = "";
1610         char pxo_squad_name[LOGIN_LEN+1] = "";
1611         short player_id;
1612         net_addr addr;
1613         ubyte stop;
1614         ushort ig_signature;
1615
1616         offset = HEADER_LENGTH;
1617
1618         GET_DATA(stop);
1619         while ( stop == APD_NEXT ) {
1620                 player_slot_num = multi_find_open_player_slot();
1621                 SDL_assert(player_slot_num != -1);
1622
1623                 // get the player's number
1624                 GET_INT(player_num);
1625
1626                 // add the player's address
1627                 memset(&addr, 0, sizeof(net_addr));
1628                 get_net_addr(data, offset, addr);
1629
1630                 // get the player's id#
1631                 GET_SHORT(player_id);
1632
1633                 // get his callsign
1634                 GET_STRING(name);
1635
1636                 // add his image filename
1637                 GET_STRING(image_name);
1638
1639                 // get his squad logo filename
1640                 GET_STRING(squad_name);
1641
1642                 // get his PXO squad name
1643                 GET_STRING(pxo_squad_name);
1644                 
1645                 // get his flags
1646                 GET_INT(new_flags);
1647                 
1648                 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1649                         if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1650                                 Int3();
1651                         }
1652
1653                 } else {
1654                         //  the error handling here is less than stellar.  We should probably put up a popup and go
1655                         // back to the main menu.  But then again, this should never ever happen!
1656                         if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1657                                 Int3();
1658                         }
1659                 }
1660
1661                 // copy his image filename
1662                 SDL_strlcpy(Net_players[player_num].player->image_filename, image_name, MAX_FILENAME_LEN);
1663                 
1664                 // copy his pilot squad filename
1665                 Net_players[player_num].player->insignia_texture = -1;
1666                 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1667
1668                 // copy his pxo squad name
1669                 SDL_strlcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name, LOGIN_LEN);
1670
1671                 // set his player id#
1672                 Net_players[player_num].player_id = player_id;
1673
1674                 // mark him as being connected
1675                 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1676                 Net_players[player_num].flags |= new_flags;
1677
1678                 // set the server pointer
1679                 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1680                         Netgame.server = &Net_players[player_num];
1681                         Netgame.server->last_heard_time = timer_get_fixed_seconds();
1682
1683                         // also - always set the server address to be where this data came from, NOT from 
1684                         // the data in the packet               
1685                         fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->port);
1686                 }
1687
1688                 // set the host pointer
1689                 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1690                         Netgame.host = &Net_players[player_num];
1691                 }
1692
1693                 // read in the player's object net signature and store as his objnum for now
1694                 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1695                         GET_USHORT( ig_signature );
1696                         Net_players[player_num].player->objnum = ig_signature;
1697                 }
1698
1699                 // get the stop byte
1700                 GET_DATA(stop);
1701         }
1702         PACKET_SET_SIZE();
1703
1704         if ( stop == APD_END_DATA ) {
1705                 // if joining a game automatically, set the connect address to NULl so we don't try and
1706                 // do this next time we enter a game
1707                 if (Cmdline_connect_addr != NULL) {
1708                         Cmdline_connect_addr = NULL;
1709                 }
1710
1711                 // send my stats to the server if I'm not in observer mode
1712                 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1713                         send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1714                 }
1715
1716                 // if i'm being accepted as a host, then move into the host setup state
1717                 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1718                         // set my permission bits
1719                         Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1720                         Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1721
1722                         gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1723                 }
1724
1725                 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1726                         Net_player->flags |= NETINFO_FLAG_OBSERVER;
1727
1728                         // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1729                         if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1730                                 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1731                         }
1732                 }
1733
1734                 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1735                         gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);        
1736                 }
1737
1738                 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1739                         // flag myself as being an ingame joiner
1740                         Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;          
1741
1742                         // move myself into the ingame join mission sync state
1743                         Multi_sync_mode = MULTI_SYNC_INGAME;
1744                         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);                                
1745                 }
1746
1747                 // update my options on the server
1748                 multi_options_update_local();
1749
1750                 // if we're in PXO mode, mark it down in our player struct
1751                 if(MULTI_IS_TRACKER_GAME){
1752                         Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1753                         Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1754                 }
1755         }
1756 }
1757
1758 // process an accept packet from the server
1759 extern int Select_default_ship;
1760
1761 void process_accept_packet(ubyte* data, header* hinfo)
1762 {
1763         int code, my_player_num, offset;
1764         ubyte val,team = 0;
1765         short player_id;
1766         
1767         // get the accept code
1768         offset = HEADER_LENGTH; 
1769
1770         GET_INT(code);
1771
1772         // read in the accept code specific data
1773         val = 0;
1774         if (code & ACCEPT_INGAME) {
1775                 // the game filename
1776                 GET_STRING(Game_current_mission_filename);
1777                 Select_default_ship = 0;
1778
1779                 // determine if I'm being placed on a team
1780                 GET_DATA(val);
1781                 if(val){
1782                         GET_DATA(team);
1783                 }
1784         }
1785
1786         if (code & ACCEPT_OBSERVER) {
1787                 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1788         }
1789
1790         if (code & ACCEPT_HOST) {
1791                 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1792         }
1793
1794         if (code & ACCEPT_CLIENT) {
1795                 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1796         }
1797
1798         // fill in the netgame server address
1799         fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->port );
1800
1801         // get the skill level setting
1802         GET_INT(Game_skill_level);
1803
1804         // get my netplayer number
1805         GET_INT(my_player_num);
1806
1807         // get my id #
1808         GET_SHORT(player_id);
1809
1810         // get netgame type flags
1811         GET_INT(Netgame.type_flags);
1812
1813         // setup the Net_players structure for myself first
1814         Net_player = &Net_players[my_player_num];
1815         Net_player->flags = 0;
1816         Net_player->tracker_player_id = Multi_tracker_id;
1817         Net_player->player_id = player_id;
1818         Net_player->s_info.xfer_handle = -1;
1819         // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player ); 
1820         stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );  
1821         multi_options_local_load(&Net_player->p_info.options, Net_player);
1822         if(val){
1823                 Net_player->p_info.team = team;
1824         }       
1825
1826         // determine if I have a CD
1827         if(Multi_has_cd){
1828                 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1829         }       
1830
1831         // set accept code in netplayer for this guy
1832         if ( code & ACCEPT_INGAME ){
1833                 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1834         }
1835         if ( code & ACCEPT_OBSERVER ){
1836                 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1837         }
1838         if ( code & ACCEPT_HOST ){
1839                 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1840         }
1841         if ( code & ACCEPT_CLIENT ){
1842                 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1843         }
1844
1845         // if I have hacked data
1846         if(game_hacked_data()){
1847                 Net_player->flags |= NETINFO_FLAG_HAXOR;
1848         }
1849
1850         // if we're supposed to flush our local data cache, do so now
1851         if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1852                 multi_flush_multidata_cache();
1853         }
1854
1855         Net_player->sv_bytes_sent = 0;
1856         Net_player->sv_last_pl = -1;
1857         Net_player->cl_bytes_recvd = 0;
1858         Net_player->cl_last_pl = -1;
1859
1860         // intiialize endgame stuff
1861         multi_endgame_init();
1862
1863         PACKET_SET_SIZE();
1864
1865         // make a call to psnet to initialize and try to connect with the server.
1866         psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1867         if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1868                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1869         }
1870 }
1871
1872 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1873 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1874 {
1875         ubyte data[MAX_PACKET_SIZE];
1876         char val;
1877         int packet_size = 0;
1878
1879         BUILD_HEADER(LEAVE_GAME);
1880
1881         // add a flag indicating whether he was kicked or not
1882         val = (char)kicked_reason;
1883         ADD_DATA(val);
1884
1885         if (player_id < 0) {
1886                 ADD_SHORT(Net_player->player_id);
1887
1888                 // inform the host that we are leaving the game
1889                 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {                       
1890                         multi_io_send_to_all_reliable(data, packet_size);
1891                 } else {
1892                         multi_io_send_reliable(Net_player, data, packet_size);
1893                 }
1894         }
1895         // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1896         // so he has to tell everyone that this guy left
1897         else {
1898                 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1899
1900                 // a couple of important checks
1901                 SDL_assert(player_id != Net_player->player_id);
1902                 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1903
1904                 // add the id of the guy to be kicked
1905                 ADD_SHORT(player_id);
1906
1907                 // broadcast to everyone
1908                 if (target == NULL) {                   
1909                         multi_io_send_to_all_reliable(data, packet_size);
1910                 } else {
1911                         multi_io_send_reliable(target, data, packet_size);
1912                 }
1913         }
1914 }
1915
1916 // process a notification the a player has left the game
1917 void process_leave_game_packet(ubyte* data, header* hinfo)
1918 {
1919         int offset;
1920         short deader_id;
1921         int player_num;
1922         char kicked_reason;     
1923         char str[512];
1924
1925         offset = HEADER_LENGTH;
1926
1927         // get whether he was kicked
1928         GET_DATA(kicked_reason);
1929
1930         // get the address of the guy who is to leave
1931         GET_SHORT(deader_id);
1932         PACKET_SET_SIZE();
1933
1934         // determine who is dropping and printf out a notification
1935         player_num = find_player_id(deader_id);
1936         if (player_num == -1) {
1937                 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1938                 return;
1939
1940         } else {
1941                 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1942         }
1943
1944         // a hook to display that a player was kicked
1945         if (kicked_reason >= 0){
1946                 // if it was me that was kicked, leave the game
1947                 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1948                         int notify_code;
1949
1950                         switch(kicked_reason){
1951                         case KICK_REASON_BAD_XFER:
1952                                 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1953                                 break;
1954                         case KICK_REASON_CANT_XFER:
1955                                 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1956                                 break;
1957                         case KICK_REASON_INGAME_ENDED:
1958                                 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1959                                 break;
1960                         default:
1961                                 notify_code = MULTI_END_NOTIFY_KICKED;
1962                                 break;
1963                         }
1964
1965                         multi_quit_game(PROMPT_NONE, notify_code);
1966                         return;
1967
1968                 // otherwise indicate someone was kicked
1969                 } else {
1970                         nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));                        
1971
1972                         // display the result
1973                         memset(str, 0, 512);
1974                         multi_kick_get_text(&Net_players[player_num], kicked_reason, str, SDL_arraysize(str));
1975                         multi_display_chat_msg(str, player_num, 0);
1976                 }
1977         }
1978
1979         // first of all, if we're the master, we should be rebroadcasting this packet
1980         if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1981                 char msg[255];
1982
1983                 SDL_snprintf(msg, SDL_arraysize(msg), XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1984
1985                 if (!(Game_mode & GM_STANDALONE_SERVER)){
1986                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1987                 }
1988
1989                 send_hud_msg_to_all(msg);               
1990                 multi_io_send_to_all_reliable(data, offset);
1991         }
1992
1993         // leave the game if the host and/or master has dropped
1994         /*
1995         if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {          
1996                 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1997
1998                 // NETLOG
1999                 ml_string(NOX("Host and/or server has left the game"));
2000
2001                 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
2002                 if (gameseq_get_state() != GS_STATE_DEBRIEF) {                  
2003                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
2004                 }               
2005
2006                 delete_player(player_num);
2007         } else {
2008                 */
2009         delete_player(player_num);      
2010
2011         // OSAPI GUI stuff (if standalone)
2012         if (Game_mode & GM_STANDALONE_SERVER) {
2013       // returns true if we should reset the standalone
2014                 if (std_remove_player(&Net_players[player_num])) {
2015                         nprintf(("Network", "Should reset!!\n"));
2016                         return;
2017                 }
2018
2019                 // update these gui vals
2020                 std_connect_set_host_connect_status();
2021                 std_connect_set_connect_count();
2022         }
2023 }
2024
2025 // send information about this currently active game to the specified address
2026 void send_game_active_packet(net_addr* addr)
2027 {
2028         int packet_size;
2029         ushort flags;
2030         ubyte data[MAX_PACKET_SIZE],val;
2031
2032         // build the header and add the data
2033         BUILD_HEADER(GAME_ACTIVE);
2034         
2035         // add the server version and compatible version #
2036         val = MULTI_FS_SERVER_VERSION;
2037         ADD_DATA(val);
2038         val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2039         ADD_DATA(val);
2040
2041         ADD_STRING(Netgame.name);
2042         ADD_STRING(Netgame.mission_name);
2043         ADD_STRING(Netgame.title);      
2044         val = (ubyte)multi_num_players();
2045         ADD_DATA(val);
2046         
2047         // add the proper flags
2048         flags = 0;
2049         if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2050                 flags |= AG_FLAG_PASSWD;
2051         }
2052
2053         // proper netgame type flags
2054         if(Netgame.type_flags & NG_TYPE_TEAM){
2055                 flags |= AG_FLAG_TEAMS;
2056         } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2057                 flags |= AG_FLAG_DOGFIGHT;
2058         } else {
2059                 flags |= AG_FLAG_COOP;
2060         }       
2061
2062         // proper netgame state flags
2063         switch(Netgame.game_state){
2064         case NETGAME_STATE_FORMING:
2065                 flags |= AG_FLAG_FORMING;
2066                 break;
2067         
2068         case NETGAME_STATE_BRIEFING:
2069         case NETGAME_STATE_MISSION_SYNC:
2070         case NETGAME_STATE_HOST_SETUP:
2071                 flags |= AG_FLAG_BRIEFING;
2072                 break;
2073         
2074         case NETGAME_STATE_IN_MISSION:
2075                 flags |= AG_FLAG_IN_MISSION;
2076                 break;
2077         
2078         case NETGAME_STATE_PAUSED:
2079                 flags |= AG_FLAG_PAUSE;
2080                 break;
2081         
2082         case NETGAME_STATE_ENDGAME:
2083         case NETGAME_STATE_DEBRIEF:
2084                 flags |= AG_FLAG_DEBRIEF;
2085                 break;
2086         }
2087
2088         // if this is a standalone
2089         if(Game_mode & GM_STANDALONE_SERVER){
2090                 flags |= AG_FLAG_STANDALONE;
2091         }
2092
2093         // if we're in campaign mode
2094         if(Netgame.campaign_mode == MP_CAMPAIGN){
2095                 flags |= AG_FLAG_CAMPAIGN;
2096         }
2097
2098         // add the data about the connection speed of the host machine
2099         SDL_assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2100         flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2101
2102         ADD_USHORT(flags);
2103         
2104         // send the data        
2105         psnet_send(addr, data, packet_size);
2106 }
2107
2108 // process information about an active game
2109 void process_game_active_packet(ubyte* data, header* hinfo)
2110 {
2111         int offset;     
2112         ubyte val;
2113         active_game ag;
2114         int modes_compatible;
2115         
2116         fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->port);
2117
2118         // read this game into a temporary structure
2119         offset = HEADER_LENGTH;
2120
2121         // get the server version and compatible version
2122         GET_DATA(ag.version);
2123         GET_DATA(ag.comp_version);
2124
2125         GET_STRING(ag.name);
2126         GET_STRING(ag.mission_name);
2127         GET_STRING(ag.title);   
2128         GET_DATA(val);
2129         ag.num_players = val;
2130         GET_USHORT(ag.flags);
2131
2132         PACKET_SET_SIZE();      
2133
2134         modes_compatible = 1;
2135         /*
2136         if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2137                 modes_compatible = 0;
2138         }
2139         if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2140                 modes_compatible = 0;
2141         }
2142         */
2143
2144         // if this is a compatible version, and our modes are compatible, register it
2145         if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2146                 multi_update_active_games(&ag);
2147         }
2148 }
2149
2150 // send_game_update_packet sends an updated Netgame structure to all players currently connected.  The update
2151 // is used to change the current mission, current state, etc.
2152 void send_netgame_update_packet(net_player *pl)
2153 {
2154         int packet_size = 0;
2155         int idx;
2156         ubyte data[MAX_PACKET_SIZE];
2157
2158         BUILD_HEADER(GAME_UPDATE);
2159         
2160         // with new mission description field, this becomes way to large
2161         // so we must add every element piece by piece except the       
2162         ADD_STRING(Netgame.name);
2163         ADD_STRING(Netgame.mission_name);       
2164         ADD_STRING(Netgame.title);
2165         ADD_STRING(Netgame.campaign_name);
2166         ADD_INT(Netgame.campaign_mode); 
2167         ADD_INT(Netgame.max_players);                   
2168         ADD_INT(Netgame.security);
2169         ADD_UINT(Netgame.respawn);
2170         ADD_INT(Netgame.flags);
2171         ADD_INT(Netgame.type_flags);
2172         ADD_INT(Netgame.version_info);
2173         ADD_DATA(Netgame.debug_flags);
2174
2175         // only the server should ever send the netgame state (standalone situation)
2176         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2177                 ADD_INT(Netgame.game_state);
2178         }
2179         
2180         // if we're the host on a standalone, send to the standalone and let him rebroadcast
2181         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2182                 if ( pl == NULL ) {                     
2183                         multi_io_send_to_all_reliable(data, packet_size);
2184
2185                         for(idx=0; idx<MAX_PLAYERS; idx++){
2186                                 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2187                                         send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2188                                 }
2189                         }
2190                 } else {                        
2191                         multi_io_send_reliable(pl, data, packet_size);
2192                         send_netgame_descript_packet( &pl->p_info.addr , 1 );
2193                 }
2194         } else {
2195                 SDL_assert( pl == NULL );                       // I don't think that a host in a standalone game would get here.
2196                 multi_io_send_reliable(Net_player, data, packet_size);
2197         }               
2198
2199         // host should always send a netgame options update as well
2200         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2201                 multi_options_update_netgame();
2202         }
2203 }
2204
2205 // process information about the netgame sent from the server/host
2206 void process_netgame_update_packet( ubyte *data, header *hinfo )
2207 {
2208         int offset;//,old_flags;
2209         int ng_state;
2210                 
2211         SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
2212         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2213
2214         // read in the netgame information
2215         offset = HEADER_LENGTH; 
2216         GET_STRING(Netgame.name);
2217         GET_STRING(Netgame.mission_name);       
2218         GET_STRING(Netgame.title);      
2219         GET_STRING(Netgame.campaign_name);
2220         GET_INT(Netgame.campaign_mode); 
2221         GET_INT(Netgame.max_players);                                   // ignore on the standalone, who keeps track of this himself                    
2222         GET_INT(Netgame.security);
2223         GET_UINT(Netgame.respawn);              
2224         
2225         // be sure not to blast the quitting flag because of the "one frame extra" problem
2226 //      old_flags = Netgame.flags;
2227         GET_INT(Netgame.flags); 
2228         GET_INT(Netgame.type_flags);
2229         GET_INT(Netgame.version_info);
2230         GET_DATA(Netgame.debug_flags);
2231
2232         // netgame state        
2233         GET_INT(ng_state);
2234         
2235         PACKET_SET_SIZE();
2236                                                         
2237         // now compare the passed in game state to our current known state.  If it has changed, then maybe
2238         // do something interesting.    
2239         // move from the forming or debriefing state to the mission sync state
2240   if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2241           // if coming from the forming state
2242                 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2243                          ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2244                         // do any special processing for forced state transitions
2245                         multi_handle_state_special();
2246                                                 
2247                         Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2248                         SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2249                         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2250                 } 
2251                 // if coming from the debriefing state
2252                 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2253                          ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){ 
2254
2255                         // do any special processing for forced state transitions
2256                         multi_handle_state_special();
2257
2258                         multi_flush_mission_stuff();
2259                                                 
2260                         Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2261                         SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2262                         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2263                 }
2264         } 
2265         // move from mission sync to team select
2266         else if ( ng_state == NETGAME_STATE_BRIEFING ){
2267                 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2268                          ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2269                         
2270                         // do any special processing for forced state transitions
2271                         multi_handle_state_special();
2272
2273                         SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2274                         gameseq_post_event(GS_EVENT_START_BRIEFING);                    
2275                 }
2276         }               
2277         // move from the debriefing to the create game screen
2278         else if ( ng_state == NETGAME_STATE_FORMING ){
2279                 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2280                          ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){ 
2281                         // do any special processing for forced state transitions
2282                         multi_handle_state_special();
2283
2284                         multi_flush_mission_stuff();
2285                         
2286                         // move to the proper screen
2287                         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2288                                 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2289                         } else {
2290                                 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2291                         }
2292                 }
2293         }               
2294
2295         Netgame.game_state = ng_state;  
2296 }
2297
2298 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2299 void send_netgame_descript_packet(net_addr *addr, int code)
2300 {
2301         ubyte data[MAX_PACKET_SIZE],val;
2302         int length;
2303         int packet_size = 0;
2304
2305         // build the header
2306         BUILD_HEADER(UPDATE_DESCRIPT);
2307
2308         val = (ubyte)code;
2309         ADD_DATA(val);  
2310
2311         if(code == 1){
2312                 // add as much of the description as we dare
2313                 length = strlen(The_mission.mission_desc);
2314                 if(length > MAX_PACKET_SIZE - 10){
2315                         length = MAX_PACKET_SIZE - 10;
2316                         ADD_INT(length);
2317                         memcpy(data+packet_size,The_mission.mission_desc,length);
2318                         packet_size += length;
2319                 } else {
2320                         ADD_STRING(The_mission.mission_desc);
2321                 }
2322         } 
2323         
2324         SDL_assert(addr != NULL);
2325         if(addr != NULL){
2326                 psnet_send(addr, data, packet_size);
2327         }
2328 }
2329
2330 // process an incoming netgame description packet
2331 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2332 {
2333         int offset,state;
2334         ubyte code;     
2335         char mission_desc[MISSION_DESC_LENGTH+2];
2336         net_addr addr;
2337
2338         fill_net_addr(&addr, hinfo->addr, hinfo->port);
2339
2340         // read this game into a temporary structure
2341         offset = HEADER_LENGTH;
2342         GET_DATA(code); 
2343         
2344         // if this is a request for mission description
2345         if(code == 0){
2346                 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2347                         PACKET_SET_SIZE();
2348                         return;
2349                 }               
2350
2351                 // send an update to this guy
2352                 send_netgame_descript_packet(&addr, 1);
2353         } else {        
2354                 memset(mission_desc,0,MISSION_DESC_LENGTH+2);           
2355                 GET_STRING(mission_desc);
2356
2357                 // only display if we're in the proper state
2358                 state = gameseq_get_state();
2359                 switch(state){
2360                 case GS_STATE_MULTI_JOIN_GAME:
2361                 case GS_STATE_MULTI_CLIENT_SETUP:                       
2362                 case GS_STATE_MULTI_HOST_SETUP:
2363                         multi_common_set_text(mission_desc);
2364                         break;
2365                 }
2366         }
2367
2368         PACKET_SET_SIZE();      
2369 }
2370
2371 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2372 void broadcast_game_query()
2373 {
2374         int packet_size;
2375         net_addr addr;  
2376         server_item *s_moveup;
2377         ubyte data[MAX_PACKET_SIZE];    
2378
2379         BUILD_HEADER(GAME_QUERY);       
2380         
2381         // go through the server list and query each of those as well
2382         s_moveup = Game_server_head;
2383         if(s_moveup != NULL){
2384                 do {                            
2385                         send_server_query(&s_moveup->server_addr);                      
2386                         s_moveup = s_moveup->next;                                      
2387                 } while(s_moveup != Game_server_head);          
2388         }       
2389
2390         fill_net_addr(&addr, Psnet_my_addr.addr, DEFAULT_GAME_PORT);
2391
2392         // send out a broadcast if our options allow us
2393         if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2394                 psnet_broadcast( &addr, data, packet_size);
2395         }               
2396 }
2397
2398 // send an individual query to an address to see if there is an active game
2399 void send_server_query(net_addr *addr)
2400 {
2401         int packet_size;        
2402         ubyte data[MAX_PACKET_SIZE];
2403
2404         // build the header and send the data
2405         BUILD_HEADER(GAME_QUERY);                               
2406         psnet_send(addr, data, packet_size);
2407 }
2408
2409 // process a query from a client looking for active freespace games
2410 void process_game_query(ubyte* data, header* hinfo)
2411 {
2412         int offset;     
2413         net_addr addr;
2414
2415         offset = HEADER_LENGTH;
2416
2417         PACKET_SET_SIZE();
2418
2419         // check to be sure that we don't capture our own broadcast message
2420         fill_net_addr(&addr, hinfo->addr, hinfo->port);
2421         if ( psnet_same( &addr, &Psnet_my_addr) ){
2422                 return;
2423         }
2424
2425         // if I am not a server of a game, don't send a reply!!!
2426         if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2427                 return;
2428         }
2429
2430         // if the game options are being selected, then ignore the request
2431         // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2432         if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2433                 return;
2434         }
2435
2436         // send information about this active game
2437         send_game_active_packet(&addr);
2438 }
2439
2440 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2441 void send_netplayer_update_packet( net_player *pl )
2442 {
2443         int packet_size,idx;
2444         ubyte data[MAX_PACKET_SIZE],val;
2445
2446         BUILD_HEADER(NETPLAYER_UPDATE);
2447
2448         // if I'm the server of the game, I should send an update for _all_players in the game
2449         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2450                 for(idx=0;idx<MAX_PLAYERS;idx++){
2451                         // only send info for connected players
2452                         if(MULTI_CONNECTED(Net_players[idx])){
2453                                 // add a stop byte
2454                                 val = 0x0;
2455                                 ADD_DATA(val);
2456
2457                                 // add the net player's information
2458                                 ADD_SHORT(Net_players[idx].player_id);
2459                                 ADD_INT(Net_players[idx].state);
2460                                 ADD_INT(Net_players[idx].p_info.ship_class);                            
2461                                 ADD_INT(Net_players[idx].tracker_player_id);
2462
2463                                 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2464                                         val = 1;
2465                                 } else {
2466                                         val = 0;
2467                                 }
2468                                 ADD_DATA(val);                          
2469                         }
2470                 }
2471                 // add the final stop byte
2472                 val = 0xff;
2473                 ADD_DATA(val);
2474
2475                 // broadcast the packet
2476                 if(!(Game_mode & GM_IN_MISSION)){
2477                         if ( pl == NULL ) {
2478                                 multi_io_send_to_all_reliable(data, packet_size);                               
2479                         } else {
2480                                 multi_io_send_reliable(pl, data, packet_size);
2481                         }
2482                 } else {
2483                         if ( pl == NULL ) {
2484                                 multi_io_send_to_all(data, packet_size);
2485                         } else {                                
2486                                 multi_io_send(pl, data, packet_size);
2487                         }
2488                 }
2489         } else {
2490                 // add a stop byte
2491                 val = 0x0;
2492                 ADD_DATA(val);
2493
2494                 // add my current state in the netgame to this packet
2495                 ADD_SHORT(Net_player->player_id);
2496                 ADD_INT(Net_player->state);
2497                 ADD_INT(Net_player->p_info.ship_class);         
2498                 ADD_INT(Multi_tracker_id);
2499
2500                 // add if I have a CD or not
2501                 if(Multi_has_cd){
2502                         val = 1;
2503                 } else {
2504                         val = 0;
2505                 }
2506                 ADD_DATA(val);          
2507
2508                 // add a final stop byte
2509                 val = 0xff;
2510                 ADD_DATA(val);
2511
2512                 // send the packet to the server
2513                 SDL_assert( pl == NULL );                                               // shouldn't ever be the case that pl is non-null here.
2514                 if(!(Game_mode & GM_IN_MISSION)){                       
2515                         multi_io_send_reliable(Net_player, data, packet_size);
2516                 } else {                        
2517                         multi_io_send(Net_player, data, packet_size);
2518                 }
2519         }       
2520 }
2521
2522 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2523 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2524 {
2525         int offset, player_num;
2526         net_player bogus;
2527         ubyte stop, has_cd;
2528         short player_id;
2529         int new_state;
2530         
2531         offset = HEADER_LENGTH;
2532
2533         // get the first stop byte
2534         GET_DATA(stop);
2535         player_num = -1;
2536         while(stop != 0xff){
2537                 // look the player up
2538                 GET_SHORT(player_id);
2539                 player_num = find_player_id(player_id);
2540                 // if we couldn't find him, read in the bogus data
2541                 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2542                         GET_INT(bogus.state);
2543                         GET_INT(bogus.p_info.ship_class);                       
2544                         GET_INT(bogus.tracker_player_id);
2545
2546                         GET_DATA(has_cd);                       
2547                 } 
2548                 // otherwise read in the data correctly
2549                 else {
2550                         GET_INT(new_state);
2551                         GET_INT(Net_players[player_num].p_info.ship_class);                     
2552                         GET_INT(Net_players[player_num].tracker_player_id);
2553                         GET_DATA(has_cd);
2554                         if(has_cd){
2555                                 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2556                         } else {
2557                                 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2558                         }                       
2559
2560                         // if he's changing state to joined, send a team update
2561                         if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2562                                 multi_team_send_update();
2563                         }
2564
2565                         // set state
2566                         Net_players[player_num].state = new_state;
2567                 }
2568
2569                 // get the next stop byte
2570                 GET_DATA(stop);
2571         }
2572
2573         PACKET_SET_SIZE();      
2574
2575         // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2576         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2577                 send_netplayer_update_packet(NULL);
2578         }
2579
2580         // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2581         if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2582                 switch(Net_players[player_num].state){
2583                 case NETPLAYER_STATE_STD_HOST_SETUP:
2584                         Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2585                         break;
2586                 
2587                 case NETPLAYER_STATE_HOST_SETUP:
2588                         // check for race conditions
2589                         if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2590                                 Netgame.game_state = NETGAME_STATE_FORMING;
2591                         }
2592                         break;          
2593                 }
2594         }
2595 }
2596
2597 #define EXTRA_DEATH_VAPORIZED           (1<<0)
2598 #define EXTRA_DEATH_WASHED                      (1<<1)
2599 // send a packet indicating a ship has been killed
2600 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2601 {
2602         int packet_size, model;
2603         ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2604         ushort debris_signature;
2605         ubyte sd;
2606         polymodel * pm;
2607
2608         // only sendable from the master
2609         SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2610
2611         // special deaths
2612         vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2613
2614         extra_death_info = 0; 
2615         if ( vaporized ) {
2616                 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2617         }
2618
2619         if ( Ships[objp->instance].wash_killed ) {
2620                 extra_death_info |= EXTRA_DEATH_WASHED;
2621         }
2622
2623         // find out the next network signature that will be used for the debris pieces.
2624         model = Ships[objp->instance].modelnum;
2625         pm = model_get(model);
2626         debris_signature = 0;
2627         if ( pm && !vaporized ) {
2628                 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2629                 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2630                 Ships[objp->instance].arrival_distance = debris_signature;
2631         }
2632
2633         BUILD_HEADER(SHIP_KILL);
2634         ADD_USHORT(objp->net_signature);
2635
2636         // ships which are initially killed get the rest of the data sent.  self destructed ships and
2637         if ( other_objp == NULL ) {
2638                 ushort temp;
2639
2640                 temp = 0;
2641                 ADD_USHORT(temp);
2642                 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2643         } else {
2644                 ADD_USHORT( other_objp->net_signature );
2645         }
2646
2647         ADD_USHORT( debris_signature );
2648         ADD_FLOAT( percent_killed );
2649         sd = (ubyte)self_destruct;
2650         ADD_DATA(sd);
2651         ADD_DATA( extra_death_info );
2652
2653         // if the ship who died is a player, then send some extra info, like who killed him, etc.
2654         was_player = 0;
2655         if ( objp->flags & OF_PLAYER_SHIP ) {
2656                 int pnum;
2657                 char temp;
2658
2659                 pnum = multi_find_player_by_object( objp );
2660                 if ( pnum != -1 ) {
2661                         was_player = 1;
2662                         ADD_DATA( was_player );
2663
2664                         SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX); 
2665                         temp = (char)Net_players[pnum].player->killer_objtype;
2666                         ADD_DATA( temp );
2667
2668                         SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX); 
2669                         temp = (char)Net_players[pnum].player->killer_species;
2670                         ADD_DATA( temp );
2671
2672                         SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX); 
2673                         temp = (char)Net_players[pnum].player->killer_weapon_index;
2674                         ADD_DATA( temp );
2675
2676                         ADD_STRING( Net_players[pnum].player->killer_parent_name );
2677                 } else {
2678                         ADD_DATA( was_player );
2679                 }
2680         } else {
2681                 ADD_DATA( was_player );
2682         }
2683
2684         // send the packet reliably!!!
2685         multi_io_send_to_all_reliable(data, packet_size);       
2686 }
2687
2688 // process a packet indicating that a ship has been killed
2689 void process_ship_kill_packet( ubyte *data, header *hinfo )
2690 {
2691         int offset;
2692         ushort ship_sig, other_sig, debris_sig;
2693         object *sobjp, *oobjp;
2694         float percent_killed;   
2695         ubyte was_player, extra_death_info, sd;
2696         char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2697
2698         offset = HEADER_LENGTH;
2699         GET_USHORT(ship_sig);
2700
2701         GET_USHORT( other_sig );
2702         GET_USHORT( debris_sig );
2703         GET_FLOAT( percent_killed );
2704         GET_DATA( sd );
2705         GET_DATA( extra_death_info );
2706         GET_DATA( was_player );
2707
2708
2709         // pnum is >=0 when the dying ship is a pleyer ship.  Get the info about how he died
2710         if ( was_player != 0 ) {
2711                 GET_DATA( killer_objtype );
2712                 GET_DATA( killer_species );
2713                 GET_DATA( killer_weapon_index );
2714                 GET_STRING( killer_name );
2715         }
2716
2717         PACKET_SET_SIZE();
2718
2719         sobjp = multi_get_network_object( ship_sig );
2720
2721         // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2722         // another message from the server that this happened!
2723         if ( sobjp == NULL ) {
2724                 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));             
2725                 return;
2726         }
2727
2728         // set this ship's hull value to 0
2729         sobjp->hull_strength = 0.0f;
2730
2731         // maybe set vaporized
2732         if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2733                 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2734         }
2735
2736         // maybe set wash_killed
2737         if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2738                 Ships[sobjp->instance].wash_killed = 1;
2739         }
2740
2741         oobjp = multi_get_network_object( other_sig );
2742
2743         if ( was_player != 0 ) {
2744                 int pnum;
2745
2746                 pnum = multi_find_player_by_object( sobjp );
2747                 if ( pnum != -1 ) {
2748                         Net_players[pnum].player->killer_objtype = killer_objtype;
2749                         Net_players[pnum].player->killer_species = killer_species;
2750                         Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2751                         SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2752                 }
2753         }          
2754
2755         // check to see if I need to respawn myself
2756         multi_respawn_check(sobjp);
2757
2758         // store the debris signature in the arrival distance which will never get used for player ships
2759         Ships[sobjp->instance].arrival_distance = debris_sig;
2760
2761         // set this bit so that we don't accidentally start switching targets when we die
2762         if(sobjp == Player_obj){
2763                 Game_mode |= GM_DEAD_DIED;
2764         }
2765
2766         nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2767
2768         // do the normal thing when not ingame joining.  When ingame joining, simply kill off the ship.
2769         if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2770                 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2771         } else {
2772                 extern void ship_destroyed( int shipnum );
2773                 ship_destroyed( sobjp->instance );
2774                 sobjp->flags |= OF_SHOULD_BE_DEAD;
2775                 obj_delete( OBJ_INDEX(sobjp) );
2776         }
2777 }
2778
2779 // send a packet indicating a ship should be created
2780 void send_ship_create_packet( object *objp, int is_support )
2781 {
2782         int packet_size;
2783         ubyte data[MAX_PACKET_SIZE];
2784
2785         // We will pass the ship to create by name.
2786         BUILD_HEADER(SHIP_CREATE);
2787         ADD_USHORT(objp->net_signature);
2788         ADD_INT( is_support );
2789         if ( is_support ){
2790                 add_vector_data(data, &packet_size, objp->pos);
2791         }
2792
2793         // broadcast the packet 
2794         multi_io_send_to_all_reliable(data, packet_size);
2795 }
2796
2797 // process a packet indicating a ship should be created
2798 void process_ship_create_packet( ubyte *data, header *hinfo )
2799 {
2800         int offset, objnum, is_support;
2801         ushort signature;
2802         p_object *objp;
2803         vector pos = ZERO_VECTOR;
2804
2805         SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2806         offset = HEADER_LENGTH;
2807         GET_USHORT(signature);
2808         GET_INT( is_support );
2809         if ( is_support ){
2810                 get_vector_data(data, &offset, pos);
2811         }
2812
2813         PACKET_SET_SIZE();
2814
2815         // find the name of this ship on ship ship arrival list.  if found, pass it to parse_object_create
2816         if ( !is_support ) {
2817                 objp = mission_parse_get_arrival_ship( signature );
2818                 if ( objp != NULL ) {
2819                         parse_create_object(objp);
2820                 } else {
2821                         nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2822                 }
2823         } else {
2824                 SDL_assert( Arriving_support_ship );
2825                 if(Arriving_support_ship == NULL){
2826                         return;
2827                 }
2828                 Arriving_support_ship->pos = pos;
2829                 Arriving_support_ship->net_signature = signature;
2830                 objnum = parse_create_object( Arriving_support_ship );
2831                 SDL_assert( objnum != -1 );
2832                 if(objnum < 0){
2833                         mission_parse_support_arrived( objnum );
2834                 }
2835         }
2836 }
2837
2838 // send a packet indicating a wing of ships should be created
2839 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2840 {
2841         int packet_size, index, ship_instance;
2842         ubyte data[MAX_PACKET_SIZE];
2843         ushort signature;
2844         int val;
2845
2846         // for creating wing -- we just send the index into the wing array of this wing.
2847         // all players load the same mission, and so their array's should all match. We also
2848         // need to send the signature of the first ship that was created.  We can find this by
2849         // looking num_to_create places back in the ship_index field in the wing structure.
2850
2851         index = WING_INDEX(wingp);
2852         ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2853         signature = Objects[Ships[ship_instance].objnum].net_signature;
2854
2855         BUILD_HEADER( WING_CREATE );
2856         ADD_INT(index);
2857         ADD_INT(num_to_create);
2858         ADD_USHORT(signature);          
2859         ADD_INT(pre_create_count);
2860         val = wingp->current_wave - 1;
2861         ADD_INT(val);
2862         
2863         multi_io_send_to_all_reliable(data, packet_size);       
2864 }
2865
2866 // process a packet saying that a wing should be created
2867 void process_wing_create_packet( ubyte *data, header *hinfo )
2868 {
2869         int offset, index, num_to_create;
2870         ushort signature;
2871         int total_arrived_count, current_wave;
2872
2873         offset = HEADER_LENGTH;
2874         GET_INT(index);
2875         GET_INT(num_to_create);
2876         GET_USHORT(signature);
2877         GET_INT(total_arrived_count);
2878         GET_INT(current_wave);
2879
2880         PACKET_SET_SIZE();
2881
2882         // do a sanity check on the wing to be sure that we are actually working on a valid wing
2883         if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2884                 nprintf(("Network", "invalid index %d for wing create packet\n"));
2885                 return;
2886         }
2887         if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2888                 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2889                 return;
2890         }
2891
2892         // bash some info
2893         Wings[index].current_count = 0;
2894         Wings[index].total_arrived_count = total_arrived_count;
2895         Wings[index].current_wave = current_wave;
2896
2897         // set the network signature that was passed.  The client should create ships in the same order
2898         // as the server -- so all ships should get the same sigs as assigned by the server.  We also
2899         // need to set some timestamps and cues correctly to be sure that these things get created on
2900         // the clients correctly
2901         multi_set_network_signature( signature, MULTI_SIG_SHIP );
2902         parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2903 }
2904
2905 // packet indicating a ship is departing
2906 void send_ship_depart_packet( object *objp )
2907 {
2908         ubyte data[MAX_PACKET_SIZE];
2909         int packet_size;
2910         ushort signature;
2911
2912         signature = objp->net_signature;
2913
2914         BUILD_HEADER(SHIP_DEPART);
2915         ADD_USHORT( signature );
2916         
2917         multi_io_send_to_all_reliable(data, packet_size);
2918 }
2919
2920 // process a packet indicating a ship is departing
2921 void process_ship_depart_packet( ubyte *data, header *hinfo )
2922 {
2923         int offset;
2924         object *objp;
2925         ushort signature;
2926
2927         offset = HEADER_LENGTH;
2928         GET_USHORT( signature );
2929         PACKET_SET_SIZE();
2930
2931         // find the object which is departing
2932         objp = multi_get_network_object( signature );
2933         if ( objp == NULL ) {
2934                 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2935                 return;
2936         }
2937
2938         // start warping him out
2939         shipfx_warpout_start( objp );
2940 }
2941
2942 // packet to tell clients cargo of a ship was revealed to all
2943 void send_cargo_revealed_packet( ship *shipp )
2944 {
2945         ubyte data[MAX_PACKET_SIZE];
2946         int packet_size;
2947
2948         // build the header and add the data
2949         BUILD_HEADER(CARGO_REVEALED);
2950         ADD_USHORT( Objects[shipp->objnum].net_signature );
2951
2952         // server sends to all players
2953         if(MULTIPLAYER_MASTER){         
2954                 multi_io_send_to_all_reliable(data, packet_size);
2955         } 
2956         // clients just send to the server
2957         else {
2958                 multi_io_send_reliable(Net_player, data, packet_size);
2959         }
2960 }
2961
2962 // process a cargo revealed packet
2963 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2964 {
2965         int offset;
2966         ushort signature;
2967         object *objp;
2968
2969         offset = HEADER_LENGTH;
2970         GET_USHORT(signature);
2971         PACKET_SET_SIZE();
2972
2973         // get a ship pointer and call the ship function to reveal the cargo
2974         objp = multi_get_network_object( signature );
2975         if ( objp == NULL ) {
2976                 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2977                 return;
2978         }
2979
2980         // SDL_assert( objp->type == OBJ_SHIP );
2981         if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2982                 return;
2983         }
2984
2985         // this will take care of re-routing to all other clients
2986         ship_do_cargo_revealed( &Ships[objp->instance], 1);     
2987
2988         // server should rebroadcast
2989         if(MULTIPLAYER_MASTER){
2990                 send_cargo_revealed_packet(&Ships[objp->instance]);
2991         }
2992 }
2993
2994 // defines used for secondary fire packet
2995 #define SFPF_ALLOW_SWARM                (1<<7)
2996 #define SFPF_DUAL_FIRE                  (1<<6)
2997 #define SFPF_TARGET_LOCKED              (1<<5)
2998
2999 // send a packet indicating a secondary weapon was fired
3000 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
3001 {
3002         int packet_size, net_player_num;
3003         ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
3004         object *objp;
3005         ushort target_signature;
3006         char t_subsys;
3007         ai_info *aip;
3008
3009         // SDL_assert ( starting_count < UCHAR_MAX );
3010
3011         // get the object for this ship.  If it is an AI object, send all the info to all player.  Otherwise,
3012         // we might send the info to the other player different than the one who fired
3013         objp = &Objects[shipp->objnum];
3014         if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3015                 if ( num_fired == 0 ) {
3016                         return;
3017                 }
3018         }
3019
3020         aip = &Ai_info[shipp->ai_index];
3021
3022         current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3023         //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );    // always true
3024
3025         // build up the header portion
3026         BUILD_HEADER( SECONDARY_FIRED_AI );
3027
3028         ADD_USHORT( Objects[shipp->objnum].net_signature );
3029         ADD_USHORT( starting_sig );
3030         
3031         // add a couple of bits for swarm missiles and dual fire secondary weaspons
3032         sinfo = 0;
3033
3034         sinfo = current_bank;
3035
3036         if ( allow_swarm ){
3037                 sinfo |= SFPF_ALLOW_SWARM;
3038         }
3039
3040         if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3041                 sinfo |= SFPF_DUAL_FIRE;
3042         }
3043
3044         if ( aip->current_target_is_locked ){
3045                 sinfo |= SFPF_TARGET_LOCKED;
3046         }
3047
3048         ADD_DATA( sinfo );
3049
3050         // add the ship's target and any targeted subsystem
3051         target_signature = 0;
3052         t_subsys = -1;
3053         if ( aip->target_objnum != -1) {
3054                 target_signature = Objects[aip->target_objnum].net_signature;
3055                 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3056                         int s_index;
3057
3058                         s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3059                         SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
3060                         t_subsys = (char)s_index;
3061                 }
3062
3063                 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3064                         SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3065                 }
3066
3067         }
3068
3069         ADD_USHORT( target_signature );
3070         ADD_DATA( t_subsys );
3071
3072         // just send this packet to everyone, then bail if an AI ship fired.
3073         if ( !(objp->flags & OF_PLAYER_SHIP) ) {                
3074                 multi_io_send_to_all(data, packet_size);
3075                 return;
3076         }
3077
3078         net_player_num = multi_find_player_by_object( objp );
3079
3080         // getting here means a player fired.  Send the current packet to all players except the player
3081         // who fired.  If nothing got fired, then don't send to the other players -- we will just send
3082         // a packet to the player who will find out that he didn't fire anything
3083         if ( num_fired > 0 ) {
3084                 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);         
3085         }
3086
3087         // if I (the master) fired, then return
3088         if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3089                 return;
3090         }
3091
3092         // now build up the packet to send to the player who actually fired.
3093         BUILD_HEADER( SECONDARY_FIRED_PLR );
3094         ADD_USHORT(starting_sig);
3095         ADD_DATA( sinfo );
3096
3097         // add the targeting information so that the player's weapons will always home on the correct
3098         // ship
3099         ADD_USHORT( target_signature );
3100         ADD_DATA( t_subsys );
3101         
3102         multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3103 }
3104
3105 /// process a packet indicating a secondary weapon was fired
3106 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3107 {
3108         int offset, allow_swarm, target_objnum_save;
3109         ushort net_signature, starting_sig, target_signature;
3110         ubyte sinfo, current_bank;
3111         object* objp, *target_objp;
3112         ship *shipp;
3113         char t_subsys;
3114         ai_info *aip;
3115         ship_subsys *targeted_subsys_save;
3116
3117         offset = HEADER_LENGTH; // size of the header
3118
3119         // if from_player is false, it means that the secondary weapon info in this packet was
3120         // fired by an ai object (or another player).  from_player == 1 means tha me (the person
3121         // receiving this packet) fired the secondary weapon
3122         if ( !from_player ) {
3123                 GET_USHORT( net_signature );
3124                 GET_USHORT( starting_sig );
3125                 GET_DATA( sinfo );                      // are we firing swarm missiles
3126
3127                 GET_USHORT( target_signature );
3128                 GET_DATA( t_subsys );
3129
3130                 PACKET_SET_SIZE();
3131
3132                 // find the object (based on network signatures) for the object that fired
3133                 objp = multi_get_network_object( net_signature );
3134                 if ( objp == NULL ) {
3135                         nprintf(("Network", "Could not find ship for fire secondary packet!"));
3136                         return;
3137                 }
3138
3139                 // set up the ships current secondary bank and that bank's mode.  Below, we will set the timeout
3140                 // of the next fire time of this bank to 0 so we can fire right away
3141                 shipp = &Ships[objp->instance];
3142
3143         } else {
3144                 GET_USHORT( starting_sig );
3145                 GET_DATA( sinfo );
3146
3147                 GET_USHORT( target_signature );
3148                 GET_DATA( t_subsys );
3149
3150                 PACKET_SET_SIZE();
3151
3152                 // get the object and ship
3153                 objp = Player_obj;
3154                 shipp = Player_ship;
3155         }
3156
3157         // check the allow swarm bit
3158         allow_swarm = 0;
3159         if ( sinfo & SFPF_ALLOW_SWARM ){
3160                 allow_swarm = 1;
3161         }
3162
3163         // set the dual fire properties of the ship
3164         if ( sinfo & SFPF_DUAL_FIRE ){
3165                 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3166         } else {
3167                 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3168         }
3169
3170         // determine whether current target is locked
3171         SDL_assert( shipp->ai_index != -1 );
3172         aip = &Ai_info[shipp->ai_index];
3173         if ( sinfo & SFPF_TARGET_LOCKED ) {
3174                 aip->current_target_is_locked = 1;
3175         } else {
3176                 aip->current_target_is_locked = 0;
3177         }
3178
3179         // find out the current bank
3180         current_bank = (ubyte)(sinfo & 0x3);
3181         //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );    // always true
3182         shipp->weapons.current_secondary_bank = current_bank;
3183
3184         // make it so we can fire this ship's secondary bank immediately!!!
3185         shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3186         shipp->weapons.detonate_weapon_time = timestamp(5000);          // be sure that we don't detonate a remote weapon before it is time.
3187
3188         // set this ship's target and subsystem information.  We will save and restore target and
3189         // targeted subsystem so that we do not accidentally change targets for this player or
3190         // any AI ships on his system.
3191         target_objnum_save = aip->target_objnum;
3192         targeted_subsys_save = aip->targeted_subsys;
3193
3194         // reset these variables for accuracy.  They will get reassigned at the end of this fuction
3195         aip->target_objnum = -1;
3196         aip->targeted_subsys = NULL;
3197
3198         target_objp = multi_get_network_object( target_signature );
3199         if ( target_objp != NULL ) {
3200                 aip->target_objnum = OBJ_INDEX(target_objp);
3201
3202                 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3203                         aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3204                 }
3205         }
3206
3207         if ( starting_sig != 0 ){
3208                 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3209         } else {
3210                 shipp->weapons.detonate_weapon_time = timestamp(0);             // signature of -1 say detonate remote weapon
3211         }
3212
3213         ship_fire_secondary( objp, allow_swarm );
3214
3215         // restore targeted object and targeted subsystem
3216         aip->target_objnum = target_objnum_save;
3217         aip->targeted_subsys = targeted_subsys_save;
3218 }
3219
3220 // send a packet indicating a countermeasure was fired
3221 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3222 {
3223         ubyte data[MAX_PACKET_SIZE];
3224         int packet_size;
3225
3226         Int3();
3227
3228         SDL_assert ( cmeasure_count < UCHAR_MAX );
3229         BUILD_HEADER(COUNTERMEASURE_FIRED);
3230         ADD_USHORT( objp->net_signature );
3231         ADD_INT( rand_val );
3232                 
3233         multi_io_send_to_all(data, packet_size);
3234 }
3235
3236 // process a packet indicating a countermeasure was fired
3237 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3238 {
3239         int offset, rand_val;
3240         ushort signature;
3241         object *objp;
3242
3243         Int3();
3244
3245         offset = HEADER_LENGTH; 
3246
3247         GET_USHORT( signature );
3248         GET_INT( rand_val );
3249         PACKET_SET_SIZE();
3250
3251         objp = multi_get_network_object( signature );
3252         if ( objp == NULL ) {
3253                 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3254                 return;
3255         }
3256         if(objp->type != OBJ_SHIP){
3257                 return;
3258         }
3259         // SDL_assert ( objp->type == OBJ_SHIP );
3260
3261         // make it so ship can fire right away!
3262         Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3263         if ( objp == Player_obj ){
3264                 nprintf(("network", "firing countermeasure from my ship\n"));
3265         }
3266
3267         ship_launch_countermeasure( objp, rand_val );           
3268 }
3269
3270 // send a packet indicating that a turret has been fired
3271 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3272 {
3273         int packet_size;
3274         ushort pnet_signature;
3275         ubyte data[MAX_PACKET_SIZE], cindex;
3276         object *objp;
3277         ubyte has_sig = 0;
3278         ship_subsys *ssp;
3279         short val;
3280
3281         // sanity
3282         if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3283                 return;
3284         }
3285
3286         // local setup -- be sure we are actually passing a weapon!!!!
3287         objp = &Objects[weapon_objnum];
3288         SDL_assert ( objp->type == OBJ_WEAPON );
3289         if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3290                 has_sig = 1;
3291         }
3292
3293         pnet_signature = Objects[ship_objnum].net_signature;
3294
3295         SDL_assert( subsys_index < UCHAR_MAX );
3296         cindex = (ubyte)subsys_index;
3297
3298         ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3299         if(ssp == NULL){
3300                 return;
3301         }
3302
3303         // build the fire turret packet.  
3304         BUILD_HEADER(FIRE_TURRET_WEAPON);       
3305         packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3306         ADD_DATA( has_sig );
3307         ADD_USHORT( pnet_signature );   
3308         if(has_sig){            
3309                 ADD_USHORT( objp->net_signature );
3310         }
3311         ADD_DATA( cindex );
3312         val = (short)ssp->submodel_info_1.angs.h;
3313         ADD_SHORT( val );
3314         val = (short)ssp->submodel_info_2.angs.p;
3315         ADD_SHORT( val );       
3316         
3317         multi_io_send_to_all(data, packet_size);
3318
3319         multi_rate_add(1, "tur", packet_size);
3320 }
3321
3322 // process a packet indicating a turret has been fired
3323 void process_turret_fired_packet( ubyte *data, header *hinfo )
3324 {
3325         int offset, weapon_objnum, wid;
3326         ushort pnet_signature, wnet_signature;
3327         vector pos, temp;
3328         matrix orient;
3329         vector o_fvec;
3330         ubyte turret_index;
3331         object *objp;
3332         ship_subsys *ssp;
3333         ubyte has_sig = 0;
3334         ship *shipp;
3335         short pitch, heading;   
3336
3337         // get the data for the turret fired packet
3338         offset = HEADER_LENGTH; 
3339         offset += multi_pack_unpack_position(0, data + offset, &o_fvec);        
3340         GET_DATA( has_sig );
3341         GET_USHORT( pnet_signature );
3342         if(has_sig){
3343                 GET_USHORT( wnet_signature );
3344         } else {
3345                 wnet_signature = 0;
3346         }
3347         GET_DATA( turret_index );
3348         GET_SHORT( heading );
3349         GET_SHORT( pitch );     
3350         PACKET_SET_SIZE();                              // move our counter forward the number of bytes we have read
3351
3352         // find the object
3353         objp = multi_get_network_object( pnet_signature );
3354         if ( objp == NULL ) {
3355                 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3356                 return;
3357         }
3358
3359         // if this isn't a ship, do nothing
3360         if ( objp->type != OBJ_SHIP ){
3361                 return;
3362         }
3363
3364         // make an orientation matrix from the o_fvec
3365         vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3366
3367         // find this turret, and set the position of the turret that just fired to be where it fired.  Quite a
3368         // hack, but should be suitable.
3369         shipp = &Ships[objp->instance];
3370         ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3371         if(ssp == NULL){
3372                 return;
3373         }
3374         wid = ssp->system_info->turret_weapon_type;
3375
3376         // bash the position and orientation of the turret
3377         ssp->submodel_info_1.angs.h = (float)heading;
3378         ssp->submodel_info_2.angs.p = (float)pitch;
3379
3380         // get the world position of the weapon
3381         ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3382
3383         // create the weapon object
3384         if(wnet_signature != 0){                
3385                 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3386         }
3387         weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3388         if (weapon_objnum != -1) {
3389                 if ( Weapon_info[wid].launch_snd != -1 ) {
3390                         snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3391                 }               
3392         }
3393 }
3394
3395 // send a mission log item packet
3396 void send_mission_log_packet( int num )
3397 {
3398         int packet_size;
3399         ubyte data[MAX_PACKET_SIZE];
3400         ubyte type;
3401         ushort sindex;
3402         log_entry *entry;
3403
3404         SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3405
3406         // get the data from the log
3407         entry = &log_entries[num];
3408         type = (ubyte)entry->type;                      // do the type casting thing to save on packet space
3409         sindex = (ushort)entry->index;
3410
3411         BUILD_HEADER(MISSION_LOG_ENTRY);
3412         ADD_DATA(type);
3413         ADD_INT(entry->flags);
3414         ADD_USHORT(sindex);
3415         ADD_DATA(entry->timestamp);
3416         ADD_STRING(entry->pname);
3417         ADD_STRING(entry->sname);
3418
3419         // broadcast the packet to all players  
3420         multi_io_send_to_all_reliable(data, packet_size);
3421 }
3422
3423 // process a mission log item packet
3424 void process_mission_log_packet( ubyte *data, header *hinfo )
3425 {
3426         int offset, flags;
3427         ushort sindex;
3428         ubyte type;
3429         char pname[NAME_LENGTH], sname[NAME_LENGTH];
3430         fix timestamp;
3431
3432         SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3433
3434         offset = HEADER_LENGTH;
3435         GET_DATA(type);
3436         GET_INT(flags);
3437         GET_USHORT(sindex);
3438         GET_DATA(timestamp);
3439         GET_STRING(pname);
3440         GET_STRING(sname);
3441
3442         PACKET_SET_SIZE();
3443
3444         mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3445 }
3446
3447 // send a mission message packet
3448 void send_mission_message_packet( int id, const char *who_from, int priority, int timing, int source, int builtin_type, int multi_target, int multi_team_filter)
3449 {
3450         int packet_size;
3451         ubyte data[MAX_PACKET_SIZE], up, us, utime;
3452         
3453         SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3454         SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3455         SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );   
3456         
3457         up = (ubyte) priority;
3458         us = (ubyte) source;
3459         utime = (ubyte)timing;
3460
3461         BUILD_HEADER(MISSION_MESSAGE);
3462         ADD_INT(id);
3463         ADD_STRING(who_from);
3464         ADD_DATA(up);
3465         ADD_DATA(utime);
3466         ADD_DATA(us);
3467         ADD_INT(builtin_type);
3468         ADD_INT(multi_team_filter);
3469
3470         if (multi_target == -1){                
3471                 multi_io_send_to_all_reliable(data, packet_size);
3472         } else {                
3473                 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3474         }
3475 }
3476
3477 // process a mission message packet
3478 void process_mission_message_packet( ubyte *data, header *hinfo )
3479 {
3480         int offset, id, builtin_type;
3481         ubyte priority, source, utiming;
3482         char who_from[NAME_LENGTH];
3483         int multi_team_filter;
3484
3485         SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3486
3487         offset = HEADER_LENGTH;
3488         GET_INT(id);
3489         GET_STRING(who_from);
3490         GET_DATA(priority);
3491         GET_DATA(utiming);
3492         GET_DATA(source);
3493         GET_INT(builtin_type);
3494         GET_INT(multi_team_filter);
3495
3496         PACKET_SET_SIZE();
3497
3498         // filter out builtin ones in TvT
3499         if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3500                 return;
3501         }
3502
3503         // maybe filter this out
3504         if(!message_filter_multi(id)){
3505                 // send the message as if it came from an sexpression
3506                 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3507         }
3508 }
3509
3510 // just send them a pong back as fast as possible
3511 void process_ping_packet(ubyte *data, header *hinfo)
3512 {
3513    net_addr addr;
3514         int offset;
3515
3516         offset = HEADER_LENGTH;
3517         PACKET_SET_SIZE();
3518
3519         // get the address to return the pong to
3520         fill_net_addr(&addr, hinfo->addr, hinfo->port);
3521                     
3522         // send the pong
3523         send_pong(&addr);       
3524 }
3525
3526 // right now it just routes the pong through to the standalone gui, which is the only
3527 // system which uses ping and pong right now.
3528 void process_pong_packet(ubyte *data, header *hinfo)
3529 {
3530         net_player *p;
3531         net_addr addr;
3532         int offset,lookup;
3533         
3534         offset = HEADER_LENGTH;
3535
3536         fill_net_addr(&addr, hinfo->addr, hinfo->port);
3537                 
3538         PACKET_SET_SIZE();      
3539                 
3540         // if we're connected , see who sent us this pong
3541         if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3542                 lookup = find_player_id(hinfo->id);
3543                 if(lookup == -1){
3544                         return;
3545                 }
3546                 
3547                 p = &Net_players[lookup]; 
3548
3549                 // evaluate the ping
3550                 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3551                         
3552                 // put in calls to any functions which may want to know about the ping times from 
3553                 // this guy
3554                 if(Game_mode & GM_STANDALONE_SERVER){
3555                    std_update_player_ping(p);   
3556                 }
3557
3558 #ifdef PSNET2
3559                 // mark his socket as still alive (extra precaution)
3560                 psnet_mark_received(Net_players[lookup].reliable_socket);
3561 #endif
3562         }
3563         // otherwise, do any special processing
3564         else {
3565                 // if we're in the join game state, see if this pong came from a server on our
3566                 // list
3567                 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3568                         multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3569                 }
3570         }
3571 }
3572
3573 // send a ping packet
3574 void send_ping(net_addr *addr)
3575 {
3576         unsigned char data[8];
3577         int packet_size;
3578
3579         // build the header and send the packet
3580         BUILD_HEADER( PING );           
3581         psnet_send(addr, &data[0], packet_size);
3582 }
3583
3584 // send a pong packet
3585 void send_pong(net_addr *addr)
3586 {
3587    unsigned char data[8];
3588         int packet_size;        
3589
3590         // build the header and send the packet
3591         BUILD_HEADER(PONG);             
3592         psnet_send(addr, &data[0], packet_size);   
3593 }
3594
3595 // sent from host to master. give me the list of missions you have.
3596 // this will be used only in a standalone mode
3597 void send_mission_list_request( int what )
3598 {
3599         ubyte data[MAX_PACKET_SIZE];
3600         int packet_size;
3601
3602         // build the header and ask for a list of missions or campaigns (depending
3603         // on the 'what' flag).
3604         BUILD_HEADER(MISSION_REQUEST);
3605                 
3606         multi_io_send_reliable(Net_player, data, packet_size);
3607 }
3608
3609 // maximum number of bytes that we can send in a mission items packet.
3610 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3611
3612 // defines used to tell what type of packets are being sent
3613 #define MISSION_LIST_ITEMS                      1
3614 #define CAMPAIGN_LIST_ITEMS             2
3615
3616 // send an individual mission file item
3617 void send_mission_items( net_player *pl )
3618 {
3619         ubyte data[MAX_PACKET_SIZE];
3620         int packet_size, i;
3621         ubyte stop, type;
3622
3623         // build the header     
3624         BUILD_HEADER(MISSION_ITEM);     
3625
3626         // send the list of missions and campaigns avilable on the server.  Stop when
3627         // reaching a certain maximum
3628         type = MISSION_LIST_ITEMS;
3629         ADD_DATA( type );
3630         for (i = 0; i < Multi_create_mission_count; i++ ) {             
3631                 stop = 0;
3632                 ADD_DATA( stop );
3633
3634                 ADD_STRING( Multi_create_mission_list[i].filename );
3635                 ADD_STRING( Multi_create_mission_list[i].name );
3636                 ADD_INT( Multi_create_mission_list[i].flags );
3637                 ADD_DATA( Multi_create_mission_list[i].max_players );
3638                 ADD_UINT( Multi_create_mission_list[i].respawn );               
3639
3640                 // STANDALONE_ONLY              
3641                 ADD_DATA( Multi_create_mission_list[i].valid_status );
3642
3643                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3644                         stop = 1;
3645                         ADD_DATA( stop );                       
3646                         multi_io_send_reliable(pl, data, packet_size);
3647                         BUILD_HEADER( MISSION_ITEM );
3648                         ADD_DATA( type );
3649                 }               
3650         }
3651         stop = 1;
3652         ADD_DATA(stop); 
3653         multi_io_send_reliable(pl, data, packet_size);
3654
3655         // send the campaign information
3656         type = CAMPAIGN_LIST_ITEMS;
3657         BUILD_HEADER(MISSION_ITEM);
3658         ADD_DATA( type );
3659         for (i = 0; i < Multi_create_campaign_count; i++ ) {            
3660                 stop = 0;
3661                 ADD_DATA( stop );
3662
3663                 ADD_STRING( Multi_create_campaign_list[i].filename );
3664                 ADD_STRING( Multi_create_campaign_list[i].name );
3665                 ADD_INT( Multi_create_campaign_list[i].flags ); 
3666                 ADD_DATA( Multi_create_campaign_list[i].max_players );          
3667
3668                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3669                         stop = 1;
3670                         ADD_DATA( stop );                       
3671                         multi_io_send_reliable(pl, data, packet_size);
3672                         BUILD_HEADER( MISSION_ITEM );
3673                         ADD_DATA( type );
3674                 }               
3675         }
3676         stop = 1;
3677         ADD_DATA(stop); 
3678         multi_io_send_reliable(pl, data, packet_size);
3679 }
3680
3681 // process a request for a list of missions
3682 void process_mission_request_packet(ubyte *data, header *hinfo)
3683 {   
3684         int player_num,offset;  
3685         
3686         offset = HEADER_LENGTH;
3687         PACKET_SET_SIZE();
3688
3689         // fill in the address information of where this came from      
3690         player_num = find_player_id(hinfo->id);
3691         if(player_num == -1){
3692                 nprintf(("Network","Could not find player to send mission list items to!\n"));
3693                 return;
3694         }
3695
3696         send_mission_items( &Net_players[player_num] );
3697 }
3698
3699 // process an individual mission file item
3700 void process_mission_item_packet(ubyte *data,header *hinfo)
3701 {
3702    int offset, flags;           
3703         char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3704         ubyte stop, type,max_players;
3705         uint respawn;
3706
3707         SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3708         offset = HEADER_LENGTH;
3709
3710         GET_DATA( type );
3711         GET_DATA(stop);
3712         while( !stop ) {
3713                 GET_STRING( filename );
3714                 GET_STRING( name );
3715                 GET_INT( flags );
3716                 GET_DATA( max_players );
3717
3718                 // missions also have respawns and a crc32 associated with them
3719                 if(type == MISSION_LIST_ITEMS){
3720                         GET_UINT(respawn);
3721
3722                         // STANDALONE_ONLY                      
3723                         GET_DATA(valid_status);
3724
3725                         if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3726                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3727                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3728                                 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3729                                 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3730                                 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3731
3732                                 // STANDALONE_ONLY                              
3733                                 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3734
3735                                 Multi_create_mission_count++;
3736                         }
3737                 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3738                         if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3739                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3740                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3741                                 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3742                                 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3743                                 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3744                                 Multi_create_campaign_count++;
3745                         }
3746                 }
3747
3748                 GET_DATA( stop );
3749         }
3750         
3751         PACKET_SET_SIZE();      
3752
3753         // this will cause whatever list to get resorted (although they should be appearing in order)
3754         multi_create_setup_list_data(-1);               
3755 }
3756
3757 // send a request to the server to pause or unpause the game
3758 void send_multi_pause_packet(int pause)
3759 {
3760         ubyte data[MAX_PACKET_SIZE];
3761         ubyte val;
3762         int packet_size = 0;
3763         
3764         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3765         
3766         // build the header
3767         BUILD_HEADER(MULTI_PAUSE_REQUEST);
3768         val = (ubyte) pause;
3769         
3770         // add the pause info
3771         ADD_DATA(val);  
3772
3773         // send the request to the server       
3774         multi_io_send_reliable(Net_player, data, packet_size);
3775 }
3776
3777 // process a pause update packet (pause, unpause, etc)
3778 void process_multi_pause_packet(ubyte *data, header *hinfo)
3779 {
3780         int offset;
3781         ubyte val;              
3782         int player_index;
3783
3784         offset = HEADER_LENGTH;
3785
3786         // get the data
3787         GET_DATA(val);  
3788         PACKET_SET_SIZE();
3789
3790         // get who sent the packet      
3791         player_index = find_player_id(hinfo->id);
3792         // if we don't know who sent the packet, don't do anything
3793         if(player_index == -1){
3794                 return;
3795         }
3796
3797         // if we're the server, we should evaluate whether this guy is allowed to send the packet
3798         multi_pause_server_eval_request(&Net_players[player_index],(int)val);   
3799 }
3800
3801 // send a game information update
3802 void send_game_info_packet()
3803 {
3804         int packet_size;
3805         ubyte data[MAX_PACKET_SIZE], paused;
3806
3807         // set the paused variable
3808         paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3809
3810         BUILD_HEADER(GAME_INFO);
3811         ADD_INT( Missiontime );
3812         ADD_DATA( paused );
3813         
3814         multi_io_send_to_all(data, packet_size);
3815 }
3816
3817 // process a game information update
3818 void process_game_info_packet( ubyte *data, header *hinfo )
3819 {
3820         int offset;
3821         fix mission_time;
3822         ubyte paused;
3823
3824         offset = HEADER_LENGTH;
3825
3826         // get the mission time -- we should examine our time and the time from the server.  If off by some delta
3827         // time, set our time to server time (should take ping time into account!!!)
3828         GET_DATA( mission_time );
3829         GET_DATA( paused );
3830         PACKET_SET_SIZE();      
3831 }
3832
3833 // send an ingame nak packet
3834 void send_ingame_nak(int state, net_player *p)
3835 {
3836         ubyte data[MAX_PACKET_SIZE];
3837         int packet_size = 0;
3838
3839         BUILD_HEADER(INGAME_NAK);
3840
3841         ADD_INT(state);
3842                 
3843         multi_io_send_reliable(p, data, packet_size);
3844 }
3845
3846 // process an ingame nak packet
3847 void process_ingame_nak(ubyte *data, header *hinfo)
3848 {
3849         int offset,state,pid;   
3850
3851         offset = HEADER_LENGTH;
3852         GET_INT(state); 
3853         PACKET_SET_SIZE();
3854         
3855    pid = find_player_id(hinfo->id);
3856         if(pid < 0){
3857                 return;
3858         }
3859         
3860         switch(state){
3861         case ACK_FILE_ACCEPTED :
3862                 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3863                 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3864                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);           
3865                 break;
3866         }       
3867 }
3868
3869 // send a packet telling players to end the mission
3870 void send_endgame_packet(net_player *pl)
3871 {
3872         ubyte data[MAX_PACKET_SIZE];
3873         int packet_size = 0;
3874         
3875         BUILD_HEADER(MISSION_END);      
3876
3877         // sending to a specific player?
3878         if(pl != NULL){
3879                 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3880                 multi_io_send_reliable(pl, data, packet_size);
3881                 return;
3882         }
3883
3884         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
3885                 // send all player stats here
3886                 multi_broadcast_stats(STATS_MISSION);           
3887
3888                 // if in dogfight mode, send all dogfight stats as well
3889                 ml_string("Before dogfight stats!");
3890                 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3891                         ml_string("Sending dogfight stats!");
3892
3893                         multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3894                 }
3895                 ml_string("After dogfight stats!");
3896
3897                 // tell everyone to leave the game              
3898                 multi_io_send_to_all_reliable(data, packet_size);
3899         } else {
3900                 multi_io_send_reliable(Net_player, data, packet_size);
3901         }
3902 }
3903
3904 // process a packet indicating we should end the current mission
3905 void process_endgame_packet(ubyte *data, header *hinfo)
3906 {
3907         int offset;     
3908         int player_num;
3909                         
3910         offset = HEADER_LENGTH;
3911         
3912         PACKET_SET_SIZE();
3913
3914         ml_string("Receiving endgame packet");
3915         
3916         // if I'm the server, I should evaluate whether the sender is authorized to end the game
3917         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3918                 // determine who this came from and make sure he is allowed to end the game             
3919                 player_num = find_player_id(hinfo->id);
3920                 SDL_assert(player_num != -1);
3921                 if(player_num < 0){
3922                         return;
3923                 }
3924
3925                 // if the player is allowed to end the mission
3926                 if(!multi_can_end_mission(&Net_players[player_num])){
3927                         return;
3928                 }               
3929
3930                 // act as if we hit alt+j locally 
3931                 multi_handle_end_mission_request();
3932         }
3933         // all clients process immediately
3934         else {
3935                 // ingame joiners should quit when they receive an endgame packet since the game is over
3936                 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3937                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3938                         return;
3939                 }
3940
3941                 // do any special processing for being in a state other than the gameplay state
3942                 multi_handle_state_special();
3943
3944                 // make sure we're not already in the debrief state
3945                 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3946                         multi_warpout_all_players();                    
3947                 }
3948         }       
3949 }
3950
3951 // send a position/orientation update for myself (if I'm an observer)
3952 void send_observer_update_packet()
3953 {
3954         ubyte data[MAX_PACKET_SIZE];
3955         int packet_size = 0;
3956         int ret;
3957         ushort target_sig;
3958         
3959         // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3960         // to send any update packets to anyone.
3961         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3962                 return;
3963         }
3964
3965         if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3966                 return;
3967         }
3968         
3969         BUILD_HEADER(OBSERVER_UPDATE);
3970
3971         ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3972         packet_size += ret;
3973         ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3974         packet_size += ret;
3975
3976         // add targeting infomation
3977         if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3978                 target_sig = Objects[Player_ai->target_objnum].net_signature;
3979         } else {
3980                 target_sig = 0;
3981         }
3982         ADD_USHORT(target_sig);
3983         
3984         multi_io_send(Net_player, data, packet_size);
3985 }
3986
3987 // process a position/orientation update from an observer
3988 void process_observer_update_packet(ubyte *data, header *hinfo)
3989 {
3990         int offset,ret;
3991         int obs_num;
3992         vector g_vec;
3993         matrix g_mat;
3994         physics_info bogus_pi;  
3995         ushort target_sig;
3996         object *target_obj;
3997         offset = HEADER_LENGTH;
3998
3999         obs_num = find_player_id(hinfo->id);
4000         
4001         memset(&bogus_pi,0,sizeof(physics_info));
4002         ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
4003         offset += ret;
4004         ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
4005         offset += ret;
4006
4007         // targeting information
4008         GET_USHORT(target_sig); 
4009         PACKET_SET_SIZE();      
4010
4011         if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
4012                 return;
4013         }
4014
4015         // set targeting info
4016         if(target_sig == 0){
4017                 Net_players[obs_num].s_info.target_objnum = -1;
4018         } else {
4019                 target_obj = multi_get_network_object(target_sig);
4020                 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4021         }
4022
4023         Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4024         Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4025         Net_players[obs_num].s_info.eye_pos = g_vec;
4026         Net_players[obs_num].s_info.eye_orient = g_mat;
4027 }
4028
4029 void send_netplayer_slot_packet()
4030 {
4031         ubyte data[MAX_PACKET_SIZE];
4032         int packet_size = 0, idx;
4033         ubyte stop;
4034
4035
4036         stop = 0xff;
4037    BUILD_HEADER(NETPLAYER_SLOTS_P);
4038    for(idx=0;idx<MAX_PLAYERS;idx++){
4039                 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4040                         ADD_DATA(stop);
4041                         ADD_SHORT(Net_players[idx].player_id);  
4042                         ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4043                         ADD_INT(Net_players[idx].p_info.ship_class);
4044                         ADD_INT(Net_players[idx].p_info.ship_index);                    
4045                 }
4046         }
4047         stop = 0x0;
4048         ADD_DATA(stop);
4049                 
4050         // standalone case or not
4051         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
4052                 multi_io_send_to_all_reliable(data, packet_size);
4053         } else {
4054                 multi_io_send_reliable(Net_player, data, packet_size);
4055         }
4056 }
4057
4058 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4059 {
4060         int offset;
4061         int player_num,ship_class,ship_index;
4062         ushort net_sig;
4063         object *objp;   
4064         ubyte stop;
4065         short player_id;
4066         
4067         offset = HEADER_LENGTH; 
4068
4069    // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4070         multi_untag_player_ships();
4071
4072         GET_DATA(stop);
4073         while(stop != 0x0){
4074                 GET_SHORT(player_id);
4075                 GET_USHORT(net_sig);
4076                 GET_INT(ship_class);
4077                 GET_INT(ship_index);
4078                 player_num = find_player_id(player_id);
4079                 if(player_num < 0){
4080                         nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4081                 } else {
4082                         // call the function in multiutil.cpp to set up the player object stuff
4083                         // being careful not to muck with the standalone object
4084                         if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4085                                 objp = multi_get_network_object(net_sig);
4086                                 SDL_assert(objp != NULL);
4087                                 multi_assign_player_ship( player_num, objp, ship_class );
4088                                 Net_players[player_num].p_info.ship_index = ship_index;
4089                                 objp->flags &= ~(OF_COULD_BE_PLAYER);
4090                                 objp->flags |= OF_PLAYER_SHIP;
4091                         }
4092                 }
4093                 GET_DATA(stop);
4094         }
4095         PACKET_SET_SIZE();
4096
4097         // standalone should forward the packet and wait for a response
4098         if(Game_mode & GM_STANDALONE_SERVER){
4099                 send_netplayer_slot_packet();
4100         } 
4101
4102         Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4103         send_netplayer_update_packet(); 
4104 }
4105
4106 // two functions to deal with ships changing their primary/secondary weapon status.  'what' indicates
4107 // if this change is a primary or secondary change.  new_bank is the new current primary/secondary
4108 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4109 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4110 {
4111         ubyte data[MAX_PACKET_SIZE], utmp;
4112         int packet_size;
4113
4114         BUILD_HEADER(SHIP_WSTATE_CHANGE);
4115         ADD_USHORT( Objects[shipp->objnum].net_signature );
4116         utmp = (ubyte)(what);
4117         ADD_DATA( utmp );
4118         utmp = (ubyte)(new_bank);
4119         ADD_DATA( utmp );
4120         utmp = (ubyte)(link_status);
4121         ADD_DATA( utmp );
4122
4123         // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB   
4124         multi_io_send_to_all_reliable(data, packet_size);
4125 }
4126
4127 void process_ship_weapon_change( ubyte *data, header *hinfo )
4128 {
4129         int offset;
4130         ushort signature;
4131         ubyte what, new_bank, link_status;
4132         object *objp;
4133         ship *shipp;
4134
4135         offset = HEADER_LENGTH;
4136         GET_USHORT( signature );
4137         GET_DATA( what );
4138         GET_DATA( new_bank );
4139         GET_DATA( link_status );
4140         PACKET_SET_SIZE();
4141
4142         objp = multi_get_network_object( signature );
4143         if ( objp == NULL ) {
4144                 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4145                 return;
4146         }
4147         // SDL_assert( objp->type == OBJ_SHIP );
4148         if(objp->type != OBJ_SHIP){
4149                 return;
4150         }
4151
4152         // if this is my data, do nothing since I already have my own data
4153         if ( objp == Player_obj ){
4154                 return;
4155         }
4156
4157         // now, get the ship and set the new bank and link modes based on the 'what' value
4158         shipp = &Ships[objp->instance];
4159         if ( what == MULTI_PRIMARY_CHANGED ) {
4160                 shipp->weapons.current_primary_bank = new_bank;
4161                 if ( link_status ){
4162                         shipp->flags |= SF_PRIMARY_LINKED;
4163                 } else {
4164                         shipp->flags &= ~SF_PRIMARY_LINKED;
4165                 }
4166         } else {
4167                 shipp->weapons.current_secondary_bank = new_bank;
4168                 if ( link_status ){
4169                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4170                 } else {
4171                         shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4172                 }
4173         }
4174 }
4175         
4176         // ship status change procedure
4177 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4178 //                server critical.
4179 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets 
4180 //                for added redundancy.
4181 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4182 //                ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4183 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS) 
4184 //                back to the client. Also sends multiple times for redundancy
4185 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4186 //                and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4187 //                on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4188
4189 #define SHIP_STATUS_REPEAT 2
4190 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4191 {
4192         int idx, temp;
4193         ubyte data[MAX_PACKET_SIZE];
4194         int packet_size = 0;
4195
4196         if(pl == NULL){
4197                 return;
4198         }
4199
4200         BUILD_HEADER(SHIP_STATUS_CHANGE);
4201         ADD_INT(id);
4202         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4203                 temp = bi->status[idx];
4204                 ADD_INT(temp);
4205         }
4206         
4207    // server should send reliably (response packet)
4208         if(MULTIPLAYER_MASTER){         
4209                 multi_io_send_reliable(pl, data, packet_size);
4210         } else {
4211                 multi_io_send(pl, data, packet_size);
4212         }
4213 }
4214
4215 void process_ship_status_packet(ubyte *data, header *hinfo)
4216 {
4217    int idx;
4218         int offset;
4219         int player_num,unique_id;
4220         button_info bi;
4221         int i_tmp;
4222         
4223         offset = HEADER_LENGTH;
4224
4225         // zero out the button info structure for good measure
4226         memset(&bi,0,sizeof(button_info));
4227         
4228         // read the button-info
4229         GET_INT(unique_id);     
4230                 
4231         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4232                 GET_INT(i_tmp);
4233                 bi.status[idx] = i_tmp;
4234         }
4235
4236         PACKET_SET_SIZE();
4237
4238    // this will be handled differently client and server side. Duh.
4239         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){                  // SERVER SIDE
4240                 // find which net-player has sent us butotn information         
4241       player_num = find_player_id(hinfo->id);
4242                 SDL_assert(player_num >= 0);
4243                 if(player_num < 0){
4244                         return;
4245                 }
4246
4247                 // don't process critical button information for observers
4248                 // its a new button_info for this guy. apply and ack
4249                 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){        
4250                         // mark that he's pressed this button
4251          // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4252                         
4253                         // send a return packet
4254          send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4255                         
4256                         // apply the button presses to his ship as normal
4257                         multi_apply_ship_status(&Net_players[player_num], &bi, 0);         
4258                 } 
4259                 // else ignore it as a repeat from the same guy
4260         } else {                                                         // CLIENT SIDE
4261                 // this is the return from the server, so we should now apply them locally
4262       // if(lookup_ship_status(Net_player,unique_id,1)){
4263                 multi_apply_ship_status(Net_player, &bi, 1);
4264                 // }
4265         }       
4266 }
4267
4268 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4269 // for clients.  Left all details to this function instead of higher level messaging
4270 // code
4271 void send_player_order_packet(int type, int index, int cmd)
4272 {
4273         ubyte data[MAX_PACKET_SIZE];
4274         ubyte val;
4275         ushort target_signature;
4276         char t_subsys;
4277         int packet_size = 0;
4278
4279         BUILD_HEADER(PLAYER_ORDER_PACKET);
4280
4281         val = (ubyte)type;
4282         ADD_DATA(val);         // ship order or wing order, or message all fighters
4283
4284         // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4285         if ( val != SQUAD_MSG_ALL ){
4286                 ADD_INT(index);  // net signature of target ship
4287         }
4288
4289         ADD_INT(cmd);         // the command itself
4290
4291         // add target data.
4292         target_signature = 0;
4293         if ( Player_ai->target_objnum != -1 ){
4294                 target_signature = Objects[Player_ai->target_objnum].net_signature;
4295         }
4296
4297         ADD_USHORT( target_signature );
4298
4299         t_subsys = -1;
4300         if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4301                 int s_index;
4302
4303                 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4304                 SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
4305                 t_subsys = (char)s_index;
4306         }
4307         ADD_DATA(t_subsys);
4308    
4309         multi_io_send_reliable(Net_player, data, packet_size);
4310 }
4311
4312 // brief explanation :
4313 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4314 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4315 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4316 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4317 void process_player_order_packet(ubyte *data, header *hinfo)
4318 {
4319         int offset, player_num, command, index = 0, tobjnum_save;       
4320         ushort target_signature;
4321         char t_subsys, type;
4322         object *objp, *target_objp;
4323         ai_info *aip;
4324         ship *shipp;
4325         ship_subsys *tsubsys_save, *targeted_subsys;
4326
4327         SDL_assert(MULTIPLAYER_MASTER);
4328
4329         // packet values - its easier to read all of these in first
4330                 
4331         offset = HEADER_LENGTH;
4332         
4333         GET_DATA( type );
4334         if ( type != SQUAD_MSG_ALL ){
4335                 GET_INT( index );
4336         }
4337
4338         GET_INT( command );
4339         GET_USHORT( target_signature );
4340         GET_DATA( t_subsys );
4341
4342         PACKET_SET_SIZE();      
4343
4344         player_num = find_player_id(hinfo->id);
4345         if(player_num == -1){
4346                 nprintf(("Network","Received player order packet from unknown player\n"));              
4347                 return;
4348         }       
4349
4350         objp = &Objects[Net_players[player_num].player->objnum];
4351         if ( objp->type != OBJ_SHIP ) {
4352                 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4353                 return;
4354         }
4355
4356         // HACK HACK HACK HACK HACK HACK
4357         // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4358         // the data is BOGUS.  All people should be able to to these things as well.
4359         if(command == REARM_REPAIR_ME_ITEM){ 
4360                 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);          
4361                 return;
4362         } else if(command == ABORT_REARM_REPAIR_ITEM){
4363                 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);            
4364                 return;
4365         }
4366
4367         // if this player is not allowed to do messaging, quit here
4368         if( !multi_can_message(&Net_players[player_num]) ){
4369                 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4370                 return;
4371         }
4372
4373         // check to see if the type of order is a reinforcement call.  If so, intercept it, and
4374         // then call them in.
4375         if ( type == SQUAD_MSG_REINFORCEMENT ) {
4376                 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4377                 hud_squadmsg_call_reinforcement(index, player_num);
4378                 return;
4379         }
4380
4381         // set the player's ai information here
4382         shipp = &Ships[objp->instance];
4383         aip = &Ai_info[shipp->ai_index];
4384
4385         // get the target objnum and targeted subsystem.  Quick out if we don't have an object to act on.
4386         target_objp = multi_get_network_object( target_signature );
4387         if ( target_objp == NULL ) {
4388                 return;
4389         }
4390
4391         targeted_subsys = NULL;
4392         if ( t_subsys != -1 ) {
4393                 SDL_assert( target_objp != NULL );
4394                 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4395         }
4396
4397         // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4398         // here
4399         tobjnum_save = aip->target_objnum;
4400         tsubsys_save = aip->targeted_subsys;
4401
4402         if ( target_objp ) {
4403                 aip->target_objnum = OBJ_INDEX(target_objp);
4404         } else {
4405                 aip->target_objnum = -1;
4406         }
4407
4408         aip->targeted_subsys = targeted_subsys;
4409
4410         if ( type == SQUAD_MSG_SHIP ) {
4411                 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4412         } else if ( type == SQUAD_MSG_WING ) {
4413                 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4414         } else if ( type == SQUAD_MSG_ALL ) {
4415                 hud_squadmsg_send_to_all_fighters( command, player_num );
4416         }
4417
4418         SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); //      make sure not targeting self
4419         aip->target_objnum = tobjnum_save;
4420         aip->targeted_subsys = tsubsys_save;
4421 }
4422
4423 // FILE SIGNATURE stuff :
4424 // there are 2 cases for file signature sending which are handled very differently
4425 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4426 //     posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked). 
4427 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4428 //     the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4429 //     would have to keep track of up to potentially 14 other ack handles  (ouch).
4430 void send_file_sig_packet(ushort sum_sig,int length_sig)
4431 {
4432         ubyte data[MAX_PACKET_SIZE];
4433         int packet_size = 0;
4434
4435         BUILD_HEADER(FILE_SIG_INFO);
4436         ADD_USHORT(sum_sig);
4437         ADD_INT(length_sig);
4438                 
4439         multi_io_send_reliable(Net_player, data, packet_size);
4440 }
4441
4442 void process_file_sig_packet(ubyte *data, header *hinfo)
4443 {
4444         int offset;
4445         int length_sig;
4446         ushort sum_sig; 
4447         offset = HEADER_LENGTH;
4448
4449         // should only be received on the server-side
4450         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); 
4451         
4452         GET_USHORT(sum_sig);
4453         GET_INT(length_sig);
4454         PACKET_SET_SIZE();
4455         server_verify_filesig(hinfo->id, sum_sig, length_sig);  
4456 }
4457
4458 void send_file_sig_request(char *file_name)
4459 {
4460         ubyte data[MAX_PACKET_SIZE];
4461         int packet_size = 0;
4462
4463         BUILD_HEADER(FILE_SIG_REQUEST);
4464         ADD_STRING(file_name);
4465
4466         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4467                 
4468         multi_io_send_to_all_reliable(data, packet_size);
4469 }
4470
4471 void process_file_sig_request(ubyte *data, header *hinfo)
4472 {               
4473         int offset = HEADER_LENGTH;     
4474
4475         // get the mission name
4476         GET_STRING(Netgame.mission_name);        
4477         PACKET_SET_SIZE();      
4478
4479         // set the current mission filename
4480         SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4481
4482         // get the checksum
4483         multi_get_mission_checksum(Game_current_mission_filename);      
4484
4485         if(!multi_endgame_ending()){    
4486                 // reply to the server
4487                 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4488         }
4489 }
4490
4491 // functions to deal with subsystems getting whacked
4492 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4493 {
4494         ubyte data[MAX_PACKET_SIZE];
4495         int packet_size;
4496         ubyte uindex;
4497         vector tmp, local_hitpos;
4498         object *objp;
4499
4500         SDL_assert ( index < UCHAR_MAX );
4501         uindex = (ubyte)(index);
4502
4503         objp = &Objects[shipp->objnum];
4504
4505         vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4506         vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4507
4508         BUILD_HEADER(SUBSYSTEM_DESTROYED);
4509         ADD_USHORT( Objects[shipp->objnum].net_signature );
4510         ADD_DATA( uindex );
4511 //      ADD_DATA( local_hitpos );
4512         add_vector_data(data, &packet_size, local_hitpos);
4513         
4514         multi_io_send_to_all_reliable(data, packet_size);
4515 }
4516
4517 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4518 {
4519         int offset;
4520         ushort signature;
4521         ubyte uindex;
4522         object *objp;
4523         vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4524
4525         offset = HEADER_LENGTH;
4526
4527         GET_USHORT( signature );
4528         GET_DATA( uindex );
4529 //      GET_DATA( local_hit_pos );
4530         get_vector_data(data, &offset, local_hit_pos);
4531
4532         // get the network object.  process it if we find it.
4533         objp = multi_get_network_object( signature );
4534         if ( objp != NULL ) {
4535                 ship *shipp;
4536                 ship_subsys *subsysp;
4537
4538                 // be sure we have a ship!!!
4539                 // SDL_assert ( objp->type == OBJ_SHIP );
4540                 if(objp->type != OBJ_SHIP){
4541                         PACKET_SET_SIZE();
4542                         return;
4543                 }
4544
4545                 shipp = &Ships[objp->instance];
4546
4547                 // call to get the pointer to the subsystem we should be working on
4548                 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4549                 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4550                 vm_vec_add2( &world_hit_pos, &objp->pos );
4551
4552                 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4553                 if ( objp == Player_obj ) {
4554                         hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4555                 }
4556         }
4557
4558         PACKET_SET_SIZE();
4559 }
4560
4561
4562 // packet to tell clients cargo of a ship was revealed to all
4563 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4564 {
4565         ubyte data[MAX_PACKET_SIZE], uindex;
4566         int packet_size;
4567
4568         SDL_assert ( index < UCHAR_MAX );
4569         uindex = (ubyte)(index);
4570
4571         // build the header and add the data
4572         BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4573         ADD_USHORT( Objects[shipp->objnum].net_signature );
4574         ADD_DATA( uindex );
4575
4576         // server sends to all players
4577         if(MULTIPLAYER_MASTER){         
4578                 multi_io_send_to_all_reliable(data, packet_size);
4579         } 
4580         // clients just send to the server
4581         else {
4582                 multi_io_send_reliable(Net_player, data, packet_size);
4583         }
4584 }
4585
4586 // process a subsystem cargo revealed packet
4587 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4588 {
4589         int offset;
4590         ushort signature;
4591         ubyte uindex;
4592         object *objp;
4593         ship *shipp;
4594         ship_subsys *subsysp;
4595
4596         offset = HEADER_LENGTH;
4597         GET_USHORT( signature );
4598         GET_DATA( uindex );
4599         PACKET_SET_SIZE();
4600
4601         // get a ship pointer and call the ship function to reveal the cargo
4602         objp = multi_get_network_object( signature );
4603         if ( objp == NULL ) {
4604                 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4605                 return;
4606         }
4607
4608         // SDL_assert( objp->type == OBJ_SHIP );
4609         if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4610                 return;
4611         }
4612
4613         shipp = &Ships[objp->instance];
4614
4615         // call to get the pointer to the subsystem we should be working on
4616         subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4617         if (subsysp == NULL) {
4618                 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4619                 return;
4620         }
4621
4622         // this will take care of re-routing to all other clients
4623         void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4624         ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4625
4626         // server should rebroadcast
4627         if(MULTIPLAYER_MASTER){
4628                 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4629         }
4630 }
4631
4632 void send_netplayer_load_packet(net_player *pl)
4633 {
4634         ubyte data[MAX_PACKET_SIZE];
4635         int packet_size = 0;
4636
4637         BUILD_HEADER(LOAD_MISSION_NOW);
4638         ADD_STRING(Netgame.mission_name);
4639
4640         if(pl == NULL){         
4641                 multi_io_send_to_all_reliable(data, packet_size);
4642         } else {
4643                 multi_io_send_reliable(pl, data, packet_size);
4644         }
4645 }
4646
4647 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4648 {
4649         char str[100];
4650         int offset = HEADER_LENGTH;     
4651
4652         GET_STRING(str);
4653         PACKET_SET_SIZE();
4654
4655         SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4656         SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4657         if(!Multi_mission_loaded){
4658
4659                 // MWA 2/3/98 -- ingame join changes!!!
4660                 // everyone can go through the same mission loading path here!!!!
4661                 nprintf(("Network","Loading mission..."));
4662
4663                 // notify everyone that I'm loading the mission
4664                 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4665                 send_netplayer_update_packet();         
4666
4667                 // do the load itself
4668                 game_start_mission();           
4669
4670                 // ingame joiners need to "untag" all player ships as could_be_players.  The ingame joining
4671                 // code will remark the correct player ships
4672                 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4673                         multi_untag_player_ships();
4674                 }
4675
4676                 Net_player->flags |= NETINFO_FLAG_MISSION_OK;           
4677                 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4678                 send_netplayer_update_packet();
4679
4680                 Multi_mission_loaded = 1;
4681                 nprintf(("Network","Finished loading mission\n"));              
4682         }       
4683 }
4684
4685 void send_jump_into_mission_packet(net_player *pl)
4686 {
4687         ubyte data[MAX_PACKET_SIZE];
4688         int packet_size = 0;
4689
4690         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4691
4692         BUILD_HEADER(JUMP_INTO_GAME);
4693
4694         // ingame joiners will get special data.  We need to tell them about the state of the mission, like paused,
4695         // and possible other things.
4696         if ( pl != NULL ) {
4697                 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4698                         ADD_INT(Netgame.game_state);
4699                 }
4700         }
4701         
4702         // broadcast
4703         if(pl == NULL){         
4704                 multi_io_send_to_all_reliable(data, packet_size);
4705         }
4706         // send to a specific player
4707         else {
4708                 multi_io_send_reliable(pl, data, packet_size);
4709         }
4710 }
4711
4712 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4713 {
4714         int offset = HEADER_LENGTH;
4715         int state = 0;
4716
4717         // if I am ingame joining, there should be extra data.  For now, this data is the netgame state.
4718         // the game could be paused, so ingame joiner needs to deal with it.
4719         if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4720                 GET_INT( state );
4721                 Netgame.game_state = state;
4722         }
4723
4724         PACKET_SET_SIZE();      
4725
4726         // handle any special processing for being in a weird substate
4727         multi_handle_state_special();
4728
4729         // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4730         if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4731                 if(Net_player->flags & NETINFO_FLAG_OBSERVER){                                          
4732                         multi_ingame_observer_finish();                 
4733                 } else {
4734                         gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4735                         Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4736                         send_netplayer_update_packet();
4737                 }
4738         } else {
4739                 // start the mission!!
4740                 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4741                         Netgame.game_state = NETGAME_STATE_IN_MISSION;
4742                         gameseq_post_event(GS_EVENT_ENTER_GAME);
4743                         Net_player->state = NETPLAYER_STATE_IN_MISSION;
4744                         send_netplayer_update_packet();
4745                 }               
4746         }
4747
4748         extern time_t Player_multi_died_check;
4749         Player_multi_died_check = -1;
4750
4751         // recalc all object pairs now  
4752         extern void obj_reset_all_collisions();
4753         obj_reset_all_collisions();
4754
4755         // display some cool text
4756         multi_common_add_text(XSTR("Received mission start\n",720),1);
4757
4758         // NETLOG
4759         ml_string(NOX("Client received mission start from server - entering mission"));
4760 }
4761
4762 //XSTR:OFF
4763
4764 const char *repair_text[] = {
4765         "unknown",
4766         "REPAIR_INFO_BEGIN",
4767         "REPAIR_INFO_END",
4768         "REPAIR_INFO_UPDATE",
4769         "REPAIR_INFO_QUEUE",
4770         "REPAIR_INFO_ABORT",
4771         "REPAIR_INFO_BROKEN",
4772         "REPAIR_INFO_WARP_ADD",
4773         "REPAIR_INFO_WARP_REMOVE",
4774         "REPAIR_INFO_ONWAY",
4775         "REPAIR_INFO_KILLED",
4776         "REPAIR_INFO_COMPLETE",
4777 };
4778
4779 //XSTR:ON
4780
4781 // the following two routines deal with updating and sending information regarding players
4782 // rearming and repairing during the game.  The process function calls the routines to deal with
4783 // setting flags and other interesting things.
4784 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4785 {
4786         int packet_size = 0;
4787         ushort repaired_signature, repair_signature;
4788         ubyte data[MAX_PACKET_SIZE];
4789         ubyte cd;
4790
4791         // use the network signature of the destination object if there is one, -1 otherwise.
4792         // client will piece it all together
4793         repaired_signature = repaired_objp->net_signature;
4794
4795         // the repair ship may be NULL here since it might have been destroyed
4796         repair_signature = 0;
4797         if ( repair_objp ){
4798                 repair_signature = repair_objp->net_signature;
4799         }
4800
4801         BUILD_HEADER(CLIENT_REPAIR_INFO);
4802         cd = (ubyte)code;
4803         ADD_DATA(cd);
4804         ADD_USHORT( repaired_signature );
4805         ADD_USHORT( repair_signature );
4806         
4807         multi_io_send_to_all_reliable(data, packet_size);
4808
4809         nprintf(("Network", "Repair: %s sent to all players (%s/%s)\n", repair_text[cd], Ships[repaired_objp->instance].ship_name, (repair_objp==NULL)?"<none>":Ships[repair_objp->instance].ship_name));
4810 }
4811
4812 void process_repair_info_packet(ubyte *data, header *hinfo)
4813 {
4814         int offset = HEADER_LENGTH;
4815         ushort repaired_signature, repair_signature;
4816         object *repaired_objp, *repair_objp;
4817         ubyte code;
4818
4819         GET_DATA(code);
4820         GET_USHORT( repaired_signature );
4821         GET_USHORT( repair_signature );
4822         PACKET_SET_SIZE();
4823
4824         repaired_objp = multi_get_network_object( repaired_signature );
4825         repair_objp = multi_get_network_object( repair_signature );
4826
4827         nprintf(("Network", "Repair: %s received (%s/%s)\n", repair_text[code], (repaired_objp==NULL)?"<None>":Ships[repaired_objp->instance].ship_name, (repair_objp==NULL)?"<None>":Ships[repair_objp->instance].ship_name));
4828
4829         if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4830                 return;
4831         }
4832
4833         if ( repaired_objp == NULL ) {
4834                 Int3();                         // Sandeep says this is bad bad bad.  No ship to repair.
4835                 return;
4836         }
4837
4838         // the hope is to simply call the routine in the ai code to set/unset flags
4839         // based on the code value and everything else should happen..I hope....
4840         if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4841
4842                 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4843
4844                 // set the dock flags when repair begins.  Prevents problem in lagging docking
4845                 // packet.  Also set any other flags/modes which need to be set to prevent Asserts.
4846                 // bleah.
4847                 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4848                         ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4849                         Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4850                 }
4851
4852                 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4853                 // as being done.
4854                 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4855                         ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4856                 }
4857         } else {
4858                 if ( code == REPAIR_INFO_WARP_ADD ){
4859                         mission_warp_in_support_ship( repaired_objp );
4860                 } else {
4861                         mission_remove_scheduled_repair( repaired_objp );
4862                 }
4863         }
4864 }
4865
4866 // sends information updating clients on certain AI information that clients will
4867 // need to know about to keep HUD information up to date.  objp is the object that we
4868 // are updating, and what is the type of stuff that we are updating.
4869 void send_ai_info_update_packet( object *objp, char what )
4870 {
4871         int packet_size;
4872         ushort other_signature;
4873         ubyte data[MAX_PACKET_SIZE];
4874         ai_info *aip;
4875         ubyte dock_index, dockee_index;
4876
4877         // SDL_assert( objp->type == OBJ_SHIP );
4878         if(objp->type != OBJ_SHIP){
4879                 return;
4880         }
4881         aip = &Ai_info[Ships[objp->instance].ai_index];
4882
4883         // do an out here
4884         if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4885                 return;
4886
4887         BUILD_HEADER( AI_INFO_UPDATE );
4888         ADD_USHORT( objp->net_signature );
4889         ADD_DATA( what );
4890
4891         // depending on the "what" value, we will send different information
4892         // to the clients
4893         switch( what ) {
4894
4895         case AI_UPDATE_DOCK:
4896                 // for docking ships, add the signature of the ship that we are docking with.
4897                 SDL_assert( aip->dock_objnum != -1 );
4898                 other_signature = Objects[aip->dock_objnum].net_signature;
4899                 dock_index = (ubyte)(aip->dock_index);
4900                 dockee_index = (ubyte)(aip->dockee_index);
4901                 ADD_USHORT( other_signature );
4902                 ADD_DATA(dock_index);
4903                 ADD_DATA(dockee_index);
4904                 break;
4905
4906         case AI_UPDATE_UNDOCK:
4907                 // for undocking ships, check the dock_objnum since we might or might not have it
4908                 // depending on whether or not a ship was destroyed while we were docked.
4909                 other_signature = 0;
4910                 if ( aip->dock_objnum != -1 )
4911                         other_signature = Objects[aip->dock_objnum].net_signature;
4912                 ADD_USHORT( other_signature );
4913
4914                 break;
4915
4916         case AI_UPDATE_ORDERS: {
4917                 int shipnum;
4918
4919                 // for orders, we only need to send a little bit of information here.  Be sure that the
4920                 // first order for this ship is active
4921                 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4922                 ADD_INT( aip->goals[0].ai_mode );
4923                 ADD_INT( aip->goals[0].ai_submode );
4924                 shipnum = -1;
4925                 if ( aip->goals[0].ship_name != NULL )
4926                         shipnum = ship_name_lookup( aip->goals[0].ship_name );
4927
4928                 // the ship_name member of the goals structure may or may not contain a real shipname.  If we don't
4929                 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4930                 if ( shipnum != -1 ) {
4931                         SDL_assert( Ships[shipnum].objnum != -1 );
4932                         other_signature = Objects[Ships[shipnum].objnum].net_signature;
4933                 } else
4934                         other_signature = 0;
4935                 
4936                 ADD_USHORT( other_signature );
4937
4938                 // for docking, add the dock and dockee index
4939                 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4940                         SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4941                         SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4942                         dock_index = (ubyte)aip->goals[0].docker.index;
4943                         dockee_index = (ubyte)aip->goals[0].dockee.index;
4944                         ADD_DATA( dock_index );
4945                         ADD_DATA( dockee_index );
4946                 }
4947                 break;
4948                 }
4949
4950         default:
4951                 Int3();
4952         }
4953         
4954         multi_rate_add(1, "aiu", packet_size);
4955         multi_io_send_to_all_reliable(data, packet_size);
4956 }
4957
4958 // process an ai_info update packet.  Docking/undocking, ai orders, etc. are taken care of here.  This
4959 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4960 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4961 {
4962         int offset = HEADER_LENGTH;
4963         int mode, submode;
4964         ushort net_signature, other_net_signature;
4965         object *objp, *other_objp;
4966         ai_info *aip;
4967         char code;
4968         ubyte dock_index = 0, dockee_index = 0;
4969
4970         GET_USHORT( net_signature );            // signature of the object that we are dealing with.
4971         GET_DATA( code );                                       // code of what we are doing.
4972         objp = multi_get_network_object( net_signature );
4973         if ( !objp ) {
4974                 nprintf(("Network", "Couldn't find object for ai update\n"));
4975         }
4976
4977         switch( code ) {
4978         case AI_UPDATE_DOCK:
4979                 GET_USHORT( other_net_signature );
4980                 GET_DATA( dock_index );
4981                 GET_DATA( dockee_index );
4982                 other_objp = multi_get_network_object( other_net_signature );
4983                 if ( !other_objp ) {
4984                         nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4985                 }
4986                 
4987                 // if we don't have an object to work with, break out of loop
4988                 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4989                         break;
4990                 }
4991
4992                 SDL_assert( other_objp->type == OBJ_SHIP );
4993                 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4994                 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4995
4996                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4997                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4998
4999                 ai_do_objects_docked_stuff( objp, other_objp );
5000                 break;
5001
5002         case AI_UPDATE_UNDOCK:
5003                 GET_USHORT( other_net_signature );
5004                 other_objp = multi_get_network_object( other_net_signature );
5005                 
5006                 // if we don't have an object to work with, break out of loop
5007                 if ( !objp )
5008                         break;
5009
5010                 ai_do_objects_undocked_stuff( objp, other_objp );
5011                 break;
5012
5013         case AI_UPDATE_ORDERS:
5014                 GET_INT( mode );
5015                 GET_INT( submode );
5016                 GET_USHORT( other_net_signature );
5017                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5018                         GET_DATA(dock_index);
5019                         GET_DATA(dockee_index);
5020                 }
5021
5022                 // be sure that we have a ship object!!!
5023                 if ( !objp || (objp->type != OBJ_SHIP) )
5024                         break;
5025
5026                 // set up the information in the first goal element of the object in question
5027                 aip = &Ai_info[Ships[objp->instance].ai_index];
5028                 aip->active_goal = 0;
5029                 aip->goals[0].ai_mode = mode;
5030                 aip->goals[0].ai_submode = submode;
5031
5032                 // for docking, add the dock and dockee index
5033                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5034                         aip->dock_index = dock_index;
5035                         aip->dockee_index = dockee_index;
5036                 }
5037
5038                 // get a shipname if we can.
5039                 other_objp = multi_get_network_object( other_net_signature );
5040                 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5041                         // get a pointer to the shipname in question.  Use the ship_name value in the
5042                         // ship.  We are only using this for HUD display, so I think that using this
5043                         // method will be fine.
5044                         aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5045
5046                         // special case for destroy subsystem -- get the ai_info pointer to our target ship
5047                         // so that we can properly set up what subsystem this ship is attacking.
5048                         if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5049                                 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5050
5051                         // if docking -- set the dock index and dockee index of this other ship
5052                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5053                                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5054                                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5055                         }
5056                 }
5057
5058                 break;
5059
5060         default:
5061                 Int3();         // this Int3() should be temporary
5062                 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5063                 break;
5064         }
5065         PACKET_SET_SIZE();
5066 }
5067
5068 // tell the standalone to move into the MISSION_SYNC_STATE
5069 void send_mission_sync_packet(int mode,int start_campaign)
5070 {
5071         ubyte data[MAX_PACKET_SIZE],is_campaign;
5072         int packet_size = 0;
5073
5074         SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5075
5076         // build the header and add the sync mode (pre or post briefing)
5077         BUILD_HEADER(MISSION_SYNC_DATA);
5078         ADD_INT(mode);
5079
5080         // if this is a campaign game
5081         if(mode == MULTI_SYNC_PRE_BRIEFING){
5082                 if(Game_mode & GM_CAMPAIGN_MODE){
5083                         // add a byte indicating campaign mode
5084                         is_campaign = 1;
5085                         ADD_DATA(is_campaign);
5086
5087                         // add a byte indicating if we should be starting a campaign or continuing it
5088                         is_campaign = (ubyte)start_campaign;
5089                         ADD_DATA(is_campaign);
5090
5091                         // add the campaign filename
5092                         ADD_STRING(Netgame.campaign_name);
5093                 }
5094                 // otherwise if this is a single mission 
5095                 else {
5096                         // add a byte indicating single mission mode
5097                         is_campaign = 0;
5098                         ADD_DATA(is_campaign);
5099
5100                         // add the mission filename
5101                         ADD_STRING(Game_current_mission_filename);
5102                 }
5103         }       
5104         multi_io_send_reliable(Net_player, data, packet_size);
5105 }
5106
5107 // move into the MISSION_SYNC state when this is received
5108 // this packet is sent only from a game host to a standalone
5109 void process_mission_sync_packet(ubyte *data, header *hinfo)
5110 {
5111         int mode;
5112         ubyte campaign_flag;
5113         int offset = HEADER_LENGTH;
5114
5115         SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5116
5117         // if this is a team vs team situation, lock the players send a final team update
5118         if(Netgame.type_flags & NG_TYPE_TEAM){
5119                 multi_team_host_lock_all();
5120                 multi_team_send_update();
5121         }
5122
5123         // get the sync mode (pre or post briefing)
5124         GET_INT(mode);
5125
5126         if(mode == MULTI_SYNC_PRE_BRIEFING){
5127                 // get the flag indicating if this is a single mission or a campaign mode
5128                 GET_DATA(campaign_flag);
5129                 if(campaign_flag){
5130                         // get the flag indicating whether we should be starting a new campaign
5131                         GET_DATA(campaign_flag);
5132
5133                         // get the campaign filename
5134                         GET_STRING(Netgame.campaign_name);
5135
5136                         // either start a new campaign or continue on to the next mission in the current campaign
5137                         if(campaign_flag){
5138                                 multi_campaign_start(Netgame.campaign_name);
5139                         } else {
5140                                 multi_campaign_next_mission();
5141                         }
5142                 } else {
5143                         // make sure we remove the campaign mode flag
5144                         Game_mode &= ~(GM_CAMPAIGN_MODE);
5145
5146                         // get the single mission filename
5147                         GET_STRING(Game_current_mission_filename);
5148                         SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5149                 }
5150         }
5151         PACKET_SET_SIZE();
5152
5153         // set the correct mode and m ove into the state
5154         Multi_sync_mode = mode;
5155         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5156 }
5157
5158 // tell a player to merge his mission stats into his alltime stats
5159 void send_store_stats_packet(int accept)
5160 {
5161         ubyte data[10],val;
5162         int packet_size = 0;
5163
5164         BUILD_HEADER(STORE_MISSION_STATS);
5165
5166         // add whether we're accepting or tossing
5167         val = (ubyte)accept;
5168         ADD_DATA(val);
5169
5170         // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5171         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5172                 multi_io_send_to_all_reliable(data, packet_size);
5173         } else {
5174                 multi_io_send_reliable(Net_player, data, packet_size);
5175         }
5176 }
5177
5178 void process_store_stats_packet(ubyte *data, header *hinfo)
5179 {
5180         int offset = HEADER_LENGTH;
5181         ubyte accept;
5182
5183         GET_DATA(accept);
5184         PACKET_SET_SIZE();
5185
5186         // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5187         if(Game_mode & GM_STANDALONE_SERVER){
5188                 // rebroadcast the packet to all others in the game
5189                 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));                             
5190                 multi_io_send_to_all_reliable(data, offset);
5191         } else {                        
5192                 if(accept){
5193                         // all players should mark the stats as being accepted in the debriefing
5194                         multi_debrief_stats_accept();                   
5195                 } else {
5196                         // all players should mark the stats as being "tossed" in the debriefing
5197                         multi_debrief_stats_toss();                     
5198                 }                       
5199         }
5200 }
5201
5202 void send_debris_update_packet(object *objp,int code)
5203 {
5204         ubyte data[MAX_PACKET_SIZE];
5205         ubyte val;
5206         int packet_size = 0;
5207
5208         BUILD_HEADER(DEBRIS_UPDATE);    
5209         ADD_USHORT(objp->net_signature);
5210         val = (ubyte) code;
5211         ADD_DATA(val);
5212         
5213         // add any extra relevant data
5214         switch(code){
5215         case DEBRIS_UPDATE_UPDATE:
5216         //      ADD_DATA(objp->pos);                                            // add position
5217                 add_vector_data(data, &packet_size, objp->pos);
5218                 ADD_ORIENT(objp->orient);                               // add orientation
5219         //      ADD_DATA(objp->phys_info.vel);          // add velocity
5220                 add_vector_data(data, &packet_size, objp->phys_info.vel);
5221         //      ADD_DATA(objp->phys_info.rotvel);       // add rotational velocity
5222                 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5223                 break;
5224         }       
5225         multi_io_send_to_all(data, packet_size);
5226 }
5227
5228 void process_debris_update_packet(ubyte *data, header *hinfo)
5229 {
5230         ushort net_sig;
5231         ubyte code;
5232         object bogus_object;
5233         object *objp;
5234         int offset = HEADER_LENGTH;
5235         
5236         GET_USHORT(net_sig);
5237         GET_DATA(code);
5238
5239         objp = NULL;
5240         objp = multi_get_network_object(net_sig);
5241         if(objp == NULL){
5242                 objp = &bogus_object;
5243         }
5244
5245         switch((int)code){
5246         // update the object
5247         case DEBRIS_UPDATE_UPDATE:
5248                 //GET_DATA(objp->pos);
5249         get_vector_data( data, &offset, objp->pos );
5250                 
5251                 GET_ORIENT(objp->orient);
5252                 GET_DATA(objp->phys_info.vel);
5253                 GET_DATA(objp->phys_info.rotvel);
5254                 break;
5255         // simply remove it (no explosion)
5256         case DEBRIS_UPDATE_REMOVE:
5257                 if(objp != &bogus_object){
5258                         SDL_assert(objp->type == OBJ_DEBRIS);
5259                         obj_delete(OBJ_INDEX(objp));
5260                 }
5261                 break;
5262         // blow it up
5263         case DEBRIS_UPDATE_NUKE:
5264                 if(objp != &bogus_object)
5265                         debris_hit(objp,NULL,&objp->pos,1000000.0f);
5266                 break;
5267         }
5268
5269         PACKET_SET_SIZE();
5270 }
5271
5272 // ALAN begin
5273 void send_wss_request_packet(short player_id, int from_slot, int from_index, int to_slot, int to_index, int wl_ship_slot, int ship_class, int mode, net_player *p)
5274 {
5275         ubyte data[MAX_PACKET_SIZE];
5276
5277         int packet_size = 0;
5278
5279         BUILD_HEADER(WSS_REQUEST_PACKET);
5280         
5281         // add the request information
5282         ADD_SHORT(player_id);
5283         ADD_INT(from_slot);
5284         ADD_INT(from_index);
5285         ADD_INT(to_slot);
5286         ADD_INT(to_index);
5287         ADD_INT(wl_ship_slot);  // only used in weapons loadout
5288         ADD_INT(ship_class);
5289         ADD_INT(mode);
5290
5291         // a standard request
5292         if(p == NULL){          
5293                 multi_io_send_reliable(Net_player, data, packet_size);
5294         } 
5295         // being routed through the standalone to the host of the game
5296         else {
5297                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);                   
5298                 multi_io_send_reliable(p, data, packet_size);
5299         }
5300 }
5301
5302 void process_wss_request_packet(ubyte *data, header *hinfo)
5303 {
5304         int offset = HEADER_LENGTH;
5305         int from_slot,from_index;
5306         int to_slot,to_index;
5307         int mode;
5308         int wl_ship_slot,ship_class;
5309         short player_id;        
5310         int player_num;
5311
5312         // determine who this request is from   
5313         GET_SHORT(player_id);   
5314         player_num = find_player_id(player_id); 
5315
5316         // read in the request data     
5317         GET_INT(from_slot);
5318         GET_INT(from_index);
5319         GET_INT(to_slot);
5320         GET_INT(to_index);
5321         GET_INT(wl_ship_slot); // only used in weapons loadout
5322         GET_INT(ship_class);    // only used in multi team select
5323         GET_INT(mode);
5324         PACKET_SET_SIZE();
5325
5326         SDL_assert(player_num != -1);   
5327         if(player_num == -1){
5328                 return;
5329         }
5330
5331         // if we're the standalone, we have to route this packet to the host of the game
5332         if(Game_mode & GM_STANDALONE_SERVER){
5333                 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5334         } 
5335         // otherwise we're the host and should process the request
5336         else {
5337                 switch(mode){
5338                 case WSS_WEAPON_SELECT :
5339                         wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5340                         break;
5341                 case WSS_SHIP_SELECT :
5342                         multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);                     
5343                         break;
5344                 default:
5345                         Int3();
5346                 }
5347         }
5348 }
5349
5350 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5351 {
5352         ubyte data[MAX_PACKET_SIZE],team;
5353         int packet_size = 0;
5354
5355         SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5356
5357         BUILD_HEADER(WSS_UPDATE_PACKET);
5358
5359         // add the team/pool # this is for
5360         team = (ubyte)team_num;
5361         ADD_DATA(team);
5362
5363         // add the data block size
5364         ADD_INT(size);
5365         
5366         // add the data itself
5367         memcpy(data + packet_size,wss_data,size);
5368         packet_size += size;
5369
5370         // if we're also the master of the game (not on a standalone)
5371         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5372                 multi_io_send_to_all_reliable(data, packet_size);
5373         }
5374         // if we're only the host on the standalone, then send the packet to the standalone to be routed
5375         else {
5376                 multi_io_send_reliable(Net_player, data, packet_size);
5377         }
5378 }
5379
5380 void process_wss_update_packet(ubyte *data, header *hinfo)
5381 {               
5382         ubyte team;
5383         int size,player_index,idx;
5384         int offset = HEADER_LENGTH;
5385
5386         // get the team/pool #
5387         GET_DATA(team);
5388
5389         // get the data size
5390         GET_INT(size);          
5391
5392         // if we're the standalone, then we should be routing this data to all the other clients
5393         if(Game_mode & GM_STANDALONE_SERVER){
5394                 // read in the data             
5395                 offset += size;         
5396                 PACKET_SET_SIZE();
5397
5398                 // determine where this came from               
5399                 player_index = find_player_id(hinfo->id);               
5400                 SDL_assert(player_index != -1);         
5401                 if(player_index < 0){
5402                         return;
5403                 }
5404
5405                 // route the packet (don't resend it to the host)
5406                 for(idx=0;idx<MAX_PLAYERS;idx++){
5407                         if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){                               
5408                                 multi_io_send_reliable(&Net_players[idx], data, offset);
5409                         }
5410                 }                       
5411         } else {
5412                 // set the proper pool pointers
5413                 ss_set_team_pointers((int)team);
5414
5415                 // read in the block of data, and apply it to the weapons/ship pools
5416                 offset += restore_wss_data(data + offset);
5417                 PACKET_SET_SIZE();
5418
5419                 // set the pool pointers back to my own team
5420                 ss_set_team_pointers(Net_player->p_info.team);
5421
5422                 // sync the interface if this was for my own team
5423                 if((int)team == Net_player->p_info.team){
5424                         multi_ts_sync_interface();
5425                 }               
5426         }
5427 }
5428 // ALAN END
5429
5430
5431 // function to send firing information from the client to the server once they reach
5432 // the final sync screen.
5433 void send_firing_info_packet()
5434 {
5435         ubyte data[MAX_PACKET_SIZE];
5436         int packet_size;
5437         ubyte plinked, sdual;
5438
5439         SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5440
5441         BUILD_HEADER(FIRING_INFO);
5442         plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5443         sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5444         ADD_DATA( plinked );
5445         ADD_DATA( sdual );
5446         
5447         multi_io_send_reliable(Net_player, data, packet_size);
5448 }
5449
5450 void process_firing_info_packet( ubyte *data, header *hinfo )
5451 {
5452         int offset, player_num; 
5453         ubyte plinked, sdual;
5454         ship *shipp;
5455
5456         // only the master of the game should be dealing with these packets
5457         SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5458
5459         offset = HEADER_LENGTH;
5460         GET_DATA( plinked );
5461         GET_DATA( sdual );
5462         PACKET_SET_SIZE();      
5463
5464         player_num = find_player_id(hinfo->id);
5465         if(player_num < 0){
5466                 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5467                 return;
5468         }
5469
5470         // get the ship pointer for this player and set the flags accordingly.
5471         shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5472         if ( plinked )
5473                 shipp->flags |= SF_PRIMARY_LINKED;
5474         else
5475                 shipp->flags &= ~SF_PRIMARY_LINKED;
5476
5477         if ( sdual )
5478                 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5479         else
5480                 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5481 }
5482
5483 // packet to deal with changing status of mission goals.  used to be sent every so often from server
5484 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5485 // goal_num is the index into mission_goals.  new_status means failed, success, etc.  -1 if not used.
5486 // valid means goal is changing to invalid(0) or valid(1).  only applies if new_status == -1
5487 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5488 {
5489         ubyte data[MAX_PACKET_SIZE];
5490         int packet_size;
5491
5492         BUILD_HEADER(MISSION_GOAL_INFO);
5493
5494         ADD_INT(goal_num);
5495         ADD_INT(new_status);
5496         ADD_INT(valid);
5497         
5498         multi_io_send_to_all_reliable(data, packet_size);
5499 }
5500
5501 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5502 {
5503         int offset, goal_num, new_status, valid;
5504
5505         offset = HEADER_LENGTH;
5506         GET_INT(goal_num);
5507         GET_INT(new_status);
5508         GET_INT(valid);
5509         PACKET_SET_SIZE();
5510
5511         // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5512         if ( new_status != -1 ){
5513                 mission_goal_status_change( goal_num, new_status );
5514         } else {
5515                 mission_goal_validation_change( goal_num, valid );
5516         }
5517 }
5518
5519 void send_player_settings_packet(net_player *p)
5520 {
5521         ubyte data[MAX_PACKET_SIZE];
5522         ubyte stop;
5523         int idx;
5524         int packet_size = 0;
5525
5526         // build the header
5527         BUILD_HEADER(PLAYER_SETTINGS);
5528
5529         // add all the data for all the players
5530         stop = 0x0;
5531         for(idx=0;idx<MAX_PLAYERS;idx++){
5532                 if(MULTI_CONNECTED(Net_players[idx])){
5533                         ADD_DATA(stop);
5534                         ADD_SHORT(Net_players[idx].player_id);
5535
5536                         // break the p_info structure by member, so we don't overwrite any absolute pointers
5537                         // ADD_DATA(Net_players[idx].p_info);
5538                         ADD_INT(Net_players[idx].p_info.team);
5539                         ADD_INT(Net_players[idx].p_info.ship_index);
5540                         ADD_INT(Net_players[idx].p_info.ship_class);
5541                 }
5542         }
5543         // add the stop byte
5544         stop = 0xff;
5545         ADD_DATA(stop);
5546
5547         // either broadcast the data or send to a specific player
5548         if(p == NULL){          
5549                 multi_io_send_to_all_reliable(data, packet_size);
5550         } else {
5551                 multi_io_send_reliable(p, data, packet_size);
5552         }                       
5553 }
5554
5555 void process_player_settings_packet(ubyte *data, header *hinfo)
5556 {
5557         int offset,player_num;
5558         net_player_info bogus,*ptr;
5559         short player_id;
5560         ubyte stop;
5561
5562         offset = HEADER_LENGTH;
5563
5564         // read in the data for all the players
5565         GET_DATA(stop);
5566         while(stop != 0xff){
5567                 // lookup the player
5568                 GET_SHORT(player_id);
5569                 player_num = find_player_id(player_id);
5570
5571                 // make sure this is a valid player
5572                 if(player_num == -1){
5573                         ptr = &bogus;                   
5574                 } else {
5575                         ptr = &Net_players[player_num].p_info;
5576                 }
5577                 
5578                 GET_INT(ptr->team);
5579                 GET_INT(ptr->ship_index);
5580                 GET_INT(ptr->ship_class);
5581                 
5582                 // next stop byte
5583                 GET_DATA(stop);
5584         }
5585         PACKET_SET_SIZE();
5586
5587         // update the server with my new state
5588         // MWA -- 3/31/98 -- check for in mission instead of state.
5589         //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5590         if( !(Game_mode & GM_IN_MISSION) ) {
5591                 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5592                 send_netplayer_update_packet(); 
5593         }
5594
5595
5596         // display some cool text
5597         multi_common_add_text(XSTR("Received player settings packet\n",721),1); 
5598 }
5599
5600 void send_deny_packet(net_addr *addr, int code)
5601 {
5602         ubyte data[10];
5603         int packet_size = 0;
5604
5605         // build the header and add the rejection code
5606         BUILD_HEADER(DENY);
5607
5608         ADD_INT(code);
5609         
5610         // send the packet      
5611         psnet_send(addr, data, packet_size);
5612 }
5613
5614 void process_deny_packet(ubyte *data, header *hinfo)
5615 {
5616         int offset,code;
5617
5618         // get the denial code
5619         offset = HEADER_LENGTH;
5620         GET_INT(code);
5621         PACKET_SET_SIZE();
5622
5623         // if there is already a dialog active, do nothing - who cares at this point.
5624         if(popup_active()){
5625                 return;
5626         }
5627
5628         // display the appropriate dialog
5629         switch(code){
5630         case JOIN_DENY_JR_STATE :
5631                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is not in an appropriate state to accept",722));
5632                 break;
5633         case JOIN_DENY_JR_TRACKER_INVAL :
5634                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a Parallax Online game and you are not a registered Parallax Online pilot",723));
5635                 break;
5636         case JOIN_DENY_JR_PASSWD :
5637                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5638                 break;  
5639         case JOIN_DENY_JR_CLOSED :
5640                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a closed game and the mission is in progress",725));
5641                 break;
5642         case JOIN_DENY_JR_TEMP_CLOSED :
5643                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the netgame is forming and the host has temporarily closed it",726));
5644                 break;
5645         case JOIN_DENY_JR_RANK_HIGH :
5646                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a rank limited game and your rank is too high",727));
5647                 break;
5648         case JOIN_DENY_JR_RANK_LOW :
5649                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a rank limited game and your rank is too low",728));
5650                 break;
5651         case JOIN_DENY_JR_DUP :
5652                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5653                 break;
5654         case JOIN_DENY_JR_FULL :
5655                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5656                 break;
5657         case JOIN_DENY_JR_BANNED :
5658                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5659                 break;
5660         case JOIN_DENY_JR_NOOBS :
5661                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5662                 break;
5663         case JOIN_DENY_JR_INGAME_JOIN :
5664                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join at this time since someone else is currently joining.  Try again shortly.",733));
5665                 break;
5666         case JOIN_DENY_JR_BAD_VERSION :
5667                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join this game because you are running an older version of FreeSpace than the server.  Exit FreeSpace, and choose the 'Update FreeSpace' button in the FreeSpace launcher to download the latest version of FreeSpace.",734));
5668                 break;  
5669         case JOIN_DENY_JR_TYPE :
5670                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5671                 break;                  
5672         }       
5673
5674         // call this so that the join request timestamp automatically expires when we hear back from the server
5675         multi_join_reset_join_stamp();
5676 }
5677
5678 // this packet will consist of 
5679 // 1.) netplayer ship classes                   (85 bytes max)
5680 // 2.) ship weapon state data                   (241 bytes max)
5681 // 3.) player settings et. al.          (133 bytes max)
5682 // TOTAL                            459                         NOTE : keep this in mind when/if adding new data to this packet
5683 void send_post_sync_data_packet(net_player *p, int std_request)
5684 {
5685         ubyte data[MAX_PACKET_SIZE], val;
5686         char bval;
5687         ship *shipp;            
5688         net_player *pl;
5689         ship_obj *so;
5690         ushort sval, ship_ets;
5691         int idx, player_index;
5692         int packet_size = 0;
5693         int ship_count;
5694         short val_short;
5695
5696         BUILD_HEADER(POST_SYNC_DATA);
5697
5698         // some header information for standalone packet routing purposes
5699         val = (ubyte)std_request;
5700         ADD_DATA(val);
5701
5702         // the standalone has two situations
5703         // 1.) sending a request to the host to distribute this block of data
5704         // 2.) having recevied this block of data from the host, it redistributes it
5705         if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5706                 // case 1, send the request                                     
5707                 multi_io_send_reliable(Netgame.host, data, packet_size);
5708                 return;
5709         }
5710         // case 2 for the standalone is below (as normal)
5711
5712         // otherwise build the data now 
5713         
5714         // add all deleted ships
5715         val = (ubyte)Multi_ts_num_deleted;
5716         ADD_DATA(val);
5717         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5718                 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5719                 ADD_USHORT(sval);
5720         }
5721
5722         // ship count   
5723         ship_count = 0;
5724         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5725                 shipp = &Ships[Objects[so->objnum].instance];
5726
5727                 // don't process non player wing ships
5728                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5729                         continue;
5730
5731                 ship_count++;
5732         }
5733
5734         // # of ships - used multiple times in the packet
5735         val = (ubyte)ship_count;
5736         ADD_DATA(val);
5737
5738         // add ship class information (85 bytes max)    
5739         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5740                 shipp = &Ships[Objects[so->objnum].instance];
5741
5742                 // don't process non player wing ships
5743                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5744                         continue;               
5745                 
5746                 // add the net signature of the object for look up
5747                 ADD_USHORT( Objects[so->objnum].net_signature );
5748                 
5749                 // add the ship info index 
5750                 val = (ubyte)(shipp->ship_info_index);
5751                 ADD_DATA(val);          
5752
5753                 // add the ships's team select index
5754                 val = (ubyte)shipp->ts_index;
5755                 ADD_DATA(val);
5756         }       
5757
5758         // add weapon state information for all starting ships (241 bytes max)
5759         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5760                 shipp = &Ships[Objects[so->objnum].instance];
5761
5762                 // don't process non player wing ships
5763                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5764                         continue;                       
5765
5766                 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5767                 pl = NULL;
5768                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5769                         player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5770                         if(player_index == -1){
5771                                 pl = NULL;
5772                         } else {
5773                                 pl = &Net_players[player_index];
5774                         }
5775                 }
5776
5777                 // add the net signature and other weapon information
5778                 ADD_USHORT( Objects[so->objnum].net_signature );                
5779
5780                 // add number of primary and secondary banks
5781                 bval = (char)(shipp->weapons.num_primary_banks);
5782                 ADD_DATA(bval);
5783                 bval = (char)(shipp->weapons.num_secondary_banks);
5784                 ADD_DATA(bval);
5785
5786                 // add weapon bank status
5787                 bval = (char)(shipp->weapons.current_primary_bank);
5788                 if(pl != NULL){
5789                         pl->s_info.cur_primary_bank = bval;
5790                 }
5791                 // SDL_assert(bval != -1);
5792                 ADD_DATA(bval);
5793
5794                 bval = (char)(shipp->weapons.current_secondary_bank);
5795                 if(pl != NULL){
5796                         pl->s_info.cur_secondary_bank = bval;
5797                 }
5798                 // SDL_assert(bval != -1);
5799                 ADD_DATA(bval);
5800                                                 
5801                 // primary weapon info
5802                 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5803                 ADD_DATA(bval);
5804                 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5805                 ADD_DATA(bval);
5806
5807                 // secondary weapon info
5808                 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5809                 ADD_DATA(bval);
5810                 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5811                 ADD_SHORT(val_short);
5812                 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5813                 ADD_DATA(bval);
5814                 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5815                 ADD_SHORT(val_short);
5816                 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5817                 ADD_DATA(bval);
5818                 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5819                 ADD_SHORT(val_short);           
5820                 
5821                 // send primary and secondary weapon link status
5822                 val = 0x0;
5823                 if(shipp->flags & SF_PRIMARY_LINKED){
5824                         if(pl != NULL){
5825                                 pl->s_info.cur_link_status |= (1<<0);
5826                         }
5827                         val |= (1<<0);
5828                 }                               
5829                 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5830                         if(pl != NULL){
5831                                 pl->s_info.cur_link_status |= (1<<1);
5832                         }
5833                         val |= (1<<1);
5834                 }               
5835                 // if this is a player ship add (1<<2)
5836                 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5837                         val |= (1<<2);
5838                 }
5839                 ADD_DATA(val);
5840
5841                 // add a ship ets value
5842                 ship_ets = 0x0000;
5843                 // shield ets           
5844                 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5845                 // weapon ets
5846                 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5847                 // engine ets
5848                 ship_ets |= ((ushort)shipp->engine_recharge_index);
5849                 ADD_USHORT(ship_ets);
5850
5851         }
5852
5853         // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5854         // or if I'm the server as well as the host, I should be sending this to all players
5855         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5856                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5857                         // broadcast
5858                         if(p == NULL){                          
5859                                 multi_io_send_to_all_reliable(data, packet_size);
5860                         }
5861                         // send to a specific player
5862                         else {
5863                                 multi_io_send_reliable(p, data, packet_size);
5864                         }
5865                 } else {
5866                         multi_io_send_reliable(Net_player, data, packet_size);
5867                 }
5868         }
5869         // standalone mode
5870         else {
5871                 // broadcast
5872                 if(p == NULL){
5873                         multi_io_send_to_all_reliable(data, packet_size);
5874                 }
5875                 // send to a specific player
5876                 else {
5877                         multi_io_send_reliable(p, data, packet_size);
5878                 }
5879         }
5880 }
5881
5882 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5883 {
5884         ubyte val, sinfo_index, ts_index;
5885         char b;
5886         ushort net_sig, ship_ets, sval;
5887         ship *shipp;
5888         object *objp;
5889         int idx;
5890         int offset = HEADER_LENGTH;
5891         int ship_count;
5892         short val_short;
5893
5894         // packet routing information
5895         GET_DATA(val);
5896
5897         // if I'm the host on a standalone, this is going to be a request to send the data to the standalone to be routed
5898         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5899                 PACKET_SET_SIZE();
5900
5901                 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5902                 multi_ts_create_wings();
5903                 
5904                 // send to the standalone through my socket
5905                 send_post_sync_data_packet(Net_player);
5906                 return;
5907         }
5908
5909         // process player
5910
5911         // add all deleted ships
5912         GET_DATA(val);
5913         Multi_ts_num_deleted = (int)val;
5914         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5915                 // get the ship's objnum
5916                 GET_USHORT(sval);
5917                 objp = NULL;
5918                 objp = multi_get_network_object(sval);
5919                 if(objp != NULL){
5920                         // delete the ship appropriately
5921                         // mark the object as having been deleted
5922                         Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5923
5924                         // delete the ship
5925                         ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5926                         obj_delete(Multi_ts_deleted_objnums[idx]);                      
5927                         ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5928                 } else {
5929                         Multi_ts_num_deleted--;
5930                         nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5931                 }
5932         }
5933
5934         // ship count
5935         GET_DATA(val);
5936         ship_count = val;
5937
5938         // process ship class information
5939         for(idx=0; idx<ship_count; idx++){      
5940                 // get the object's net signature
5941                 GET_USHORT(net_sig);
5942                 GET_DATA(sinfo_index);
5943                 GET_DATA(ts_index);
5944
5945                 // attempt to get the object
5946                 objp = multi_get_network_object(net_sig);
5947
5948                 // make sure we found a ship
5949                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5950
5951                 // set the ship to be the right class
5952                 change_ship_type(objp->instance,(int)sinfo_index);
5953
5954                 // set the ship's team select index
5955                 Ships[objp->instance].ts_index = (int)ts_index;         
5956         }
5957
5958         // process ship weapon state info
5959         for(idx=0; idx<ship_count; idx++){      
5960                 // get the object's net signature
5961                 GET_USHORT(net_sig);
5962
5963                 // attempt to get the object
5964                 objp = multi_get_network_object(net_sig);
5965
5966                 // make sure we found a ship
5967                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5968
5969                 // get a pointer to the ship
5970                 shipp = &Ships[objp->instance];
5971
5972                 // get number of primary and secondary banks;
5973                 GET_DATA(b);
5974                 SDL_assert( b != -1 );
5975                 shipp->weapons.num_primary_banks = (int)b;
5976
5977                 GET_DATA(b);
5978                 SDL_assert( b != -1 );
5979                 shipp->weapons.num_secondary_banks = (int)b;
5980
5981                 // get bank selection info
5982                 GET_DATA(b);
5983                 if ( b == -1 ){
5984                         b = 0;
5985                 }
5986                 shipp->weapons.current_primary_bank = (int)b;
5987
5988                 GET_DATA(b);
5989                 if ( b == -1 ){
5990                         b = 0;
5991                 }
5992                 shipp->weapons.current_secondary_bank = (int)b;         
5993
5994                         // primary weapon info
5995                 GET_DATA(b);
5996                 shipp->weapons.primary_bank_weapons[0] = (int)b;
5997
5998                 GET_DATA(b);
5999                 shipp->weapons.primary_bank_weapons[1] = (int)b;
6000
6001                 // secondary weapon info
6002                 GET_DATA(b);
6003                 shipp->weapons.secondary_bank_weapons[0] = (int)b;
6004                 GET_SHORT(val_short);
6005                 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
6006
6007                 GET_DATA(b);
6008                 shipp->weapons.secondary_bank_weapons[1] = (int)b;
6009                 GET_SHORT(val_short);
6010                 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
6011
6012                 GET_DATA(b);
6013                 shipp->weapons.secondary_bank_weapons[2] = (int)b;
6014                 GET_SHORT(val_short);
6015                 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6016
6017                 // other flags
6018                 val = 0x0;
6019                 GET_DATA(val);
6020
6021                 if(val & (1<<0)){
6022                         shipp->flags |= SF_PRIMARY_LINKED;                              
6023                 }                               
6024                 if(val & (1<<1)){               
6025                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;                 
6026                 }
6027                 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6028                 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6029                 if(val & (1<<2)){
6030                         Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6031                 } else {
6032                         obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6033                 }
6034
6035                 // get ship ets
6036                 GET_USHORT(ship_ets);
6037                 // shield ets
6038                 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6039                 // weapon ets
6040                 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6041                 // engine ets
6042                 shipp->engine_recharge_index = (ship_ets & 0x000f);     
6043         }
6044         PACKET_SET_SIZE();
6045
6046         // ack the server
6047         Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6048         send_netplayer_update_packet();
6049
6050         // the standalone server will receive this packet from the host of the game, to be applied locally and
6051         // also to be rebroadcast. 
6052         if(Game_mode & GM_STANDALONE_SERVER){
6053                 // update player ets settings
6054                 for(idx=0;idx<MAX_PLAYERS;idx++){
6055                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6056                                 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6057                         }
6058                 }                       
6059                 
6060                 send_post_sync_data_packet(NULL,0);
6061         }
6062 }
6063
6064 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6065 {
6066         ubyte data[MAX_PACKET_SIZE],val;
6067         short val_short;
6068         int idx,i;
6069         int packet_size = 0;
6070
6071         // build the header
6072         BUILD_HEADER(WSS_SLOTS_DATA);
6073
6074         // some header information for standalone packet routing purposes
6075         val = (ubyte)std_request;
6076         ADD_DATA(val);
6077
6078         // add the team #
6079         val = (ubyte)team_num;
6080         ADD_DATA(val);
6081         
6082         // add whether this is the final packet or not
6083         val = (ubyte)final;
6084         ADD_DATA(val);
6085
6086         // the standalone has two situations
6087         // 1.) sending a request to the host to distribute this block of data
6088         // 2.) having recevied this block of data from the host, it redistributes it
6089         if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6090                 // case 1, send the request                                     
6091                 multi_io_send_reliable(Netgame.host, data, packet_size);
6092                 return;
6093         }
6094         // case 2 for the standalone is below (as normal)
6095
6096         // add all the slots
6097         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6098                 // add the ship class
6099                 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6100                 ADD_DATA(val);
6101
6102                 // add the weapons
6103                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6104                         val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6105                         ADD_DATA(val);
6106                 }
6107
6108                 // add the weapon counts
6109                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6110                         val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6111                         ADD_SHORT(val_short);
6112                 }
6113         }
6114
6115                 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6116         // or if I'm the server as well as the host, I should be sending this to all players
6117         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6118                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6119                         // broadcast
6120                         if(p == NULL){                          
6121                                 multi_io_send_to_all_reliable(data, packet_size);
6122                         }
6123                         // send to a specific player
6124                         else {
6125                                 multi_io_send_reliable(p, data, packet_size);
6126                         }
6127                 } else {
6128                         multi_io_send_reliable(Net_player, data, packet_size);
6129                 }
6130         }
6131         // standalone mode
6132         else {
6133                 // broadcast
6134                 if(p == NULL){
6135                         multi_io_send_to_all_reliable(data, packet_size);                       
6136                 }
6137                 // send to a specific player
6138                 else {
6139                         multi_io_send_reliable(p, data, packet_size);
6140                 }
6141         }       
6142 }
6143
6144 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6145 {
6146         ubyte val,team_num,final;
6147         int idx,i;
6148         int offset = HEADER_LENGTH;
6149         short val_short;
6150
6151         // packet routing information
6152         GET_DATA(val);
6153
6154         // get team data
6155         GET_DATA(team_num);
6156
6157         // get whether this is the final packet or not
6158         GET_DATA(final);
6159
6160         // if I'm the host on a standalone, this is going to be a request to send the data to the standalone to be routed
6161         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6162                 PACKET_SET_SIZE();
6163
6164                 // send to the standalone through my socket
6165                 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6166                 return;
6167         }       
6168
6169         // read in all the slot data
6170         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6171                 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6172
6173                 // get the ship class
6174                 GET_DATA(val);
6175                 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6176
6177                 // get the weapons
6178                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6179                         GET_DATA(val);
6180                         Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6181
6182                         // check for signed/unsigned problems
6183                         if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6184                                 Wss_slots_teams[team_num][idx].wep[i] = -1;
6185                         }
6186                 } 
6187
6188                 // get the weapon counts
6189                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6190                         GET_SHORT(val_short);
6191                         Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6192                 }
6193         }
6194         PACKET_SET_SIZE();
6195
6196         // update my netplayer state if this is the final packet
6197         if(final){
6198                 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6199                 send_netplayer_update_packet();
6200         }
6201
6202         // the standalone server will receive this packet from the host of the game, to be applied locally and
6203         // also to be rebroadcast. 
6204         if(Game_mode & GM_STANDALONE_SERVER){
6205                 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6206         } else {
6207                 // add some mission sync text
6208                 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6209         }
6210 }
6211
6212 #define OBJ_VISIBILITY_DOT                                      0.6f    
6213
6214 // send and receive packets for shield explosion information
6215 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6216 {
6217         int packet_size, i;
6218         ubyte data[MAX_PACKET_SIZE], utri_num;
6219
6220         Int3();
6221         // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6222
6223         SDL_assert( tri_num < UCHAR_MAX );
6224         utri_num = (ubyte)tri_num;
6225
6226         // for each player, determine if this object is behind the player -- if so, don't
6227         // send the packet.
6228         for ( i = 0; i < MAX_PLAYERS; i++ ) {
6229                 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6230                         float           dot;
6231                         vector  eye_to_obj_vec, diff, eye_pos;
6232                         matrix  eye_orient;
6233
6234                         eye_pos = Net_players[i].s_info.eye_pos;
6235                         eye_orient = Net_players[i].s_info.eye_orient;
6236
6237                         // check for same vectors
6238                         vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6239                         if ( vm_vec_mag_quick(&diff) < 0.01 ){
6240                                 continue;
6241                         }
6242
6243                         vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6244                         dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6245
6246                         if ( dot < OBJ_VISIBILITY_DOT ){
6247                                 continue;
6248                         }
6249
6250                         BUILD_HEADER(SHIELD_EXPLOSION);
6251
6252                         ADD_USHORT( Objects[objnum].net_signature );
6253                         ADD_DATA(utri_num);                     
6254                         
6255                         multi_io_send(&Net_players[i], data, packet_size);
6256                 }
6257         }
6258 }
6259
6260 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6261
6262 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6263 {
6264         int offset;
6265         ushort signature;
6266         ubyte utri_num;
6267         object *objp;
6268
6269         // get the shield hit data
6270         offset = HEADER_LENGTH;
6271         GET_USHORT(signature);
6272         GET_DATA(utri_num);
6273         //GET_DATA(hit_pos);
6274         PACKET_SET_SIZE();
6275
6276         // find the object with this signature.  If found, then do a shield explosion
6277         objp = multi_get_network_object( signature );
6278         if ( objp ) {
6279                 polymodel *pm;
6280                 shield_info *shieldp;
6281                 shield_tri stri;
6282                 vector hit_pos;
6283                 int i;
6284
6285                 // given the tri num, find the local position which is the average of the
6286                 // three vertices of the triangle affected.  Use this average point as the hit
6287                 // point
6288                 // SDL_assert( objp->type == OBJ_SHIP );
6289                 if(objp->type != OBJ_SHIP){
6290                         return;
6291                 }
6292
6293                 pm = model_get(Ships[objp->instance].modelnum);
6294                 shieldp = &pm->shield;
6295                 SDL_assert( utri_num < shieldp->ntris );
6296                 stri = shieldp->tris[utri_num];
6297                 vm_vec_zero(&hit_pos);
6298                 for ( i = 0; i < 3; i++ ) {
6299                         vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6300                 }
6301                 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6302                 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6303         }
6304 }
6305
6306 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6307 {
6308         scoring_struct *sc;
6309         ubyte data[MAX_PACKET_SIZE], val;
6310         int idx;                
6311         int packet_size = 0;
6312
6313         ushort u_tmp;
6314         int i_tmp;
6315
6316         sc = &pl->player->stats;
6317
6318         // build the header
6319         BUILD_HEADER(PLAYER_STATS);     
6320
6321         // add the player id
6322         ADD_SHORT(pl->player_id);
6323
6324         // add the byte indicating whether these stats are all-time or not
6325         val = (ubyte)stats_code;
6326         ADD_DATA(val);  
6327         
6328         // kill information - alltime
6329         switch(stats_code){
6330         case STATS_ALLTIME:     
6331                 // alltime kills
6332                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6333                         u_tmp = sc->kills[idx];
6334                         ADD_USHORT(u_tmp);
6335                 }
6336                 // medal information
6337                 for(idx=0;idx<NUM_MEDALS;idx++){
6338                         i_tmp = sc->medals[idx];
6339                         ADD_INT(i_tmp);
6340                 }
6341
6342                 ADD_INT(sc->score);
6343                 ADD_INT(sc->rank);
6344                 ADD_INT(sc->assists);
6345                 ADD_INT(sc->kill_count);
6346                 ADD_INT(sc->kill_count_ok);
6347                 ADD_UINT(sc->p_shots_fired);
6348                 ADD_UINT(sc->s_shots_fired);
6349                 ADD_UINT(sc->p_shots_hit);
6350                 ADD_UINT(sc->s_shots_hit);
6351                 ADD_UINT(sc->p_bonehead_hits);
6352                 ADD_UINT(sc->s_bonehead_hits);
6353                 ADD_INT(sc->bonehead_kills);
6354
6355                 ADD_UINT(sc->missions_flown);
6356                 ADD_UINT(sc->flight_time);
6357                 ADD_INT(sc->last_flown);
6358                 ADD_INT(sc->last_backup);
6359                 break;
6360
6361         case STATS_MISSION:     
6362                 // mission OKkills              
6363                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6364                         u_tmp = sc->m_okKills[idx];
6365                         ADD_USHORT(u_tmp);                      
6366                 }
6367         
6368                 ADD_INT(sc->m_score);
6369                 ADD_INT(sc->m_assists);
6370                 ADD_INT(sc->m_kill_count);
6371                 ADD_INT(sc->m_kill_count_ok);
6372                 ADD_UINT(sc->mp_shots_fired);
6373                 ADD_UINT(sc->ms_shots_fired);
6374                 ADD_UINT(sc->mp_shots_hit);
6375                 ADD_UINT(sc->ms_shots_hit);
6376                 ADD_UINT(sc->mp_bonehead_hits);
6377                 ADD_UINT(sc->ms_bonehead_hits);
6378                 ADD_INT(sc->m_bonehead_kills);
6379                 ADD_INT(sc->m_player_deaths);
6380                 ADD_INT(sc->m_medal_earned);
6381                 break;
6382
6383         case STATS_MISSION_KILLS:               
6384                 ADD_INT(sc->m_kill_count);
6385                 ADD_INT(sc->m_kill_count_ok);
6386                 ADD_INT(sc->m_assists);
6387                 break;          
6388
6389         case STATS_DOGFIGHT_KILLS:
6390                 for(idx=0; idx<MAX_PLAYERS; idx++){
6391 #ifndef MAKE_FS1
6392                         u_tmp = sc->m_dogfight_kills[idx];
6393 #else
6394                         u_tmp = 0;
6395 #endif
6396                         ADD_USHORT(u_tmp);
6397                 }
6398                 ADD_INT(sc->m_kill_count);
6399                 ADD_INT(sc->m_kill_count_ok);
6400                 ADD_INT(sc->m_assists);
6401                 break;          
6402         }
6403
6404         SDL_assert(packet_size < MAX_PACKET_SIZE);
6405
6406         // if we're a client, always send the data to the server
6407         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6408                 multi_io_send_reliable(Net_player, data, packet_size);          
6409         }
6410         // otherwise do server specific stuff
6411         else {
6412                 // send to a specific target
6413                 if(target != NULL){
6414                         multi_io_send_reliable(target, data, packet_size);                      
6415                 }
6416                 // otherwise, send to everyone
6417                 else {                  
6418                         multi_io_send_to_all_reliable(data, packet_size);
6419                 }
6420         }
6421 }
6422
6423 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6424 {
6425         ubyte val;
6426         int player_num,idx;
6427         scoring_struct *sc,bogus;
6428         short player_id;
6429         int offset = HEADER_LENGTH;
6430         ushort u_tmp;
6431         int i_tmp;
6432
6433         // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6434
6435         // get the player who these stats are for
6436         GET_SHORT(player_id);   
6437         player_num = find_player_id(player_id);
6438         if (player_num == -1) {
6439                 nprintf(("Network", "Couldn't find player for stats update!\n"));
6440                 ml_string("Couldn't find player for stats update!\n");
6441
6442                 sc = &bogus;
6443                 Int3();
6444         } else {
6445                 sc = &Net_players[player_num].player->stats;
6446         }
6447
6448         // get the stats code
6449         GET_DATA(val);  
6450         switch(val){
6451         case STATS_ALLTIME:
6452                 ml_string("Received STATS_ALLTIME\n");
6453
6454                 // kills - alltime
6455                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6456                         GET_USHORT(u_tmp);
6457                         sc->kills[idx] = u_tmp;
6458                 }
6459
6460                 // read in the stats
6461                 for (idx=0; idx<NUM_MEDALS; idx++) {
6462                         GET_INT(i_tmp);
6463                         sc->medals[idx] = i_tmp;
6464                 }
6465
6466                 GET_INT(sc->score);
6467                 GET_INT(sc->rank);
6468                 GET_INT(sc->assists);
6469                 GET_INT(sc->kill_count);
6470                 GET_INT(sc->kill_count_ok);
6471                 GET_UINT(sc->p_shots_fired);
6472                 GET_UINT(sc->s_shots_fired);
6473                 GET_UINT(sc->p_shots_hit);
6474                 GET_UINT(sc->s_shots_hit);
6475                 GET_UINT(sc->p_bonehead_hits);
6476                 GET_UINT(sc->s_bonehead_hits);
6477                 GET_INT(sc->bonehead_kills);
6478
6479                 GET_UINT(sc->missions_flown);
6480                 GET_UINT(sc->flight_time);
6481                 GET_INT(sc->last_flown);
6482                 GET_INT(sc->last_backup);
6483                 break;
6484
6485         case STATS_MISSION:
6486                 ml_string("Received STATS_MISSION\n");
6487
6488                 // kills - mission OK                   
6489                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6490                         GET_USHORT(u_tmp);
6491                         sc->m_okKills[idx] = u_tmp;                     
6492                 }
6493                 
6494                 GET_INT(sc->m_score);
6495                 GET_INT(sc->m_assists);
6496                 GET_INT(sc->m_kill_count);
6497                 GET_INT(sc->m_kill_count_ok);
6498                 GET_UINT(sc->mp_shots_fired);
6499                 GET_UINT(sc->ms_shots_fired);
6500                 GET_UINT(sc->mp_shots_hit);
6501                 GET_UINT(sc->ms_shots_hit);
6502                 GET_UINT(sc->mp_bonehead_hits);
6503                 GET_UINT(sc->ms_bonehead_hits);
6504                 GET_INT(sc->m_bonehead_kills);
6505                 GET_INT(sc->m_player_deaths);
6506                 GET_INT(sc->m_medal_earned);
6507                 break;
6508
6509         case STATS_MISSION_KILLS:               
6510                 ml_string("Received STATS_MISSION_KILLS\n");
6511
6512                 GET_INT(sc->m_kill_count);
6513                 GET_INT(sc->m_kill_count_ok);
6514                 GET_INT(sc->m_assists);
6515                 break;          
6516
6517         case STATS_DOGFIGHT_KILLS:
6518                 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6519                 if(player_num >= 0){
6520                         ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6521                 }
6522                 for(idx=0; idx<MAX_PLAYERS; idx++){
6523                         GET_USHORT(u_tmp);
6524 #ifndef MAKE_FS1
6525                         sc->m_dogfight_kills[idx] = u_tmp;
6526                         if(player_num >= 0){                            
6527                                 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6528                         }
6529 #endif
6530                 }
6531                 GET_INT(sc->m_kill_count);
6532                 GET_INT(sc->m_kill_count_ok);
6533                 GET_INT(sc->m_assists);         
6534                 break;          
6535         }
6536         PACKET_SET_SIZE();
6537
6538         // if I'm the server of the game, I should always rebroadcast these stats
6539         if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6540                 // make sure these are alltime stats
6541                 SDL_assert(val == STATS_ALLTIME);
6542
6543                 multi_broadcast_stats(STATS_ALLTIME);
6544         }
6545 }
6546
6547 // called to create asteroid stuff
6548 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6549 {
6550         int packet_size;
6551         ubyte data[MAX_PACKET_SIZE];
6552         ubyte packet_type, atype;
6553         vector vec;
6554
6555         vm_vec_zero(&vec);
6556         if (relvec != NULL )
6557                 vec = *relvec;
6558
6559         BUILD_HEADER( ASTEROID_INFO );
6560         packet_type = ASTEROID_CREATE;
6561
6562         SDL_assert( asteroid_type < UCHAR_MAX );
6563         atype = (ubyte)asteroid_type;
6564
6565         ADD_DATA( packet_type );
6566         ADD_USHORT( parent_objp->net_signature );
6567         ADD_USHORT( new_objp->net_signature );
6568         ADD_DATA( atype );
6569         //ADD_DATA( vec );
6570         add_vector_data( data, &packet_size, vec );
6571
6572         multi_io_send_to_all(data, packet_size);
6573 }
6574
6575 void send_asteroid_throw( object *objp )
6576 {
6577         int packet_size;
6578         ubyte data[MAX_PACKET_SIZE], packet_type;
6579
6580         BUILD_HEADER( ASTEROID_INFO );
6581
6582         // this packet type is an asteroid throw
6583         packet_type = ASTEROID_THROW;
6584         ADD_DATA( packet_type );
6585         ADD_USHORT( objp->net_signature );
6586         //ADD_DATA( objp->pos );
6587         add_vector_data( data, &packet_size, objp->pos );
6588         //ADD_DATA( objp->phys_info.vel );
6589         add_vector_data( data, &packet_size, objp->phys_info.vel );
6590         
6591         multi_io_send_to_all(data, packet_size);
6592 }
6593
6594 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6595 {
6596         int packet_size;
6597         ubyte data[MAX_PACKET_SIZE], packet_type;
6598         vector vec;
6599
6600         vm_vec_zero(&vec);
6601         if ( hitpos != NULL )
6602                 vec = *hitpos;
6603
6604         // build up an asteroid hit packet
6605         BUILD_HEADER( ASTEROID_INFO );
6606         packet_type = ASTEROID_HIT;
6607         ADD_DATA( packet_type );
6608         ADD_USHORT( objp->net_signature );
6609
6610         if(other_objp == NULL){
6611                 ushort invalid_sig = 0xffff;
6612                 ADD_USHORT(invalid_sig);
6613         } else {
6614                 ADD_USHORT( other_objp->net_signature );
6615         }
6616         //ADD_DATA( vec );
6617         add_vector_data( data, &packet_size, vec );
6618         ADD_FLOAT( damage );
6619         
6620         multi_io_send_to_all(data, packet_size);
6621 }
6622
6623 void process_asteroid_info( ubyte *data, header *hinfo )
6624 {
6625         int offset;
6626         ubyte packet_type;
6627
6628         offset = HEADER_LENGTH;
6629         GET_DATA( packet_type );
6630
6631         // based on the packet type, do something interesting with an asteroid!
6632         switch( packet_type ) {
6633
6634         case ASTEROID_CREATE: {
6635                 ushort psignature, signature;
6636                 ubyte atype;
6637                 vector relvec = ZERO_VECTOR;
6638                 object *parent_objp;
6639
6640                 GET_USHORT( psignature );
6641                 GET_USHORT( signature );
6642                 GET_DATA( atype );
6643                 //GET_DATA( relvec );
6644                 get_vector_data( data, &offset, relvec );
6645
6646                 // after getting the values, set the next network signature, and call the create sub function
6647                 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6648                 parent_objp = multi_get_network_object( psignature );
6649                 if ( parent_objp ) {
6650                         asteroid_sub_create( parent_objp, atype, &relvec );
6651                 } else {
6652                         nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6653                 }
6654
6655
6656                 break;
6657         }
6658
6659                 // asteroid throw packet -- asteroid has wrapped bounds
6660         case ASTEROID_THROW: {
6661                 ushort signature;
6662                 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6663                 object *objp;
6664
6665                 GET_USHORT( signature );
6666                 //GET_DATA( pos );
6667                 get_vector_data( data, &offset, pos );
6668                 //GET_DATA( vel );
6669                 get_vector_data( data, &offset, vel );
6670                 objp = multi_get_network_object( signature );
6671                 if ( !objp ) {
6672                         nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6673                         break;
6674                 }
6675                 objp->pos = pos;
6676                 objp->phys_info.vel = vel;
6677                 objp->phys_info.desired_vel = vel;
6678                 break;
6679         }
6680
6681         case ASTEROID_HIT: {
6682                 ushort signature, osignature;
6683                 object *objp, *other_objp;
6684                 vector hitpos = ZERO_VECTOR;
6685                 float damage;
6686
6687                 GET_USHORT( signature );
6688                 GET_USHORT( osignature );
6689                 //GET_DATA( hitpos );
6690                 get_vector_data( data, &offset, hitpos );
6691                 GET_FLOAT( damage );
6692
6693                 objp = multi_get_network_object( signature );
6694                 if(osignature == 0xffff){
6695                         other_objp = NULL; 
6696                 } else {
6697                         other_objp = multi_get_network_object( osignature );
6698                 }
6699                 if ( !objp ) {
6700                         nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6701                         break;
6702                 }
6703
6704                 if ( IS_VEC_NULL(&hitpos) ){
6705                         asteroid_hit( objp, other_objp, NULL, damage );
6706                 } else {
6707                         asteroid_hit( objp, other_objp, &hitpos, damage );
6708                 }
6709                 
6710                 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6711                 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6712                         weapon_hit( other_objp, objp, &hitpos );
6713                 }
6714                 break;
6715         }
6716
6717         default:
6718                 Int3();
6719                 break;
6720         }
6721
6722         PACKET_SET_SIZE();
6723 }
6724
6725 void send_host_restr_packet(const char *callsign, int code, int mode)
6726 {
6727         ubyte data[MAX_PACKET_SIZE],val;
6728         int packet_size = 0;
6729
6730         // build the header and add the opcode
6731         BUILD_HEADER(HOST_RESTR_QUERY);
6732         val = (ubyte)code;
6733         ADD_DATA(val);
6734         val = (ubyte)mode;
6735         ADD_DATA(val);
6736
6737         // add the callsign
6738         ADD_STRING(callsign);
6739
6740         // if I'm the standalone server, I should be sending this to the game host
6741         if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){               
6742                 multi_io_send_reliable(Netgame.host, data, packet_size);
6743         } 
6744         // otherwise if I'm the host, I should be sending a reply back to the standalone server
6745         else {
6746                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);         
6747                 multi_io_send_reliable(Net_player, data, packet_size);
6748         }
6749 }       
6750
6751 void process_host_restr_packet(ubyte *data, header *hinfo)
6752 {
6753         char callsign[255];
6754         ubyte code,mode;
6755         int offset = HEADER_LENGTH;
6756
6757         // get the opcode and the callsign
6758         GET_DATA(code);
6759         GET_DATA(mode);
6760         GET_STRING(callsign);
6761         PACKET_SET_SIZE();
6762
6763         // do code specific operations
6764         switch(code){
6765         // query to the host from standalone
6766         case 0:         
6767                 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6768
6769                 // set the join mode
6770                 Multi_join_restr_mode = mode;
6771
6772                 // set the timestamp
6773                 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6774
6775                 // notify the host of the event
6776                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6777                 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6778                 break;
6779                 
6780         // affirmative reply from the host to the standalone
6781         case 1:
6782                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);           
6783
6784                 // let the player join if the timestamp has not already elapsed on the server
6785                 if(Multi_restr_query_timestamp != -1){
6786                         multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6787                 }
6788                 break;  
6789
6790         // negative reply
6791         case 2 :
6792                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6793                 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6794                 Multi_restr_query_timestamp = -1;
6795                 break;
6796         }
6797 }
6798
6799 void send_netgame_end_error_packet(int notify_code,int err_code)
6800 {
6801         ubyte data[10];
6802         char code;
6803         int packet_size = 0;
6804
6805         // only the server should ever be here - although this might change if for some reason the host wants to end the game
6806         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6807         
6808         // build the header and add the notification and error codes
6809         BUILD_HEADER(NETGAME_END_ERROR);
6810         code = (char)notify_code;
6811         ADD_DATA(code);
6812         code = (char)err_code;
6813         ADD_DATA(code);
6814
6815         // send the packet      
6816         multi_io_send_to_all_reliable(data, packet_size);
6817 }
6818
6819 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6820 {
6821         int offset = HEADER_LENGTH;
6822         char notify_code,error_code;
6823
6824         // get the error and notification codes
6825         GET_DATA(notify_code);
6826         GET_DATA(error_code);
6827         PACKET_SET_SIZE();
6828
6829         // quit the game
6830         multi_quit_game(PROMPT_NONE,notify_code,error_code);    
6831 }
6832
6833 // sends info that a countermeasure succeeded.
6834 void send_countermeasure_success_packet( int objnum )
6835 {
6836         int pnum, packet_size;
6837         ubyte data[MAX_PACKET_SIZE];
6838
6839         pnum = multi_find_player_by_object( &Objects[objnum] );
6840         if ( pnum == -1 ) {
6841                 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6842                 return;
6843         }
6844
6845         BUILD_HEADER(COUNTERMEASURE_SUCCESS);   
6846         multi_io_send(&Net_players[pnum], data, packet_size);
6847 }
6848
6849 // start the flashing of my hud gauge
6850 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6851 {
6852         int offset;
6853
6854         offset = HEADER_LENGTH;
6855         PACKET_SET_SIZE();
6856
6857         hud_start_text_flash(XSTR("Evaded", 1430), 800);
6858         snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6859 }
6860
6861 #define UPDATE_IS_PAUSED                (1<<0)
6862 #define UPDATE_HULL_INFO                (1<<1)
6863
6864 void send_client_update_packet(net_player *pl)
6865 {
6866         ubyte data[MAX_PACKET_SIZE],val;
6867         int packet_size = 0;
6868
6869         // build the header
6870         BUILD_HEADER(CLIENT_UPDATE);
6871
6872         val = 0;        
6873
6874         // add the pause status
6875         if ( Multi_pause_status ) {
6876                 val |= UPDATE_IS_PAUSED;
6877         } else if ( (Game_mode & GM_IN_MISSION) && !(pl->flags & NETINFO_FLAG_INGAME_JOIN) && !(NETPLAYER_IS_OBSERVER(pl)) && !(NETPLAYER_IS_DEAD(pl)) && (Objects[pl->player->objnum].type == OBJ_SHIP) ) {
6878                 val |= UPDATE_HULL_INFO;
6879                 SDL_assert( Player_ship );                      // I"d better have one of these!!!!
6880         }
6881
6882         ADD_DATA(val);
6883
6884         // if paused, add the net address of the guy who paused
6885         if(val & UPDATE_IS_PAUSED){
6886                 SDL_assert(Multi_pause_pauser != NULL);
6887                 ADD_SHORT(Multi_pause_pauser->player_id);
6888         }
6889
6890         // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6891         if ( val & UPDATE_HULL_INFO ) {
6892                 object *objp;
6893                 ubyte percent, ns, threats;
6894                 ship_info *sip;
6895                 ship *shipp;
6896                 ship_subsys *subsysp;
6897                 int i;
6898
6899                 // get the object for the player
6900                 SDL_assert( pl->player->objnum != -1 );
6901
6902                 objp = &Objects[pl->player->objnum];
6903
6904                 SDL_assert ( objp->type == OBJ_SHIP );
6905                 shipp = &Ships[objp->instance];
6906                 sip = &Ship_info[shipp->ship_info_index];
6907
6908                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
6909                 // percentage value since that should be close enough
6910                 float temp = (objp->hull_strength  / sip->initial_hull_strength * 100.0f);              
6911                 if(temp < 0.0f){
6912                         percent = 0;
6913                 } else {
6914                         percent = (ubyte)temp;
6915                 }
6916                 ADD_DATA( percent );
6917
6918                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6919                         percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6920                         ADD_DATA( percent );
6921                 }
6922
6923                 // add the data for the subsystem hits.  We can assume that the lists will be the same side of
6924                 // both machines. Added as percent since that number <= 100
6925
6926                 // also write out the number of subsystems.  We do this because the client might not know
6927                 // about the object he is getting data for.  (i.e. he killed the object already).
6928                 ns = (ubyte)sip->n_subsystems;
6929                 ADD_DATA( ns );
6930
6931                 // now the subsystems.
6932                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6933                         percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6934                         ADD_DATA( percent );
6935                 }
6936
6937                 // compute the threats for this player.  Only compute the threats if this player is actually
6938                 // playing (i.e. he has a ship)
6939                 hud_update_reticle( pl->player );
6940                 threats = (ubyte)pl->player->threat_flags;
6941                 ADD_DATA( threats );
6942
6943                 // add his energy level for guns
6944                 ADD_FLOAT(shipp->weapon_energy);
6945
6946                 // add his secondary bank ammo
6947                 ADD_INT(shipp->weapons.num_secondary_banks);
6948                 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6949                         ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6950                 }
6951         }
6952
6953         // add pl
6954         ADD_INT(pl->sv_last_pl);
6955
6956         // send the packet reliably to the player       
6957         multi_io_send(pl, data, packet_size);
6958 }
6959
6960 void process_client_update_packet(ubyte *data, header *hinfo)
6961 {
6962         ubyte val;
6963         short pauser;
6964         int player_index;
6965         int is_paused, have_hull_info;
6966         int ammo_count;
6967         int ammo[10];
6968         float weapon_energy;
6969         int offset = HEADER_LENGTH;
6970
6971         // get the header byte containing useful information
6972         GET_DATA(val);
6973
6974         is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6975         have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6976
6977         // if we are paused, get who paused
6978         if(is_paused){          
6979                 GET_SHORT(pauser);
6980                 player_index = find_player_id(pauser);
6981                 if(player_index != -1){
6982                         Multi_pause_pauser = &Net_players[player_index];
6983                 } else {
6984                         Multi_pause_pauser = NULL;
6985                 }       
6986         }
6987
6988         // if we have hull information, then read it in.
6989         if ( have_hull_info ) {
6990                 float fval;
6991                 ship_info *sip;
6992                 ship *shipp;
6993                 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6994                 ubyte ub_tmp;
6995                 ship_subsys *subsysp;
6996                 object *objp;
6997                 int i;
6998
6999                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
7000                 // percentage value since that should be close enough
7001                 GET_DATA( hull_percent );
7002
7003                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
7004                         GET_DATA(ub_tmp);
7005                         shield_percent[i] = ub_tmp;
7006                 }
7007
7008                 // get the data for the subsystems
7009                 GET_DATA( n_subsystems );
7010                 for ( i = 0; i < n_subsystems; i++ ){
7011                         GET_DATA(ub_tmp);
7012                         subsystem_percent[i] = ub_tmp;
7013                 }
7014
7015                 GET_DATA( threats );
7016
7017                 // add his energy level for guns
7018                 GET_FLOAT(weapon_energy);
7019                 
7020                 // add his secondary bank ammo
7021                 GET_INT(ammo_count);
7022                 for(i=0; i<ammo_count; i++){
7023                         GET_INT(ammo[i]);
7024                 }
7025
7026                 // assign the above information to my ship, assuming that I can find it!  Ingame joiners might get this
7027                 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7028                 // UDP client update packets.  Only read this info if I have a ship.
7029                 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {                        
7030                         shipp = Player_ship;
7031                         objp = Player_obj;
7032                         sip = &Ship_info[shipp->ship_info_index];
7033
7034                         fval = hull_percent * sip->initial_hull_strength / 100.0f;
7035                         objp->hull_strength = fval;
7036
7037                         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7038                                 fval = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7039                                 objp->shields[i] = fval;
7040                         }
7041
7042                         // for sanity, be sure that the number of susbystems that I read in matches the player.  If not,
7043                         // then don't read these in.
7044                         if ( n_subsystems == sip->n_subsystems ) {
7045
7046                                 n_subsystems = 0;               // reuse this variable
7047                                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7048                                         int subsys_type;
7049
7050                                         fval = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7051                                         subsysp->current_hits = fval;
7052
7053                                         // add the value just generated (it was zero'ed above) into the array of generic system types
7054                                         subsys_type = subsysp->system_info->type;                                       // this is the generic type of subsystem
7055                                         SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7056                                         shipp->subsys_info[subsys_type].current_hits += fval;
7057                                         n_subsystems++;
7058                                 }
7059                         }
7060                         ship_recalc_subsys_strength( shipp );
7061
7062                         shipp->weapon_energy = weapon_energy;
7063                         for(i=0; i<ammo_count; i++){
7064                                 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7065                         }
7066
7067                         // update my threat flags.
7068                         // temporarily commented out until tested.
7069                         Net_player->player->threat_flags = threats;
7070                 }
7071         }
7072
7073         // get pl
7074         int pl;
7075         GET_INT(pl);
7076         if(Net_player != NULL){
7077                 Net_player->cl_last_pl = pl;
7078         }
7079
7080         PACKET_SET_SIZE();
7081         // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7082         if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7083                 if( is_paused ) {
7084                         multi_pause_pause();
7085                 } else {
7086                         multi_pause_unpause();
7087                 }
7088         }
7089 }
7090
7091 void send_countdown_packet(int time)
7092 {
7093         ubyte data[20];
7094         char val;
7095         int packet_size = 0;
7096
7097         // build the header and add the time
7098         BUILD_HEADER(COUNTDOWN);
7099         val = (char)time;
7100         ADD_DATA(val);
7101
7102         // if we're the server, we should broadcast to everyone
7103         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
7104                 multi_io_send_to_all_reliable(data, packet_size);
7105         }
7106         // otherwise we'de better be a host sending to the standalone
7107         else {
7108                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7109                 multi_io_send_reliable(Net_player, data, packet_size);
7110         }
7111 }
7112
7113 void process_countdown_packet(ubyte *data, header *hinfo)
7114 {
7115         int offset = HEADER_LENGTH;
7116         char time;
7117
7118         // get the time
7119         GET_DATA(time);
7120         PACKET_SET_SIZE();
7121
7122         // if we're not in the post sync data screen, ignore it
7123         if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7124                 return;
7125         }
7126
7127         // if we're the standalone, this should be a -1 telling us to start the countdown
7128         if(Game_mode & GM_STANDALONE_SERVER){
7129                 SDL_assert((int)time == -1);
7130
7131                 // start the countdown
7132                 multi_sync_start_countdown();
7133         }
7134         // otherwise if we're clients, just bash the countdown
7135         else {          
7136                 Multi_sync_countdown = (int)time;
7137         }
7138 }
7139
7140 // packets for debriefing information
7141 void send_debrief_info( int stage_count[], int *stages[] )
7142 {
7143         ubyte data[MAX_PACKET_SIZE];
7144         int packet_size, i, j;
7145         int i_tmp;
7146
7147         BUILD_HEADER(DEBRIEF_INFO);
7148
7149         // add the data for the teams
7150         for ( i = 0; i < Num_teams; i++ ) {
7151                 int count;
7152
7153                 count = stage_count[i];
7154                 ADD_INT( count );
7155                 for ( j = 0; j < count; j++ ) {
7156                         i_tmp = stages[i][j];
7157                         ADD_INT( i_tmp );
7158                 }
7159         }
7160         
7161         multi_io_send_to_all_reliable(data, packet_size);
7162 }
7163
7164 // process a debrief info packet from the server
7165 void process_debrief_info( ubyte *data, header *hinfo )
7166 {
7167         int offset, i, j;
7168         int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7169         int i_tmp;
7170
7171         offset = HEADER_LENGTH;
7172         for ( i = 0; i < Num_teams; i++ ) {
7173                 int count;
7174
7175                 GET_INT( count );
7176                 stage_counts[i] = count;
7177                 stages[i] = active_stages[i];
7178                 for ( j = 0; j < count; j++ ) {
7179                         GET_INT(i_tmp);
7180                         active_stages[i][j] = i_tmp;
7181                 }
7182         }
7183         PACKET_SET_SIZE();
7184
7185         // now that we have the stage data for the debriefing stages, call debrief function with the
7186         // data so that clients can now see the debriefing stuff.  Do it only for my team.
7187         SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7188         debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7189 }
7190
7191 // sends homing information to all clients.  We only need signature and num_missiles (because of hornets).
7192 // sends homing_object and homing_subsystem to all clients.
7193 void send_homing_weapon_info( int weapon_num )
7194 {
7195         ubyte data[MAX_PACKET_SIZE];
7196         char t_subsys;
7197         int packet_size;
7198         object *homing_object;
7199         ushort homing_signature;
7200         weapon *wp;
7201
7202         wp = &Weapons[weapon_num];
7203
7204         // be sure that this weapon object is a homing object.
7205         if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7206                 return;
7207
7208         // get the homing signature.  If this weapon isn't homing on anything, then sent 0 as the
7209         // homing signature.
7210         homing_signature = 0;
7211         homing_object = wp->homing_object;
7212         if ( homing_object != NULL ) {
7213                 homing_signature = homing_object->net_signature;
7214
7215                 // get the subsystem index.
7216                 t_subsys = -1;
7217                 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7218                         int s_index;
7219
7220                         s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7221                         SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
7222                         t_subsys = (char)s_index;
7223                 }
7224         }
7225
7226         BUILD_HEADER(HOMING_WEAPON_UPDATE);
7227         ADD_USHORT( Objects[wp->objnum].net_signature );
7228         ADD_USHORT( homing_signature );
7229         ADD_DATA( t_subsys );
7230         
7231         multi_io_send_to_all(data, packet_size);
7232 }
7233
7234 // process a homing weapon info change packet.  multiple_missiles parameter specifies is this
7235 // packet contains information for multiple weapons (like hornets).
7236 void process_homing_weapon_info( ubyte *data, header *hinfo )
7237 {
7238         int offset;
7239         ushort weapon_signature, homing_signature;
7240         char h_subsys;
7241         object *homing_object, *weapon_objp;
7242         weapon *wp;
7243
7244         offset = HEADER_LENGTH;
7245
7246         // get the data for the packet
7247         GET_USHORT( weapon_signature );
7248         GET_USHORT( homing_signature );
7249         GET_DATA( h_subsys );
7250         PACKET_SET_SIZE();
7251
7252         // deal with changing this weapons homing information
7253         weapon_objp = multi_get_network_object( weapon_signature );
7254         if ( weapon_objp == NULL ) {
7255                 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7256                 return;
7257         }
7258         SDL_assert( weapon_objp->type == OBJ_WEAPON );
7259         wp = &Weapons[weapon_objp->instance];
7260
7261         // be sure that we can find these weapons and 
7262         homing_object = multi_get_network_object( homing_signature );
7263         if ( homing_object == NULL ) {
7264                 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7265                 return;
7266         }
7267
7268         if ( homing_object->type == OBJ_WEAPON ) {
7269                 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7270         }
7271
7272         wp->homing_object = homing_object;
7273         wp->homing_subsys = NULL;
7274         wp->target_num = OBJ_INDEX(homing_object);
7275         wp->target_sig = homing_object->signature;
7276         if ( h_subsys != -1 ) {
7277                 SDL_assert( homing_object->type == OBJ_SHIP );
7278                 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7279         }
7280
7281         if ( homing_object->type == OBJ_SHIP ) {
7282                 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7283         }
7284 }
7285
7286 void send_emp_effect(ushort net_sig, float intensity, float time)
7287 {
7288         ubyte data[25];
7289         int packet_size;
7290
7291         SDL_assert(MULTIPLAYER_MASTER);
7292
7293         // build the packet and add the opcode
7294         BUILD_HEADER(EMP_EFFECT);
7295         ADD_USHORT(net_sig);
7296         ADD_FLOAT(intensity);
7297         ADD_FLOAT(time);
7298
7299         // send it to the player                
7300         multi_io_send_to_all(data, packet_size);
7301 }
7302
7303 void process_emp_effect(ubyte *data, header *hinfo)
7304 {
7305         float intensity, time;
7306         ushort net_sig;
7307         object *objp;
7308         int offset = HEADER_LENGTH;
7309
7310         // read in the EMP effect data
7311         GET_USHORT(net_sig);
7312         GET_FLOAT(intensity);
7313         GET_FLOAT(time);
7314         PACKET_SET_SIZE();
7315
7316         // try and find the object
7317         objp = multi_get_network_object(net_sig);
7318         if((objp != NULL) && (objp->type == OBJ_SHIP)){         
7319                 // if i'm not an observer and I have a valid ship, play the EMP effect
7320                 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7321                         emp_start_local(intensity, time);
7322                 }
7323
7324                 // start the effect for the ship itself
7325                 emp_start_ship(objp, intensity, time);
7326         }
7327 }
7328
7329 // tells whether or not reinforcements are available
7330 void send_reinforcement_avail( int rnum )
7331 {
7332         ubyte data[25];
7333         int packet_size;
7334
7335         BUILD_HEADER(REINFORCEMENT_AVAIL);
7336         ADD_INT( rnum );        
7337         multi_io_send_to_all_reliable(data, packet_size);
7338 }
7339
7340 void process_reinforcement_avail( ubyte *data, header *hinfo )
7341 {
7342         int offset;
7343         int rnum;
7344
7345         offset = HEADER_LENGTH;
7346         GET_INT( rnum );
7347         PACKET_SET_SIZE();
7348
7349         // sanity check for a valid reinforcement number
7350         if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7351                 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7352         }
7353 }
7354
7355 void send_change_iff_packet(ushort net_signature, int new_team)
7356 {
7357         ubyte data[MAX_PACKET_SIZE];
7358         int packet_size = 0;
7359
7360         if(Net_player == NULL){
7361                 return;
7362         }
7363         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7364                 return;
7365         }
7366
7367         // build the packet and add the data
7368         BUILD_HEADER(CHANGE_IFF);
7369         ADD_USHORT(net_signature);
7370         ADD_INT(new_team);
7371
7372         // send to all players  
7373         multi_io_send_to_all_reliable(data, packet_size);
7374 }
7375
7376 void process_change_iff_packet( ubyte *data, header *hinfo)
7377 {
7378         int offset = HEADER_LENGTH;
7379         ushort net_signature;
7380         int new_team;   
7381         object *objp;
7382
7383         // get the data
7384         GET_USHORT(net_signature);
7385         GET_INT(new_team);
7386         PACKET_SET_SIZE();
7387
7388         // lookup the object
7389         objp = multi_get_network_object(net_signature);
7390         if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7391                 Ships[objp->instance].team = new_team;
7392         }       
7393 }
7394
7395 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7396 {
7397         int packet_size, objnum;
7398         ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7399         object *objp;   
7400         int np_index;
7401         net_player *ignore = NULL;
7402
7403         // sanity checking for now
7404         SDL_assert ( banks_fired <= 3 );
7405
7406         // get an object pointer for this ship.
7407         objnum = shipp->objnum;
7408         objp = &Objects[objnum];
7409
7410         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7411         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7412                 return;
7413         }
7414
7415         // just in case nothing got fired
7416         if(banks_fired <= 0){
7417                 return;
7418         }
7419
7420         // ubanks_fired = (ubyte)banks_fired;
7421         // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7422         // SDL_assert( current_bank <= 3 );
7423
7424         // insert the current primary bank into this byte
7425         // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7426
7427         // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7428         // if ( shipp->flags & SF_PRIMARY_LINKED ){
7429                 // ubanks_fired |= (1<<7);
7430         // }    
7431
7432         // determine if its a player ship and don't send to him if we're in "client firing" mode
7433         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7434         if(MULTIPLAYER_MASTER){
7435                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7436                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7437                         ignore = &Net_players[np_index];
7438                 }
7439         }
7440
7441         // build up the standard weapon fired packet.  This packet will get sent to all players if an AI
7442         // ship fired the primary weapons.  If a player fired the weaspon, then this packet will get sent
7443         // to every player but the guy who actullly fired the weapon.  This method is used to help keep client
7444         // and server in sync w.r.t. weapon energy for player ship
7445         BUILD_HEADER( PRIMARY_FIRED_NEW );
7446         ADD_USHORT(objp->net_signature);
7447         // ADD_DATA(ubanks_fired);
7448
7449         // if I'm a server, broadcast to all players
7450         if(MULTIPLAYER_MASTER){         
7451                 multi_io_send_to_all(data, packet_size, ignore);
7452
7453                 // TEST CODE
7454                 multi_rate_add(1, "wfi", packet_size);
7455         }
7456         // otherwise just send to the server
7457         else {
7458                 multi_io_send(Net_player, data, packet_size);           
7459         }
7460 }
7461
7462 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7463 {
7464         int offset; // linked;  
7465         // ubyte banks_fired, current_bank;
7466         object* objp;   
7467 //      ship *shipp;
7468         ushort shooter_sig;     
7469
7470         // read all packet info
7471         offset = HEADER_LENGTH;
7472         GET_USHORT(shooter_sig);
7473         // GET_DATA(banks_fired);
7474         PACKET_SET_SIZE();
7475
7476         // find the object this fired packet is operating on
7477         objp = multi_get_network_object( shooter_sig );
7478         if ( objp == NULL ) {
7479                 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7480                 return;
7481         }
7482         // if this object is not actually a valid ship, don't do anything
7483         if(objp->type != OBJ_SHIP){
7484                 return;
7485         }
7486         if(objp->instance < 0){
7487                 return;
7488         }
7489 //      shipp = &Ships[objp->instance];
7490         
7491         // get the link status of the primary banks
7492         // linked = 0;
7493         // if ( banks_fired & (1<<7) ) {
7494                 // linked = 1;
7495                 // banks_fired ^= (1<<7);
7496         // }
7497
7498         // get the current primary bank
7499         // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7500         // current_bank &= 0x3;
7501         // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7502         // shipp->weapons.current_primary_bank = current_bank;
7503
7504         // strip off all remaining bits and just keep which banks were actually fired.
7505         // banks_fired &= 0x3;
7506         
7507         // set the link status of the ship if not the player.  If it is the player, we will do sanity checking
7508         // only (for now).      
7509         // if ( !linked ){
7510 //              shipp->flags &= ~SF_PRIMARY_LINKED;
7511         // } else {
7512                 // shipp->flags |= SF_PRIMARY_LINKED;
7513         // }
7514
7515         // if we're in client firing mode, ignore ones for myself       
7516         if((Player_obj != NULL) && (Player_obj == objp)){               
7517                 return;
7518         }
7519                 
7520         ship_fire_primary( objp, 0, 1 );
7521 }
7522
7523 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7524 {
7525         ubyte data[MAX_PACKET_SIZE];
7526         int packet_size;
7527         int np_index;   
7528         net_player *ignore = NULL;
7529
7530         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7531         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7532                 return;
7533         }
7534
7535         SDL_assert ( cmeasure_count < UCHAR_MAX );
7536         BUILD_HEADER(COUNTERMEASURE_NEW);
7537         ADD_USHORT( objp->net_signature );
7538         ADD_INT( rand_val );
7539
7540         nprintf(("Network","Sending NEW countermeasure packet!\n"));
7541
7542         // determine if its a player ship and don't send to him if we're in "client firing" mode
7543         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7544         if(MULTIPLAYER_MASTER){
7545                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7546                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7547                         ignore = &Net_players[np_index];
7548                 }
7549         }
7550         
7551         // if I'm the server, send to all players
7552         if(MULTIPLAYER_MASTER){                 
7553                 multi_io_send_to_all(data, packet_size, ignore);
7554         } 
7555         // otherwise send to the server
7556         else {
7557                 multi_io_send(Net_player, data, packet_size);
7558         }
7559 }
7560
7561 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7562 {
7563         int offset;
7564         ushort signature;
7565         int rand_val;
7566         object *objp;   
7567
7568         offset = HEADER_LENGTH;
7569         GET_USHORT( signature );
7570         GET_INT( rand_val );
7571         PACKET_SET_SIZE();
7572
7573         objp = multi_get_network_object( signature );
7574         if ( objp == NULL ) {
7575                 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7576                 return;
7577         }
7578         if(objp->type != OBJ_SHIP){
7579                 return;
7580         }       
7581
7582         // if we're in client firing mode, ignore ones for myself
7583         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){         
7584         if((Player_obj != NULL) && (Player_obj == objp)){               
7585                 return;
7586         }
7587                 
7588         // make it so ship can fire right away!
7589         Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7590         if ( objp == Player_obj ){              
7591                 nprintf(("network", "firing countermeasure from my ship\n"));
7592         }
7593         ship_launch_countermeasure( objp, rand_val );                   
7594 }
7595
7596 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7597 {
7598         ubyte data[MAX_PACKET_SIZE];
7599         int packet_size = 0;    
7600         ubyte u_beam_info;
7601         char subsys_index;
7602         beam_info b_info;
7603
7604         // only the server should ever be doing this
7605         SDL_assert(MULTIPLAYER_MASTER);
7606
7607         // setup outgoing data
7608         SDL_assert(shooter != NULL);
7609         SDL_assert(turret != NULL);
7610         SDL_assert(target != NULL);
7611         SDL_assert(override != NULL);
7612         if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7613                 return;
7614         }
7615         u_beam_info = (ubyte)beam_info_index;
7616         subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7617         SDL_assert(subsys_index >= 0);
7618         if(subsys_index < 0){
7619                 return;
7620         }
7621
7622         // swap the beam_info override info into little endian byte order
7623         b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7624         b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7625         b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7626          
7627         b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7628         b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7629         b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7630          
7631         b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7632         b_info.shot_count = override->shot_count;
7633          
7634         for (int i = 0; i < b_info.shot_count; i++) {
7635                 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7636         }
7637
7638         // build the header
7639         BUILD_HEADER(BEAM_FIRED);
7640         ADD_USHORT(shooter->net_signature);
7641         ADD_DATA(subsys_index);
7642         ADD_USHORT(target->net_signature);
7643         ADD_DATA(u_beam_info);
7644         ADD_DATA(b_info);  // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7645
7646         // send to all clients  
7647         multi_io_send_to_all_reliable(data, packet_size);
7648 }
7649
7650 void process_beam_fired_packet(ubyte *data, header *hinfo)
7651 {
7652         int i,offset;
7653         ushort shooter_sig, target_sig;
7654         char subsys_index;
7655         ubyte u_beam_info;
7656         beam_info b_info;
7657         beam_fire_info fire_info;
7658
7659         // only clients should ever get this
7660         SDL_assert(MULTIPLAYER_CLIENT);
7661
7662         // read in packet data
7663         offset = HEADER_LENGTH;
7664         GET_USHORT(shooter_sig);
7665         GET_DATA(subsys_index);
7666         GET_USHORT(target_sig);
7667         GET_DATA(u_beam_info);
7668         GET_DATA(b_info);
7669
7670         PACKET_SET_SIZE();
7671
7672         // swap the beam_info override info into native byte order
7673         b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7674         b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7675         b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7676         b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7677         b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7678         b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7679         b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7680
7681         for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7682                 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7683         }
7684
7685         // lookup all relevant data
7686         fire_info.beam_info_index = (int)u_beam_info;
7687         fire_info.shooter = NULL;
7688         fire_info.target = NULL;
7689         fire_info.turret = NULL;
7690         fire_info.target_subsys = NULL;
7691         fire_info.beam_info_override = NULL;            
7692         fire_info.shooter = multi_get_network_object(shooter_sig);
7693         fire_info.target = multi_get_network_object(target_sig);
7694         fire_info.beam_info_override = &b_info;
7695         fire_info.accuracy = 1.0f;
7696         if((fire_info.shooter == NULL) || (fire_info.shooter->type != OBJ_SHIP) || (fire_info.shooter->instance < 0) || (fire_info.shooter->instance > MAX_SHIPS) || (fire_info.target == NULL)){
7697                 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7698                 return;
7699         }
7700         fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7701         if(fire_info.turret == NULL){
7702                 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7703                 return;
7704         }
7705
7706         // fire da beam
7707         beam_fire(&fire_info);
7708 }
7709
7710 void send_sw_query_packet(ubyte code, char *txt)
7711 {
7712         ubyte data[MAX_PACKET_SIZE];
7713         int packet_size = 0;
7714
7715         // build the packet and add the code
7716         BUILD_HEADER(SW_STD_QUERY);
7717         ADD_DATA(code);
7718         if((code == SW_STD_START) || (code == SW_STD_BAD)){             
7719                 ADD_STRING(txt);
7720         }
7721
7722         // if I'm the host, send to standalone
7723         if(MULTIPLAYER_HOST){
7724                 SDL_assert(!MULTIPLAYER_MASTER);
7725                 SDL_assert(code == SW_STD_START);               
7726                 multi_io_send_reliable(Net_player, data, packet_size);
7727         }
7728         // otherwise standalone sends back to host
7729         else {
7730                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7731                 SDL_assert(code != SW_STD_START);
7732                 SDL_assert(Netgame.host != NULL);
7733                 if(Netgame.host != NULL){                       
7734                         multi_io_send_reliable(Netgame.host, data, packet_size);
7735                 }
7736         }
7737 }
7738
7739 void process_sw_query_packet(ubyte *data, header *hinfo)
7740 {       
7741 }
7742
7743 void send_event_update_packet(int event)
7744 {
7745         ubyte data[MAX_PACKET_SIZE];
7746         ushort u_event = (ushort)event;
7747         int packet_size = 0;
7748
7749         // build the header and add the event
7750         BUILD_HEADER(EVENT_UPDATE);
7751         ADD_USHORT(u_event);
7752         ADD_INT(Mission_events[event].flags);
7753         ADD_INT(Mission_events[event].formula);
7754         ADD_INT(Mission_events[event].result);
7755         ADD_INT(Mission_events[event].count);
7756
7757         // send to all players  
7758         multi_io_send_to_all_reliable(data, packet_size);
7759 }
7760
7761 void process_event_update_packet(ubyte *data, header *hinfo)
7762 {
7763         int offset = HEADER_LENGTH;
7764         int store_flags;
7765         ushort u_event;
7766         
7767         // get the data
7768         GET_USHORT(u_event);
7769         store_flags = Mission_events[u_event].flags;
7770         GET_INT(Mission_events[u_event].flags);
7771         GET_INT(Mission_events[u_event].formula);
7772         GET_INT(Mission_events[u_event].result);
7773         GET_INT(Mission_events[u_event].count);
7774         PACKET_SET_SIZE();
7775
7776         // went from non directive special to directive special
7777         if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7778                 mission_event_set_directive_special(u_event);
7779         }
7780         // if we went directive special to non directive special
7781         else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7782                 mission_event_unset_directive_special(u_event);
7783         }       
7784 }
7785
7786 // weapon detonate packet
7787 void send_weapon_detonate_packet(object *objp)
7788 {
7789         ubyte data[MAX_PACKET_SIZE];
7790         int packet_size = 0;
7791
7792         // sanity checks
7793         SDL_assert(MULTIPLAYER_MASTER);
7794         if(!MULTIPLAYER_MASTER){
7795                 return;
7796         }
7797         SDL_assert(objp != NULL);
7798         if(objp == NULL){
7799                 return;
7800         }
7801
7802         // build the header and add the data
7803         BUILD_HEADER(WEAPON_DET);
7804         ADD_USHORT(objp->net_signature);
7805
7806         // send to all players
7807         multi_io_send_to_all(data, packet_size);
7808 }
7809
7810 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7811 {
7812         ushort net_sig;
7813         int offset = HEADER_LENGTH;
7814         object *objp = NULL;
7815
7816         // get the weapon signature
7817         GET_USHORT(net_sig);
7818         PACKET_SET_SIZE();
7819
7820         // lookup the weapon
7821         objp = multi_get_network_object(net_sig);
7822         if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7823                 weapon_detonate(objp);
7824         }
7825 }       
7826
7827 // flak fired packet
7828 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7829 {
7830         int packet_size;
7831         ushort pnet_signature;
7832         ubyte data[MAX_PACKET_SIZE], cindex;
7833         object *objp;   
7834         ship_subsys *ssp;
7835         short val;
7836
7837         // sanity
7838         if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7839                 return;
7840         }
7841
7842         // local setup -- be sure we are actually passing a weapon!!!!
7843         objp = &Objects[weapon_objnum];
7844         SDL_assert ( objp->type == OBJ_WEAPON );        
7845         pnet_signature = Objects[ship_objnum].net_signature;
7846
7847         SDL_assert( subsys_index < UCHAR_MAX );
7848         cindex = (ubyte)subsys_index;
7849
7850         ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7851         if(ssp == NULL){
7852                 return;
7853         }
7854
7855         // build the fire turret packet.  
7856         BUILD_HEADER(FLAK_FIRED);       
7857         packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7858         ADD_USHORT( pnet_signature );           
7859         ADD_DATA( cindex );
7860         val = (short)ssp->submodel_info_1.angs.h;
7861         ADD_SHORT( val );
7862         val = (short)ssp->submodel_info_2.angs.p;
7863         ADD_SHORT( val );       
7864         ADD_FLOAT( flak_range );
7865         
7866         multi_io_send_to_all(data, packet_size);
7867
7868         multi_rate_add(1, "flk", packet_size);
7869 }
7870
7871 void process_flak_fired_packet(ubyte *data, header *hinfo)
7872 {
7873         int offset, weapon_objnum, wid;
7874         ushort pnet_signature;
7875         vector pos, dir;
7876         matrix orient;
7877         vector o_fvec;
7878         ubyte turret_index;
7879         object *objp;
7880         ship_subsys *ssp;       
7881         ship *shipp;
7882         short pitch, heading;
7883         float flak_range;
7884
7885         // get the data for the turret fired packet
7886         offset = HEADER_LENGTH;         
7887         offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7888         GET_USHORT( pnet_signature );
7889         GET_DATA( turret_index );
7890         GET_SHORT( heading );
7891         GET_SHORT( pitch );     
7892         GET_FLOAT( flak_range );
7893         PACKET_SET_SIZE();                              // move our counter forward the number of bytes we have read
7894
7895         // find the object
7896         objp = multi_get_network_object( pnet_signature );
7897         if ( objp == NULL ) {
7898                 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7899                 return;
7900         }
7901
7902         // if this isn't a ship, do nothing
7903         if ( objp->type != OBJ_SHIP ){
7904                 return;
7905         }
7906
7907         // make an orientation matrix from the o_fvec
7908         vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7909
7910         // find this turret, and set the position of the turret that just fired to be where it fired.  Quite a
7911         // hack, but should be suitable.
7912         shipp = &Ships[objp->instance];
7913         ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7914         if(ssp == NULL){
7915                 return;
7916         }
7917         wid = ssp->system_info->turret_weapon_type;
7918         if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7919                 return;
7920         }
7921
7922         // bash the position and orientation of the turret
7923         ssp->submodel_info_1.angs.h = (float)heading;
7924         ssp->submodel_info_2.angs.p = (float)pitch;
7925
7926         // get the world position of the weapon
7927         ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7928
7929         // create the weapon object     
7930         weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7931         if (weapon_objnum != -1) {
7932                 if ( Weapon_info[wid].launch_snd != -1 ) {
7933                         snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7934                 }
7935
7936                 // create a muzzle flash from a flak gun based upon firing position and weapon type
7937                 flak_muzzle_flash(&pos, &dir, wid);
7938
7939                 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7940                 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7941         }
7942 }
7943
7944 #define ADD_NORM_VEC(d) do { SDL_assert((packet_size + 3) < MAX_PACKET_SIZE); char vnorm[3] = { (char)(d.x * 127.0f), (char)(d.y * 127.0f), (char)(d.z * 127.0f) }; memcpy(data + packet_size, vnorm, 3); packet_size += 3; } while(0);
7945 #define GET_NORM_VEC(d) do { char vnorm[3]; memcpy(vnorm, data+offset, 3); d.x = (float)vnorm[0] / 127.0f; d.y = (float)vnorm[1] / 127.0f; d.z = (float)vnorm[2] / 127.0f; } while(0);
7946
7947 // player pain packet
7948 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7949 {
7950         ubyte data[MAX_PACKET_SIZE];
7951         ubyte windex;
7952         ushort udamage;
7953         int packet_size = 0;
7954
7955         SDL_assert(MULTIPLAYER_MASTER);
7956         if(!MULTIPLAYER_MASTER){
7957                 return;
7958         }
7959         SDL_assert(pl != NULL);
7960         if(pl == NULL){
7961                 return;
7962         }
7963
7964         // build the packet and add the code
7965         BUILD_HEADER(NETPLAYER_PAIN);
7966         windex = (ubyte)weapon_info_index;
7967         ADD_DATA(windex);
7968         udamage = (ushort)damage;
7969         ADD_USHORT(udamage);
7970         //ADD_DATA((*force));
7971         add_vector_data( data, &packet_size, *force );
7972         //ADD_DATA((*hitpos));
7973         add_vector_data( data, &packet_size, *hitpos );
7974
7975         // send to the player
7976         multi_io_send(pl, data, packet_size);
7977
7978         multi_rate_add(1, "pai", packet_size);
7979 }       
7980
7981 void process_player_pain_packet(ubyte *data, header *hinfo)
7982 {
7983         int offset;
7984         ubyte windex;
7985         ushort udamage;
7986         vector force = ZERO_VECTOR;
7987         vector local_hit_pos = ZERO_VECTOR;
7988         weapon_info *wip;
7989
7990         // get the data for the pain packet
7991         offset = HEADER_LENGTH;         
7992         GET_DATA(windex);
7993         GET_USHORT(udamage);
7994         //GET_DATA(force);
7995         get_vector_data( data, &offset, force );
7996         //GET_DATA(local_hit_pos);
7997         get_vector_data( data, &offset, local_hit_pos );
7998         PACKET_SET_SIZE();
7999
8000         mprintf(("PAIN!\n"));
8001
8002         // get weapon info pointer
8003         //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER));        // always true
8004         if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
8005                 return;
8006         }
8007         wip = &Weapon_info[windex];
8008
8009         // play the weapon hit sound
8010         SDL_assert(Player_obj != NULL);
8011         if(Player_obj == NULL){
8012                 return;
8013         }
8014         weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
8015
8016         // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
8017         ship_hit_pain((float)udamage);
8018
8019         // apply the whack      
8020         ship_apply_whack(&force, &local_hit_pos, Player_obj);   
8021 }
8022
8023 // lightning packet
8024 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8025 {
8026         ubyte data[MAX_PACKET_SIZE];
8027         char val;
8028         int packet_size = 0;
8029
8030         // build the header and add the data
8031         BUILD_HEADER(LIGHTNING_PACKET);
8032         val = (char)bolt_type;
8033         ADD_DATA(val);
8034         //ADD_DATA((*start));
8035         add_vector_data( data, &packet_size, *start );
8036         //ADD_DATA((*strike));
8037         add_vector_data( data, &packet_size, *strike );
8038
8039         // send to everyone unreliable for now
8040         multi_io_send_to_all(data, packet_size);
8041 }
8042
8043 void process_lightning_packet(ubyte *data, header *hinfo)
8044 {
8045         int offset;
8046         char bolt_type;
8047         vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8048
8049         // read the data
8050         offset = HEADER_LENGTH;
8051         GET_DATA(bolt_type);
8052 //      GET_DATA(start);
8053         get_vector_data(data, &offset, start);
8054 //      GET_DATA(strike);
8055         get_vector_data(data, &offset, strike);
8056         PACKET_SET_SIZE();
8057
8058         // invalid bolt?
8059         if(bolt_type < 0){
8060                 return;
8061         }
8062
8063         // fire it up
8064         nebl_bolt(bolt_type, &start, &strike);
8065 }
8066
8067 void send_bytes_recvd_packet(net_player *pl)
8068 {
8069         // only clients should ever be doing this
8070         if(pl == NULL){
8071                 return;
8072         }       
8073
8074         ubyte data[MAX_PACKET_SIZE];
8075         int packet_size = 0;
8076         BUILD_HEADER(BYTES_SENT);
8077         ADD_INT(pl->cl_bytes_recvd);
8078
8079         // send to the server
8080         multi_io_send_reliable(pl, data, packet_size);
8081 }
8082
8083 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8084 {
8085         int bytes;
8086         int pid;
8087         net_player *pl = NULL;
8088         int offset = HEADER_LENGTH;
8089         
8090         GET_INT(bytes);
8091         PACKET_SET_SIZE();
8092
8093         // not server?
8094         if(Net_player == NULL){
8095                 return;
8096         }
8097         if(!MULTIPLAYER_MASTER){
8098                 return;
8099         }
8100
8101         // make sure we know what player sent this
8102         pid = find_player_id(hinfo->id);
8103         if((pid < 0) || (pid >= MAX_PLAYERS)){
8104                 return;
8105         }
8106         pl = &Net_players[pid];
8107
8108         // compute his pl
8109         pl->cl_bytes_recvd = bytes;
8110         if(bytes < 0){
8111                 return;
8112         }
8113         pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8114
8115         // reset bytes sent
8116         pl->sv_bytes_sent = 0;
8117 }
8118
8119 // host transfer
8120 void send_host_captain_change_packet(short player_id, int captain_change)
8121 {
8122         ubyte data[MAX_PACKET_SIZE];
8123         int packet_size = 0;
8124
8125         // build the packet
8126         BUILD_HEADER(TRANSFER_HOST);
8127         ADD_SHORT(player_id);
8128         ADD_INT(captain_change);
8129
8130         // send to all
8131         multi_io_send_to_all_reliable(data, packet_size);
8132 }
8133
8134 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8135 {
8136         int offset = HEADER_LENGTH;
8137         int idx, found_player, captain_change;
8138         short player_id;
8139
8140         // get the player id
8141         GET_SHORT(player_id);
8142         GET_INT(captain_change);
8143         PACKET_SET_SIZE();
8144
8145         // captain change
8146         if(captain_change){
8147                 // flag the new guy             
8148                 for(idx=0; idx<MAX_PLAYERS; idx++){
8149                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8150                                 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8151                                 break;
8152                         }
8153                 }
8154         } else {
8155                 // unflag all old players
8156                 for(idx=0; idx<MAX_PLAYERS; idx++){
8157                         Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8158                 }
8159
8160                 // flag the new guy
8161                 found_player = 0;
8162                 for(idx=0; idx<MAX_PLAYERS; idx++){
8163                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8164                                 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8165
8166                                 // spew to the HUD config
8167                                 if(Net_players[idx].player != NULL){
8168                                         HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8169                                 }
8170
8171                                 found_player = 1;
8172                                 break;
8173                         }
8174                 }
8175
8176                 // doh
8177                 if(!found_player){
8178                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8179                 }
8180         }       
8181 }
8182
8183 void send_self_destruct_packet()
8184 {
8185         ubyte data[MAX_PACKET_SIZE];
8186         int packet_size = 0;
8187
8188         // bogus
8189         if(Net_player == NULL){
8190                 return;
8191         }
8192
8193         // if i'm the server, I shouldn't be here
8194         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8195         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8196                 return;
8197         }
8198         
8199         // only if this is valid
8200         if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8201                 return;
8202         }
8203
8204         // bogus object?
8205         if((Player_ship == NULL) || (Player_obj == NULL)){
8206                 return;
8207         }
8208
8209         // self destruct
8210         BUILD_HEADER(SELF_DESTRUCT);
8211         ADD_USHORT(Player_obj->net_signature);
8212
8213         // send to the server
8214         multi_io_send_reliable(Net_player, data, packet_size);
8215 }
8216
8217 void process_self_destruct_packet(ubyte *data, header *hinfo)
8218 {
8219         int offset = HEADER_LENGTH;
8220         ushort net_sig;
8221         int np_index;
8222
8223         // get the net signature
8224         GET_USHORT(net_sig);
8225         PACKET_SET_SIZE();
8226
8227         // get the player
8228         np_index = find_player_id(hinfo->id);
8229         if(np_index < 0){
8230                 return;
8231         }
8232         if(MULTI_OBSERVER(Net_players[np_index])){
8233                 return;
8234         }
8235         if(Net_players[np_index].player == NULL){
8236                 return;
8237         }
8238         if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8239                 return;
8240         }
8241         if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8242                 return;
8243         }
8244         if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8245                 return;
8246         }
8247         if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8248                 return;
8249         }
8250
8251         // do eet
8252         ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);
8253 }