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