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