]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multimsgs.cpp
avoid sending LAN broadcast with PXO game query
[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                 return;
2386         } else {
2387                 // go through the server list and query each of those as well
2388                 s_moveup = Game_server_head;
2389                 if(s_moveup != NULL){
2390                         do {
2391                                 send_server_query(&s_moveup->server_addr);
2392                                 s_moveup = s_moveup->next;
2393                         } while(s_moveup != Game_server_head);
2394                 }
2395         }
2396
2397         fill_net_addr(&addr, Psnet_my_addr.addr, DEFAULT_GAME_PORT);
2398
2399         // send out a broadcast if our options allow us
2400         if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2401                 psnet_broadcast( &addr, data, packet_size);
2402         }               
2403 }
2404
2405 // send an individual query to an address to see if there is an active game
2406 void send_server_query(net_addr *addr)
2407 {
2408         int packet_size;        
2409         ubyte data[MAX_PACKET_SIZE];
2410
2411         // build the header and send the data
2412         BUILD_HEADER(GAME_QUERY);                               
2413         psnet_send(addr, data, packet_size);
2414 }
2415
2416 // process a query from a client looking for active freespace games
2417 void process_game_query(ubyte* data, header* hinfo)
2418 {
2419         int offset;     
2420         net_addr addr;
2421
2422         offset = HEADER_LENGTH;
2423
2424         PACKET_SET_SIZE();
2425
2426         // check to be sure that we don't capture our own broadcast message
2427         fill_net_addr(&addr, hinfo->addr, hinfo->port);
2428         if ( psnet_same( &addr, &Psnet_my_addr) ){
2429                 return;
2430         }
2431
2432         // if I am not a server of a game, don't send a reply!!!
2433         if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2434                 return;
2435         }
2436
2437         // if the game options are being selected, then ignore the request
2438         // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2439         if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2440                 return;
2441         }
2442
2443         // send information about this active game
2444         send_game_active_packet(&addr);
2445 }
2446
2447 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2448 void send_netplayer_update_packet( net_player *pl )
2449 {
2450         int packet_size,idx;
2451         ubyte data[MAX_PACKET_SIZE],val;
2452
2453         BUILD_HEADER(NETPLAYER_UPDATE);
2454
2455         // if I'm the server of the game, I should send an update for _all_players in the game
2456         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2457                 for(idx=0;idx<MAX_PLAYERS;idx++){
2458                         // only send info for connected players
2459                         if(MULTI_CONNECTED(Net_players[idx])){
2460                                 // add a stop byte
2461                                 val = 0x0;
2462                                 ADD_DATA(val);
2463
2464                                 // add the net player's information
2465                                 ADD_SHORT(Net_players[idx].player_id);
2466                                 ADD_INT(Net_players[idx].state);
2467                                 ADD_INT(Net_players[idx].p_info.ship_class);                            
2468                                 ADD_INT(Net_players[idx].tracker_player_id);
2469
2470                                 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2471                                         val = 1;
2472                                 } else {
2473                                         val = 0;
2474                                 }
2475                                 ADD_DATA(val);                          
2476                         }
2477                 }
2478                 // add the final stop byte
2479                 val = 0xff;
2480                 ADD_DATA(val);
2481
2482                 // broadcast the packet
2483                 if(!(Game_mode & GM_IN_MISSION)){
2484                         if ( pl == NULL ) {
2485                                 multi_io_send_to_all_reliable(data, packet_size);                               
2486                         } else {
2487                                 multi_io_send_reliable(pl, data, packet_size);
2488                         }
2489                 } else {
2490                         if ( pl == NULL ) {
2491                                 multi_io_send_to_all(data, packet_size);
2492                         } else {                                
2493                                 multi_io_send(pl, data, packet_size);
2494                         }
2495                 }
2496         } else {
2497                 // add a stop byte
2498                 val = 0x0;
2499                 ADD_DATA(val);
2500
2501                 // add my current state in the netgame to this packet
2502                 ADD_SHORT(Net_player->player_id);
2503                 ADD_INT(Net_player->state);
2504                 ADD_INT(Net_player->p_info.ship_class);         
2505                 ADD_INT(Multi_tracker_id);
2506
2507                 // add if I have a CD or not
2508                 if(Multi_has_cd){
2509                         val = 1;
2510                 } else {
2511                         val = 0;
2512                 }
2513                 ADD_DATA(val);          
2514
2515                 // add a final stop byte
2516                 val = 0xff;
2517                 ADD_DATA(val);
2518
2519                 // send the packet to the server
2520                 SDL_assert( pl == NULL );                                               // shouldn't ever be the case that pl is non-null here.
2521                 if(!(Game_mode & GM_IN_MISSION)){                       
2522                         multi_io_send_reliable(Net_player, data, packet_size);
2523                 } else {                        
2524                         multi_io_send(Net_player, data, packet_size);
2525                 }
2526         }       
2527 }
2528
2529 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2530 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2531 {
2532         int offset, player_num;
2533         net_player bogus;
2534         ubyte stop, has_cd;
2535         short player_id;
2536         int new_state;
2537         
2538         offset = HEADER_LENGTH;
2539
2540         // get the first stop byte
2541         GET_DATA(stop);
2542         player_num = -1;
2543         while(stop != 0xff){
2544                 // look the player up
2545                 GET_SHORT(player_id);
2546                 player_num = find_player_id(player_id);
2547                 // if we couldn't find him, read in the bogus data
2548                 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2549                         GET_INT(bogus.state);
2550                         GET_INT(bogus.p_info.ship_class);                       
2551                         GET_INT(bogus.tracker_player_id);
2552
2553                         GET_DATA(has_cd);                       
2554                 } 
2555                 // otherwise read in the data correctly
2556                 else {
2557                         GET_INT(new_state);
2558                         GET_INT(Net_players[player_num].p_info.ship_class);                     
2559                         GET_INT(Net_players[player_num].tracker_player_id);
2560                         GET_DATA(has_cd);
2561                         if(has_cd){
2562                                 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2563                         } else {
2564                                 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2565                         }                       
2566
2567                         // if he's changing state to joined, send a team update
2568                         if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2569                                 multi_team_send_update();
2570                         }
2571
2572                         // set state
2573                         Net_players[player_num].state = new_state;
2574                 }
2575
2576                 // get the next stop byte
2577                 GET_DATA(stop);
2578         }
2579
2580         PACKET_SET_SIZE();      
2581
2582         // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2583         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2584                 send_netplayer_update_packet(NULL);
2585         }
2586
2587         // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2588         if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2589                 switch(Net_players[player_num].state){
2590                 case NETPLAYER_STATE_STD_HOST_SETUP:
2591                         Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2592                         break;
2593                 
2594                 case NETPLAYER_STATE_HOST_SETUP:
2595                         // check for race conditions
2596                         if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2597                                 Netgame.game_state = NETGAME_STATE_FORMING;
2598                         }
2599                         break;          
2600                 }
2601         }
2602 }
2603
2604 #define EXTRA_DEATH_VAPORIZED           (1<<0)
2605 #define EXTRA_DEATH_WASHED                      (1<<1)
2606 // send a packet indicating a ship has been killed
2607 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2608 {
2609         int packet_size, model;
2610         ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2611         ushort debris_signature;
2612         ubyte sd;
2613         polymodel * pm;
2614
2615         // only sendable from the master
2616         SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2617
2618         // special deaths
2619         vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2620
2621         extra_death_info = 0; 
2622         if ( vaporized ) {
2623                 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2624         }
2625
2626         if ( Ships[objp->instance].wash_killed ) {
2627                 extra_death_info |= EXTRA_DEATH_WASHED;
2628         }
2629
2630         // find out the next network signature that will be used for the debris pieces.
2631         model = Ships[objp->instance].modelnum;
2632         pm = model_get(model);
2633         debris_signature = 0;
2634         if ( pm && !vaporized ) {
2635                 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2636                 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2637                 Ships[objp->instance].arrival_distance = debris_signature;
2638         }
2639
2640         BUILD_HEADER(SHIP_KILL);
2641         ADD_USHORT(objp->net_signature);
2642
2643         // ships which are initially killed get the rest of the data sent.  self destructed ships and
2644         if ( other_objp == NULL ) {
2645                 ushort temp;
2646
2647                 temp = 0;
2648                 ADD_USHORT(temp);
2649                 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2650         } else {
2651                 ADD_USHORT( other_objp->net_signature );
2652         }
2653
2654         ADD_USHORT( debris_signature );
2655         ADD_FLOAT( percent_killed );
2656         sd = (ubyte)self_destruct;
2657         ADD_DATA(sd);
2658         ADD_DATA( extra_death_info );
2659
2660         // if the ship who died is a player, then send some extra info, like who killed him, etc.
2661         was_player = 0;
2662         if ( objp->flags & OF_PLAYER_SHIP ) {
2663                 int pnum;
2664                 char temp;
2665
2666                 pnum = multi_find_player_by_object( objp );
2667                 if ( pnum != -1 ) {
2668                         was_player = 1;
2669                         ADD_DATA( was_player );
2670
2671                         SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX); 
2672                         temp = (char)Net_players[pnum].player->killer_objtype;
2673                         ADD_DATA( temp );
2674
2675                         SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX); 
2676                         temp = (char)Net_players[pnum].player->killer_species;
2677                         ADD_DATA( temp );
2678
2679                         SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX); 
2680                         temp = (char)Net_players[pnum].player->killer_weapon_index;
2681                         ADD_DATA( temp );
2682
2683                         ADD_STRING( Net_players[pnum].player->killer_parent_name );
2684                 } else {
2685                         ADD_DATA( was_player );
2686                 }
2687         } else {
2688                 ADD_DATA( was_player );
2689         }
2690
2691         // send the packet reliably!!!
2692         multi_io_send_to_all_reliable(data, packet_size);       
2693 }
2694
2695 // process a packet indicating that a ship has been killed
2696 void process_ship_kill_packet( ubyte *data, header *hinfo )
2697 {
2698         int offset;
2699         ushort ship_sig, other_sig, debris_sig;
2700         object *sobjp, *oobjp;
2701         float percent_killed;   
2702         ubyte was_player, extra_death_info, sd;
2703         char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2704
2705         offset = HEADER_LENGTH;
2706         GET_USHORT(ship_sig);
2707
2708         GET_USHORT( other_sig );
2709         GET_USHORT( debris_sig );
2710         GET_FLOAT( percent_killed );
2711         GET_DATA( sd );
2712         GET_DATA( extra_death_info );
2713         GET_DATA( was_player );
2714
2715
2716         // pnum is >=0 when the dying ship is a pleyer ship.  Get the info about how he died
2717         if ( was_player != 0 ) {
2718                 GET_DATA( killer_objtype );
2719                 GET_DATA( killer_species );
2720                 GET_DATA( killer_weapon_index );
2721                 GET_STRING( killer_name );
2722         }
2723
2724         PACKET_SET_SIZE();
2725
2726         sobjp = multi_get_network_object( ship_sig );
2727
2728         // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2729         // another message from the server that this happened!
2730         if ( sobjp == NULL ) {
2731                 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));             
2732                 return;
2733         }
2734
2735         // set this ship's hull value to 0
2736         sobjp->hull_strength = 0.0f;
2737
2738         // maybe set vaporized
2739         if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2740                 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2741         }
2742
2743         // maybe set wash_killed
2744         if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2745                 Ships[sobjp->instance].wash_killed = 1;
2746         }
2747
2748         oobjp = multi_get_network_object( other_sig );
2749
2750         if ( was_player != 0 ) {
2751                 int pnum;
2752
2753                 pnum = multi_find_player_by_object( sobjp );
2754                 if ( pnum != -1 ) {
2755                         Net_players[pnum].player->killer_objtype = killer_objtype;
2756                         Net_players[pnum].player->killer_species = killer_species;
2757                         Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2758                         SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2759                 }
2760         }          
2761
2762         // check to see if I need to respawn myself
2763         multi_respawn_check(sobjp);
2764
2765         // store the debris signature in the arrival distance which will never get used for player ships
2766         Ships[sobjp->instance].arrival_distance = debris_sig;
2767
2768         // set this bit so that we don't accidentally start switching targets when we die
2769         if(sobjp == Player_obj){
2770                 Game_mode |= GM_DEAD_DIED;
2771         }
2772
2773         nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2774
2775         // do the normal thing when not ingame joining.  When ingame joining, simply kill off the ship.
2776         if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2777                 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2778         } else {
2779                 extern void ship_destroyed( int shipnum );
2780                 ship_destroyed( sobjp->instance );
2781                 sobjp->flags |= OF_SHOULD_BE_DEAD;
2782                 obj_delete( OBJ_INDEX(sobjp) );
2783         }
2784 }
2785
2786 // send a packet indicating a ship should be created
2787 void send_ship_create_packet( object *objp, int is_support )
2788 {
2789         int packet_size;
2790         ubyte data[MAX_PACKET_SIZE];
2791
2792         // We will pass the ship to create by name.
2793         BUILD_HEADER(SHIP_CREATE);
2794         ADD_USHORT(objp->net_signature);
2795         ADD_INT( is_support );
2796         if ( is_support ){
2797                 add_vector_data(data, &packet_size, objp->pos);
2798         }
2799
2800         // broadcast the packet 
2801         multi_io_send_to_all_reliable(data, packet_size);
2802 }
2803
2804 // process a packet indicating a ship should be created
2805 void process_ship_create_packet( ubyte *data, header *hinfo )
2806 {
2807         int offset, objnum, is_support;
2808         ushort signature;
2809         p_object *objp;
2810         vector pos = ZERO_VECTOR;
2811
2812         SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2813         offset = HEADER_LENGTH;
2814         GET_USHORT(signature);
2815         GET_INT( is_support );
2816         if ( is_support ){
2817                 get_vector_data(data, &offset, pos);
2818         }
2819
2820         PACKET_SET_SIZE();
2821
2822         // find the name of this ship on ship ship arrival list.  if found, pass it to parse_object_create
2823         if ( !is_support ) {
2824                 objp = mission_parse_get_arrival_ship( signature );
2825                 if ( objp != NULL ) {
2826                         parse_create_object(objp);
2827                 } else {
2828                         nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2829                 }
2830         } else {
2831                 SDL_assert( Arriving_support_ship );
2832                 if(Arriving_support_ship == NULL){
2833                         return;
2834                 }
2835                 Arriving_support_ship->pos = pos;
2836                 Arriving_support_ship->net_signature = signature;
2837                 objnum = parse_create_object( Arriving_support_ship );
2838                 SDL_assert( objnum != -1 );
2839                 if(objnum < 0){
2840                         mission_parse_support_arrived( objnum );
2841                 }
2842         }
2843 }
2844
2845 // send a packet indicating a wing of ships should be created
2846 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2847 {
2848         int packet_size, index, ship_instance;
2849         ubyte data[MAX_PACKET_SIZE];
2850         ushort signature;
2851         int val;
2852
2853         // for creating wing -- we just send the index into the wing array of this wing.
2854         // all players load the same mission, and so their array's should all match. We also
2855         // need to send the signature of the first ship that was created.  We can find this by
2856         // looking num_to_create places back in the ship_index field in the wing structure.
2857
2858         index = WING_INDEX(wingp);
2859         ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2860         signature = Objects[Ships[ship_instance].objnum].net_signature;
2861
2862         BUILD_HEADER( WING_CREATE );
2863         ADD_INT(index);
2864         ADD_INT(num_to_create);
2865         ADD_USHORT(signature);          
2866         ADD_INT(pre_create_count);
2867         val = wingp->current_wave - 1;
2868         ADD_INT(val);
2869         
2870         multi_io_send_to_all_reliable(data, packet_size);       
2871 }
2872
2873 // process a packet saying that a wing should be created
2874 void process_wing_create_packet( ubyte *data, header *hinfo )
2875 {
2876         int offset, index, num_to_create;
2877         ushort signature;
2878         int total_arrived_count, current_wave;
2879
2880         offset = HEADER_LENGTH;
2881         GET_INT(index);
2882         GET_INT(num_to_create);
2883         GET_USHORT(signature);
2884         GET_INT(total_arrived_count);
2885         GET_INT(current_wave);
2886
2887         PACKET_SET_SIZE();
2888
2889         // do a sanity check on the wing to be sure that we are actually working on a valid wing
2890         if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2891                 nprintf(("Network", "invalid index %d for wing create packet\n"));
2892                 return;
2893         }
2894         if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2895                 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2896                 return;
2897         }
2898
2899         // bash some info
2900         Wings[index].current_count = 0;
2901         Wings[index].total_arrived_count = total_arrived_count;
2902         Wings[index].current_wave = current_wave;
2903
2904         // set the network signature that was passed.  The client should create ships in the same order
2905         // as the server -- so all ships should get the same sigs as assigned by the server.  We also
2906         // need to set some timestamps and cues correctly to be sure that these things get created on
2907         // the clients correctly
2908         multi_set_network_signature( signature, MULTI_SIG_SHIP );
2909         parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2910 }
2911
2912 // packet indicating a ship is departing
2913 void send_ship_depart_packet( object *objp )
2914 {
2915         ubyte data[MAX_PACKET_SIZE];
2916         int packet_size;
2917         ushort signature;
2918
2919         signature = objp->net_signature;
2920
2921         BUILD_HEADER(SHIP_DEPART);
2922         ADD_USHORT( signature );
2923         
2924         multi_io_send_to_all_reliable(data, packet_size);
2925 }
2926
2927 // process a packet indicating a ship is departing
2928 void process_ship_depart_packet( ubyte *data, header *hinfo )
2929 {
2930         int offset;
2931         object *objp;
2932         ushort signature;
2933
2934         offset = HEADER_LENGTH;
2935         GET_USHORT( signature );
2936         PACKET_SET_SIZE();
2937
2938         // find the object which is departing
2939         objp = multi_get_network_object( signature );
2940         if ( objp == NULL ) {
2941                 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2942                 return;
2943         }
2944
2945         // start warping him out
2946         shipfx_warpout_start( objp );
2947 }
2948
2949 // packet to tell clients cargo of a ship was revealed to all
2950 void send_cargo_revealed_packet( ship *shipp )
2951 {
2952         ubyte data[MAX_PACKET_SIZE];
2953         int packet_size;
2954
2955         // build the header and add the data
2956         BUILD_HEADER(CARGO_REVEALED);
2957         ADD_USHORT( Objects[shipp->objnum].net_signature );
2958
2959         // server sends to all players
2960         if(MULTIPLAYER_MASTER){         
2961                 multi_io_send_to_all_reliable(data, packet_size);
2962         } 
2963         // clients just send to the server
2964         else {
2965                 multi_io_send_reliable(Net_player, data, packet_size);
2966         }
2967 }
2968
2969 // process a cargo revealed packet
2970 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2971 {
2972         int offset;
2973         ushort signature;
2974         object *objp;
2975
2976         offset = HEADER_LENGTH;
2977         GET_USHORT(signature);
2978         PACKET_SET_SIZE();
2979
2980         // get a ship pointer and call the ship function to reveal the cargo
2981         objp = multi_get_network_object( signature );
2982         if ( objp == NULL ) {
2983                 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2984                 return;
2985         }
2986
2987         // SDL_assert( objp->type == OBJ_SHIP );
2988         if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2989                 return;
2990         }
2991
2992         // this will take care of re-routing to all other clients
2993         ship_do_cargo_revealed( &Ships[objp->instance], 1);     
2994
2995         // server should rebroadcast
2996         if(MULTIPLAYER_MASTER){
2997                 send_cargo_revealed_packet(&Ships[objp->instance]);
2998         }
2999 }
3000
3001 // defines used for secondary fire packet
3002 #define SFPF_ALLOW_SWARM                (1<<7)
3003 #define SFPF_DUAL_FIRE                  (1<<6)
3004 #define SFPF_TARGET_LOCKED              (1<<5)
3005
3006 // send a packet indicating a secondary weapon was fired
3007 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
3008 {
3009         int packet_size, net_player_num;
3010         ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
3011         object *objp;
3012         ushort target_signature;
3013         char t_subsys;
3014         ai_info *aip;
3015
3016         // SDL_assert ( starting_count < UCHAR_MAX );
3017
3018         // get the object for this ship.  If it is an AI object, send all the info to all player.  Otherwise,
3019         // we might send the info to the other player different than the one who fired
3020         objp = &Objects[shipp->objnum];
3021         if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3022                 if ( num_fired == 0 ) {
3023                         return;
3024                 }
3025         }
3026
3027         aip = &Ai_info[shipp->ai_index];
3028
3029         current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3030         //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );    // always true
3031
3032         // build up the header portion
3033         BUILD_HEADER( SECONDARY_FIRED_AI );
3034
3035         ADD_USHORT( Objects[shipp->objnum].net_signature );
3036         ADD_USHORT( starting_sig );
3037         
3038         // add a couple of bits for swarm missiles and dual fire secondary weaspons
3039         sinfo = 0;
3040
3041         sinfo = current_bank;
3042
3043         if ( allow_swarm ){
3044                 sinfo |= SFPF_ALLOW_SWARM;
3045         }
3046
3047         if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3048                 sinfo |= SFPF_DUAL_FIRE;
3049         }
3050
3051         if ( aip->current_target_is_locked ){
3052                 sinfo |= SFPF_TARGET_LOCKED;
3053         }
3054
3055         ADD_DATA( sinfo );
3056
3057         // add the ship's target and any targeted subsystem
3058         target_signature = 0;
3059         t_subsys = -1;
3060         if ( aip->target_objnum != -1) {
3061                 target_signature = Objects[aip->target_objnum].net_signature;
3062                 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3063                         int s_index;
3064
3065                         s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3066                         SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
3067                         t_subsys = (char)s_index;
3068                 }
3069
3070                 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3071                         SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3072                 }
3073
3074         }
3075
3076         ADD_USHORT( target_signature );
3077         ADD_DATA( t_subsys );
3078
3079         // just send this packet to everyone, then bail if an AI ship fired.
3080         if ( !(objp->flags & OF_PLAYER_SHIP) ) {                
3081                 multi_io_send_to_all(data, packet_size);
3082                 return;
3083         }
3084
3085         net_player_num = multi_find_player_by_object( objp );
3086
3087         // getting here means a player fired.  Send the current packet to all players except the player
3088         // who fired.  If nothing got fired, then don't send to the other players -- we will just send
3089         // a packet to the player who will find out that he didn't fire anything
3090         if ( num_fired > 0 ) {
3091                 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);         
3092         }
3093
3094         // if I (the master) fired, then return
3095         if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3096                 return;
3097         }
3098
3099         // now build up the packet to send to the player who actually fired.
3100         BUILD_HEADER( SECONDARY_FIRED_PLR );
3101         ADD_USHORT(starting_sig);
3102         ADD_DATA( sinfo );
3103
3104         // add the targeting information so that the player's weapons will always home on the correct
3105         // ship
3106         ADD_USHORT( target_signature );
3107         ADD_DATA( t_subsys );
3108         
3109         multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3110 }
3111
3112 /// process a packet indicating a secondary weapon was fired
3113 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3114 {
3115         int offset, allow_swarm, target_objnum_save;
3116         ushort net_signature, starting_sig, target_signature;
3117         ubyte sinfo, current_bank;
3118         object* objp, *target_objp;
3119         ship *shipp;
3120         char t_subsys;
3121         ai_info *aip;
3122         ship_subsys *targeted_subsys_save;
3123
3124         offset = HEADER_LENGTH; // size of the header
3125
3126         // if from_player is false, it means that the secondary weapon info in this packet was
3127         // fired by an ai object (or another player).  from_player == 1 means tha me (the person
3128         // receiving this packet) fired the secondary weapon
3129         if ( !from_player ) {
3130                 GET_USHORT( net_signature );
3131                 GET_USHORT( starting_sig );
3132                 GET_DATA( sinfo );                      // are we firing swarm missiles
3133
3134                 GET_USHORT( target_signature );
3135                 GET_DATA( t_subsys );
3136
3137                 PACKET_SET_SIZE();
3138
3139                 // find the object (based on network signatures) for the object that fired
3140                 objp = multi_get_network_object( net_signature );
3141                 if ( objp == NULL ) {
3142                         nprintf(("Network", "Could not find ship for fire secondary packet!"));
3143                         return;
3144                 }
3145
3146                 // set up the ships current secondary bank and that bank's mode.  Below, we will set the timeout
3147                 // of the next fire time of this bank to 0 so we can fire right away
3148                 shipp = &Ships[objp->instance];
3149
3150         } else {
3151                 GET_USHORT( starting_sig );
3152                 GET_DATA( sinfo );
3153
3154                 GET_USHORT( target_signature );
3155                 GET_DATA( t_subsys );
3156
3157                 PACKET_SET_SIZE();
3158
3159                 // get the object and ship
3160                 objp = Player_obj;
3161                 shipp = Player_ship;
3162         }
3163
3164         // check the allow swarm bit
3165         allow_swarm = 0;
3166         if ( sinfo & SFPF_ALLOW_SWARM ){
3167                 allow_swarm = 1;
3168         }
3169
3170         // set the dual fire properties of the ship
3171         if ( sinfo & SFPF_DUAL_FIRE ){
3172                 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3173         } else {
3174                 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3175         }
3176
3177         // determine whether current target is locked
3178         SDL_assert( shipp->ai_index != -1 );
3179         aip = &Ai_info[shipp->ai_index];
3180         if ( sinfo & SFPF_TARGET_LOCKED ) {
3181                 aip->current_target_is_locked = 1;
3182         } else {
3183                 aip->current_target_is_locked = 0;
3184         }
3185
3186         // find out the current bank
3187         current_bank = (ubyte)(sinfo & 0x3);
3188         //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );    // always true
3189         shipp->weapons.current_secondary_bank = current_bank;
3190
3191         // make it so we can fire this ship's secondary bank immediately!!!
3192         shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3193         shipp->weapons.detonate_weapon_time = timestamp(5000);          // be sure that we don't detonate a remote weapon before it is time.
3194
3195         // set this ship's target and subsystem information.  We will save and restore target and
3196         // targeted subsystem so that we do not accidentally change targets for this player or
3197         // any AI ships on his system.
3198         target_objnum_save = aip->target_objnum;
3199         targeted_subsys_save = aip->targeted_subsys;
3200
3201         // reset these variables for accuracy.  They will get reassigned at the end of this fuction
3202         aip->target_objnum = -1;
3203         aip->targeted_subsys = NULL;
3204
3205         target_objp = multi_get_network_object( target_signature );
3206         if ( target_objp != NULL ) {
3207                 aip->target_objnum = OBJ_INDEX(target_objp);
3208
3209                 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3210                         aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3211                 }
3212         }
3213
3214         if ( starting_sig != 0 ){
3215                 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3216         } else {
3217                 shipp->weapons.detonate_weapon_time = timestamp(0);             // signature of -1 say detonate remote weapon
3218         }
3219
3220         ship_fire_secondary( objp, allow_swarm );
3221
3222         // restore targeted object and targeted subsystem
3223         aip->target_objnum = target_objnum_save;
3224         aip->targeted_subsys = targeted_subsys_save;
3225 }
3226
3227 // send a packet indicating a countermeasure was fired
3228 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3229 {
3230         ubyte data[MAX_PACKET_SIZE];
3231         int packet_size;
3232
3233         Int3();
3234
3235         SDL_assert ( cmeasure_count < UCHAR_MAX );
3236         BUILD_HEADER(COUNTERMEASURE_FIRED);
3237         ADD_USHORT( objp->net_signature );
3238         ADD_INT( rand_val );
3239                 
3240         multi_io_send_to_all(data, packet_size);
3241 }
3242
3243 // process a packet indicating a countermeasure was fired
3244 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3245 {
3246         int offset, rand_val;
3247         ushort signature;
3248         object *objp;
3249
3250         Int3();
3251
3252         offset = HEADER_LENGTH; 
3253
3254         GET_USHORT( signature );
3255         GET_INT( rand_val );
3256         PACKET_SET_SIZE();
3257
3258         objp = multi_get_network_object( signature );
3259         if ( objp == NULL ) {
3260                 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3261                 return;
3262         }
3263         if(objp->type != OBJ_SHIP){
3264                 return;
3265         }
3266         // SDL_assert ( objp->type == OBJ_SHIP );
3267
3268         // make it so ship can fire right away!
3269         Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3270         if ( objp == Player_obj ){
3271                 nprintf(("network", "firing countermeasure from my ship\n"));
3272         }
3273
3274         ship_launch_countermeasure( objp, rand_val );           
3275 }
3276
3277 // send a packet indicating that a turret has been fired
3278 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3279 {
3280         int packet_size;
3281         ushort pnet_signature;
3282         ubyte data[MAX_PACKET_SIZE], cindex;
3283         object *objp;
3284         ubyte has_sig = 0;
3285         ship_subsys *ssp;
3286         short val;
3287
3288         // sanity
3289         if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3290                 return;
3291         }
3292
3293         // local setup -- be sure we are actually passing a weapon!!!!
3294         objp = &Objects[weapon_objnum];
3295         SDL_assert ( objp->type == OBJ_WEAPON );
3296         if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3297                 has_sig = 1;
3298         }
3299
3300         pnet_signature = Objects[ship_objnum].net_signature;
3301
3302         SDL_assert( subsys_index < UCHAR_MAX );
3303         cindex = (ubyte)subsys_index;
3304
3305         ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3306         if(ssp == NULL){
3307                 return;
3308         }
3309
3310         // build the fire turret packet.  
3311         BUILD_HEADER(FIRE_TURRET_WEAPON);       
3312         packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3313         ADD_DATA( has_sig );
3314         ADD_USHORT( pnet_signature );   
3315         if(has_sig){            
3316                 ADD_USHORT( objp->net_signature );
3317         }
3318         ADD_DATA( cindex );
3319         val = (short)ssp->submodel_info_1.angs.h;
3320         ADD_SHORT( val );
3321         val = (short)ssp->submodel_info_2.angs.p;
3322         ADD_SHORT( val );       
3323         
3324         multi_io_send_to_all(data, packet_size);
3325
3326         multi_rate_add(1, "tur", packet_size);
3327 }
3328
3329 // process a packet indicating a turret has been fired
3330 void process_turret_fired_packet( ubyte *data, header *hinfo )
3331 {
3332         int offset, weapon_objnum, wid;
3333         ushort pnet_signature, wnet_signature;
3334         vector pos, temp;
3335         matrix orient;
3336         vector o_fvec;
3337         ubyte turret_index;
3338         object *objp;
3339         ship_subsys *ssp;
3340         ubyte has_sig = 0;
3341         ship *shipp;
3342         short pitch, heading;   
3343
3344         // get the data for the turret fired packet
3345         offset = HEADER_LENGTH; 
3346         offset += multi_pack_unpack_position(0, data + offset, &o_fvec);        
3347         GET_DATA( has_sig );
3348         GET_USHORT( pnet_signature );
3349         if(has_sig){
3350                 GET_USHORT( wnet_signature );
3351         } else {
3352                 wnet_signature = 0;
3353         }
3354         GET_DATA( turret_index );
3355         GET_SHORT( heading );
3356         GET_SHORT( pitch );     
3357         PACKET_SET_SIZE();                              // move our counter forward the number of bytes we have read
3358
3359         // find the object
3360         objp = multi_get_network_object( pnet_signature );
3361         if ( objp == NULL ) {
3362                 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3363                 return;
3364         }
3365
3366         // if this isn't a ship, do nothing
3367         if ( objp->type != OBJ_SHIP ){
3368                 return;
3369         }
3370
3371         // make an orientation matrix from the o_fvec
3372         vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3373
3374         // find this turret, and set the position of the turret that just fired to be where it fired.  Quite a
3375         // hack, but should be suitable.
3376         shipp = &Ships[objp->instance];
3377         ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3378         if(ssp == NULL){
3379                 return;
3380         }
3381         wid = ssp->system_info->turret_weapon_type;
3382
3383         // bash the position and orientation of the turret
3384         ssp->submodel_info_1.angs.h = (float)heading;
3385         ssp->submodel_info_2.angs.p = (float)pitch;
3386
3387         // get the world position of the weapon
3388         ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3389
3390         // create the weapon object
3391         if(wnet_signature != 0){                
3392                 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3393         }
3394         weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3395         if (weapon_objnum != -1) {
3396                 if ( Weapon_info[wid].launch_snd != -1 ) {
3397                         snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3398                 }               
3399         }
3400 }
3401
3402 // send a mission log item packet
3403 void send_mission_log_packet( int num )
3404 {
3405         int packet_size;
3406         ubyte data[MAX_PACKET_SIZE];
3407         ubyte type;
3408         ushort sindex;
3409         log_entry *entry;
3410
3411         SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3412
3413         // get the data from the log
3414         entry = &log_entries[num];
3415         type = (ubyte)entry->type;                      // do the type casting thing to save on packet space
3416         sindex = (ushort)entry->index;
3417
3418         BUILD_HEADER(MISSION_LOG_ENTRY);
3419         ADD_DATA(type);
3420         ADD_INT(entry->flags);
3421         ADD_USHORT(sindex);
3422         ADD_DATA(entry->timestamp);
3423         ADD_STRING(entry->pname);
3424         ADD_STRING(entry->sname);
3425
3426         // broadcast the packet to all players  
3427         multi_io_send_to_all_reliable(data, packet_size);
3428 }
3429
3430 // process a mission log item packet
3431 void process_mission_log_packet( ubyte *data, header *hinfo )
3432 {
3433         int offset, flags;
3434         ushort sindex;
3435         ubyte type;
3436         char pname[NAME_LENGTH], sname[NAME_LENGTH];
3437         fix timestamp;
3438
3439         SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3440
3441         offset = HEADER_LENGTH;
3442         GET_DATA(type);
3443         GET_INT(flags);
3444         GET_USHORT(sindex);
3445         GET_DATA(timestamp);
3446         GET_STRING(pname);
3447         GET_STRING(sname);
3448
3449         PACKET_SET_SIZE();
3450
3451         mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3452 }
3453
3454 // send a mission message packet
3455 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)
3456 {
3457         int packet_size;
3458         ubyte data[MAX_PACKET_SIZE], up, us, utime;
3459         
3460         SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3461         SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3462         SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );   
3463         
3464         up = (ubyte) priority;
3465         us = (ubyte) source;
3466         utime = (ubyte)timing;
3467
3468         BUILD_HEADER(MISSION_MESSAGE);
3469         ADD_INT(id);
3470         ADD_STRING(who_from);
3471         ADD_DATA(up);
3472         ADD_DATA(utime);
3473         ADD_DATA(us);
3474         ADD_INT(builtin_type);
3475         ADD_INT(multi_team_filter);
3476
3477         if (multi_target == -1){                
3478                 multi_io_send_to_all_reliable(data, packet_size);
3479         } else {                
3480                 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3481         }
3482 }
3483
3484 // process a mission message packet
3485 void process_mission_message_packet( ubyte *data, header *hinfo )
3486 {
3487         int offset, id, builtin_type;
3488         ubyte priority, source, utiming;
3489         char who_from[NAME_LENGTH];
3490         int multi_team_filter;
3491
3492         SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3493
3494         offset = HEADER_LENGTH;
3495         GET_INT(id);
3496         GET_STRING(who_from);
3497         GET_DATA(priority);
3498         GET_DATA(utiming);
3499         GET_DATA(source);
3500         GET_INT(builtin_type);
3501         GET_INT(multi_team_filter);
3502
3503         PACKET_SET_SIZE();
3504
3505         // filter out builtin ones in TvT
3506         if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3507                 return;
3508         }
3509
3510         // maybe filter this out
3511         if(!message_filter_multi(id)){
3512                 // send the message as if it came from an sexpression
3513                 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3514         }
3515 }
3516
3517 // just send them a pong back as fast as possible
3518 void process_ping_packet(ubyte *data, header *hinfo)
3519 {
3520    net_addr addr;
3521         int offset;
3522
3523         offset = HEADER_LENGTH;
3524         PACKET_SET_SIZE();
3525
3526         // get the address to return the pong to
3527         fill_net_addr(&addr, hinfo->addr, hinfo->port);
3528                     
3529         // send the pong
3530         send_pong(&addr);       
3531 }
3532
3533 // right now it just routes the pong through to the standalone gui, which is the only
3534 // system which uses ping and pong right now.
3535 void process_pong_packet(ubyte *data, header *hinfo)
3536 {
3537         net_player *p;
3538         net_addr addr;
3539         int offset,lookup;
3540         
3541         offset = HEADER_LENGTH;
3542
3543         fill_net_addr(&addr, hinfo->addr, hinfo->port);
3544                 
3545         PACKET_SET_SIZE();      
3546                 
3547         // if we're connected , see who sent us this pong
3548         if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3549                 lookup = find_player_id(hinfo->id);
3550                 if(lookup == -1){
3551                         return;
3552                 }
3553                 
3554                 p = &Net_players[lookup]; 
3555
3556                 // evaluate the ping
3557                 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3558                         
3559                 // put in calls to any functions which may want to know about the ping times from 
3560                 // this guy
3561                 if(Game_mode & GM_STANDALONE_SERVER){
3562                    std_update_player_ping(p);   
3563                 }
3564
3565 #ifdef PSNET2
3566                 // mark his socket as still alive (extra precaution)
3567                 psnet_mark_received(Net_players[lookup].reliable_socket);
3568 #endif
3569         }
3570         // otherwise, do any special processing
3571         else {
3572                 // if we're in the join game state, see if this pong came from a server on our
3573                 // list
3574                 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3575                         multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3576                 }
3577         }
3578 }
3579
3580 // send a ping packet
3581 void send_ping(net_addr *addr)
3582 {
3583         unsigned char data[8];
3584         int packet_size;
3585
3586         // build the header and send the packet
3587         BUILD_HEADER( PING );           
3588         psnet_send(addr, &data[0], packet_size);
3589 }
3590
3591 // send a pong packet
3592 void send_pong(net_addr *addr)
3593 {
3594    unsigned char data[8];
3595         int packet_size;        
3596
3597         // build the header and send the packet
3598         BUILD_HEADER(PONG);             
3599         psnet_send(addr, &data[0], packet_size);   
3600 }
3601
3602 // sent from host to master. give me the list of missions you have.
3603 // this will be used only in a standalone mode
3604 void send_mission_list_request( int what )
3605 {
3606         ubyte data[MAX_PACKET_SIZE];
3607         int packet_size;
3608
3609         // build the header and ask for a list of missions or campaigns (depending
3610         // on the 'what' flag).
3611         BUILD_HEADER(MISSION_REQUEST);
3612                 
3613         multi_io_send_reliable(Net_player, data, packet_size);
3614 }
3615
3616 // maximum number of bytes that we can send in a mission items packet.
3617 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3618
3619 // defines used to tell what type of packets are being sent
3620 #define MISSION_LIST_ITEMS                      1
3621 #define CAMPAIGN_LIST_ITEMS             2
3622
3623 // send an individual mission file item
3624 void send_mission_items( net_player *pl )
3625 {
3626         ubyte data[MAX_PACKET_SIZE];
3627         int packet_size, i;
3628         ubyte stop, type;
3629
3630         // build the header     
3631         BUILD_HEADER(MISSION_ITEM);     
3632
3633         // send the list of missions and campaigns avilable on the server.  Stop when
3634         // reaching a certain maximum
3635         type = MISSION_LIST_ITEMS;
3636         ADD_DATA( type );
3637         for (i = 0; i < Multi_create_mission_count; i++ ) {             
3638                 stop = 0;
3639                 ADD_DATA( stop );
3640
3641                 ADD_STRING( Multi_create_mission_list[i].filename );
3642                 ADD_STRING( Multi_create_mission_list[i].name );
3643                 ADD_INT( Multi_create_mission_list[i].flags );
3644                 ADD_DATA( Multi_create_mission_list[i].max_players );
3645                 ADD_UINT( Multi_create_mission_list[i].respawn );               
3646
3647                 // STANDALONE_ONLY              
3648                 ADD_DATA( Multi_create_mission_list[i].valid_status );
3649
3650                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3651                         stop = 1;
3652                         ADD_DATA( stop );                       
3653                         multi_io_send_reliable(pl, data, packet_size);
3654                         BUILD_HEADER( MISSION_ITEM );
3655                         ADD_DATA( type );
3656                 }               
3657         }
3658         stop = 1;
3659         ADD_DATA(stop); 
3660         multi_io_send_reliable(pl, data, packet_size);
3661
3662         // send the campaign information
3663         type = CAMPAIGN_LIST_ITEMS;
3664         BUILD_HEADER(MISSION_ITEM);
3665         ADD_DATA( type );
3666         for (i = 0; i < Multi_create_campaign_count; i++ ) {            
3667                 stop = 0;
3668                 ADD_DATA( stop );
3669
3670                 ADD_STRING( Multi_create_campaign_list[i].filename );
3671                 ADD_STRING( Multi_create_campaign_list[i].name );
3672                 ADD_INT( Multi_create_campaign_list[i].flags ); 
3673                 ADD_DATA( Multi_create_campaign_list[i].max_players );          
3674
3675                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3676                         stop = 1;
3677                         ADD_DATA( stop );                       
3678                         multi_io_send_reliable(pl, data, packet_size);
3679                         BUILD_HEADER( MISSION_ITEM );
3680                         ADD_DATA( type );
3681                 }               
3682         }
3683         stop = 1;
3684         ADD_DATA(stop); 
3685         multi_io_send_reliable(pl, data, packet_size);
3686 }
3687
3688 // process a request for a list of missions
3689 void process_mission_request_packet(ubyte *data, header *hinfo)
3690 {   
3691         int player_num,offset;  
3692         
3693         offset = HEADER_LENGTH;
3694         PACKET_SET_SIZE();
3695
3696         // fill in the address information of where this came from      
3697         player_num = find_player_id(hinfo->id);
3698         if(player_num == -1){
3699                 nprintf(("Network","Could not find player to send mission list items to!\n"));
3700                 return;
3701         }
3702
3703         send_mission_items( &Net_players[player_num] );
3704 }
3705
3706 // process an individual mission file item
3707 void process_mission_item_packet(ubyte *data,header *hinfo)
3708 {
3709    int offset, flags;           
3710         char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3711         ubyte stop, type,max_players;
3712         uint respawn;
3713
3714         SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3715         offset = HEADER_LENGTH;
3716
3717         GET_DATA( type );
3718         GET_DATA(stop);
3719         while( !stop ) {
3720                 GET_STRING( filename );
3721                 GET_STRING( name );
3722                 GET_INT( flags );
3723                 GET_DATA( max_players );
3724
3725                 // missions also have respawns and a crc32 associated with them
3726                 if(type == MISSION_LIST_ITEMS){
3727                         GET_UINT(respawn);
3728
3729                         // STANDALONE_ONLY                      
3730                         GET_DATA(valid_status);
3731
3732                         if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3733                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3734                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3735                                 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3736                                 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3737                                 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3738
3739                                 // STANDALONE_ONLY                              
3740                                 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3741
3742                                 Multi_create_mission_count++;
3743                         }
3744                 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3745                         if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3746                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3747                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3748                                 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3749                                 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3750                                 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3751                                 Multi_create_campaign_count++;
3752                         }
3753                 }
3754
3755                 GET_DATA( stop );
3756         }
3757         
3758         PACKET_SET_SIZE();      
3759
3760         // this will cause whatever list to get resorted (although they should be appearing in order)
3761         multi_create_setup_list_data(-1);               
3762 }
3763
3764 // send a request to the server to pause or unpause the game
3765 void send_multi_pause_packet(int pause)
3766 {
3767         ubyte data[MAX_PACKET_SIZE];
3768         ubyte val;
3769         int packet_size = 0;
3770         
3771         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3772         
3773         // build the header
3774         BUILD_HEADER(MULTI_PAUSE_REQUEST);
3775         val = (ubyte) pause;
3776         
3777         // add the pause info
3778         ADD_DATA(val);  
3779
3780         // send the request to the server       
3781         multi_io_send_reliable(Net_player, data, packet_size);
3782 }
3783
3784 // process a pause update packet (pause, unpause, etc)
3785 void process_multi_pause_packet(ubyte *data, header *hinfo)
3786 {
3787         int offset;
3788         ubyte val;              
3789         int player_index;
3790
3791         offset = HEADER_LENGTH;
3792
3793         // get the data
3794         GET_DATA(val);  
3795         PACKET_SET_SIZE();
3796
3797         // get who sent the packet      
3798         player_index = find_player_id(hinfo->id);
3799         // if we don't know who sent the packet, don't do anything
3800         if(player_index == -1){
3801                 return;
3802         }
3803
3804         // if we're the server, we should evaluate whether this guy is allowed to send the packet
3805         multi_pause_server_eval_request(&Net_players[player_index],(int)val);   
3806 }
3807
3808 // send a game information update
3809 void send_game_info_packet()
3810 {
3811         int packet_size;
3812         ubyte data[MAX_PACKET_SIZE], paused;
3813
3814         // set the paused variable
3815         paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3816
3817         BUILD_HEADER(GAME_INFO);
3818         ADD_INT( Missiontime );
3819         ADD_DATA( paused );
3820         
3821         multi_io_send_to_all(data, packet_size);
3822 }
3823
3824 // process a game information update
3825 void process_game_info_packet( ubyte *data, header *hinfo )
3826 {
3827         int offset;
3828         fix mission_time;
3829         ubyte paused;
3830
3831         offset = HEADER_LENGTH;
3832
3833         // get the mission time -- we should examine our time and the time from the server.  If off by some delta
3834         // time, set our time to server time (should take ping time into account!!!)
3835         GET_DATA( mission_time );
3836         GET_DATA( paused );
3837         PACKET_SET_SIZE();      
3838 }
3839
3840 // send an ingame nak packet
3841 void send_ingame_nak(int state, net_player *p)
3842 {
3843         ubyte data[MAX_PACKET_SIZE];
3844         int packet_size = 0;
3845
3846         BUILD_HEADER(INGAME_NAK);
3847
3848         ADD_INT(state);
3849                 
3850         multi_io_send_reliable(p, data, packet_size);
3851 }
3852
3853 // process an ingame nak packet
3854 void process_ingame_nak(ubyte *data, header *hinfo)
3855 {
3856         int offset,state,pid;   
3857
3858         offset = HEADER_LENGTH;
3859         GET_INT(state); 
3860         PACKET_SET_SIZE();
3861         
3862    pid = find_player_id(hinfo->id);
3863         if(pid < 0){
3864                 return;
3865         }
3866         
3867         switch(state){
3868         case ACK_FILE_ACCEPTED :
3869                 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3870                 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3871                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);           
3872                 break;
3873         }       
3874 }
3875
3876 // send a packet telling players to end the mission
3877 void send_endgame_packet(net_player *pl)
3878 {
3879         ubyte data[MAX_PACKET_SIZE];
3880         int packet_size = 0;
3881         
3882         BUILD_HEADER(MISSION_END);      
3883
3884         // sending to a specific player?
3885         if(pl != NULL){
3886                 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3887                 multi_io_send_reliable(pl, data, packet_size);
3888                 return;
3889         }
3890
3891         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
3892                 // send all player stats here
3893                 multi_broadcast_stats(STATS_MISSION);           
3894
3895                 // if in dogfight mode, send all dogfight stats as well
3896                 ml_string("Before dogfight stats!");
3897                 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3898                         ml_string("Sending dogfight stats!");
3899
3900                         multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3901                 }
3902                 ml_string("After dogfight stats!");
3903
3904                 // tell everyone to leave the game              
3905                 multi_io_send_to_all_reliable(data, packet_size);
3906         } else {
3907                 multi_io_send_reliable(Net_player, data, packet_size);
3908         }
3909 }
3910
3911 // process a packet indicating we should end the current mission
3912 void process_endgame_packet(ubyte *data, header *hinfo)
3913 {
3914         int offset;     
3915         int player_num;
3916                         
3917         offset = HEADER_LENGTH;
3918         
3919         PACKET_SET_SIZE();
3920
3921         ml_string("Receiving endgame packet");
3922         
3923         // if I'm the server, I should evaluate whether the sender is authorized to end the game
3924         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3925                 // determine who this came from and make sure he is allowed to end the game             
3926                 player_num = find_player_id(hinfo->id);
3927                 SDL_assert(player_num != -1);
3928                 if(player_num < 0){
3929                         return;
3930                 }
3931
3932                 // if the player is allowed to end the mission
3933                 if(!multi_can_end_mission(&Net_players[player_num])){
3934                         return;
3935                 }               
3936
3937                 // act as if we hit alt+j locally 
3938                 multi_handle_end_mission_request();
3939         }
3940         // all clients process immediately
3941         else {
3942                 // ingame joiners should quit when they receive an endgame packet since the game is over
3943                 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3944                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3945                         return;
3946                 }
3947
3948                 // do any special processing for being in a state other than the gameplay state
3949                 multi_handle_state_special();
3950
3951                 // make sure we're not already in the debrief state
3952                 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3953                         multi_warpout_all_players();                    
3954                 }
3955         }       
3956 }
3957
3958 // send a position/orientation update for myself (if I'm an observer)
3959 void send_observer_update_packet()
3960 {
3961         ubyte data[MAX_PACKET_SIZE];
3962         int packet_size = 0;
3963         int ret;
3964         ushort target_sig;
3965         
3966         // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3967         // to send any update packets to anyone.
3968         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3969                 return;
3970         }
3971
3972         if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3973                 return;
3974         }
3975         
3976         BUILD_HEADER(OBSERVER_UPDATE);
3977
3978         ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3979         packet_size += ret;
3980         ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3981         packet_size += ret;
3982
3983         // add targeting infomation
3984         if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3985                 target_sig = Objects[Player_ai->target_objnum].net_signature;
3986         } else {
3987                 target_sig = 0;
3988         }
3989         ADD_USHORT(target_sig);
3990         
3991         multi_io_send(Net_player, data, packet_size);
3992 }
3993
3994 // process a position/orientation update from an observer
3995 void process_observer_update_packet(ubyte *data, header *hinfo)
3996 {
3997         int offset,ret;
3998         int obs_num;
3999         vector g_vec;
4000         matrix g_mat;
4001         physics_info bogus_pi;  
4002         ushort target_sig;
4003         object *target_obj;
4004         offset = HEADER_LENGTH;
4005
4006         obs_num = find_player_id(hinfo->id);
4007         
4008         memset(&bogus_pi,0,sizeof(physics_info));
4009         ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
4010         offset += ret;
4011         ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
4012         offset += ret;
4013
4014         // targeting information
4015         GET_USHORT(target_sig); 
4016         PACKET_SET_SIZE();      
4017
4018         if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
4019                 return;
4020         }
4021
4022         // set targeting info
4023         if(target_sig == 0){
4024                 Net_players[obs_num].s_info.target_objnum = -1;
4025         } else {
4026                 target_obj = multi_get_network_object(target_sig);
4027                 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4028         }
4029
4030         Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4031         Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4032         Net_players[obs_num].s_info.eye_pos = g_vec;
4033         Net_players[obs_num].s_info.eye_orient = g_mat;
4034 }
4035
4036 void send_netplayer_slot_packet()
4037 {
4038         ubyte data[MAX_PACKET_SIZE];
4039         int packet_size = 0, idx;
4040         ubyte stop;
4041
4042
4043         stop = 0xff;
4044    BUILD_HEADER(NETPLAYER_SLOTS_P);
4045    for(idx=0;idx<MAX_PLAYERS;idx++){
4046                 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4047                         ADD_DATA(stop);
4048                         ADD_SHORT(Net_players[idx].player_id);  
4049                         ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4050                         ADD_INT(Net_players[idx].p_info.ship_class);
4051                         ADD_INT(Net_players[idx].p_info.ship_index);                    
4052                 }
4053         }
4054         stop = 0x0;
4055         ADD_DATA(stop);
4056                 
4057         // standalone case or not
4058         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
4059                 multi_io_send_to_all_reliable(data, packet_size);
4060         } else {
4061                 multi_io_send_reliable(Net_player, data, packet_size);
4062         }
4063 }
4064
4065 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4066 {
4067         int offset;
4068         int player_num,ship_class,ship_index;
4069         ushort net_sig;
4070         object *objp;   
4071         ubyte stop;
4072         short player_id;
4073         
4074         offset = HEADER_LENGTH; 
4075
4076    // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4077         multi_untag_player_ships();
4078
4079         GET_DATA(stop);
4080         while(stop != 0x0){
4081                 GET_SHORT(player_id);
4082                 GET_USHORT(net_sig);
4083                 GET_INT(ship_class);
4084                 GET_INT(ship_index);
4085                 player_num = find_player_id(player_id);
4086                 if(player_num < 0){
4087                         nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4088                 } else {
4089                         // call the function in multiutil.cpp to set up the player object stuff
4090                         // being careful not to muck with the standalone object
4091                         if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4092                                 objp = multi_get_network_object(net_sig);
4093                                 SDL_assert(objp != NULL);
4094                                 multi_assign_player_ship( player_num, objp, ship_class );
4095                                 Net_players[player_num].p_info.ship_index = ship_index;
4096                                 objp->flags &= ~(OF_COULD_BE_PLAYER);
4097                                 objp->flags |= OF_PLAYER_SHIP;
4098                         }
4099                 }
4100                 GET_DATA(stop);
4101         }
4102         PACKET_SET_SIZE();
4103
4104         // standalone should forward the packet and wait for a response
4105         if(Game_mode & GM_STANDALONE_SERVER){
4106                 send_netplayer_slot_packet();
4107         } 
4108
4109         Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4110         send_netplayer_update_packet(); 
4111 }
4112
4113 // two functions to deal with ships changing their primary/secondary weapon status.  'what' indicates
4114 // if this change is a primary or secondary change.  new_bank is the new current primary/secondary
4115 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4116 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4117 {
4118         ubyte data[MAX_PACKET_SIZE], utmp;
4119         int packet_size;
4120
4121         BUILD_HEADER(SHIP_WSTATE_CHANGE);
4122         ADD_USHORT( Objects[shipp->objnum].net_signature );
4123         utmp = (ubyte)(what);
4124         ADD_DATA( utmp );
4125         utmp = (ubyte)(new_bank);
4126         ADD_DATA( utmp );
4127         utmp = (ubyte)(link_status);
4128         ADD_DATA( utmp );
4129
4130         // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB   
4131         multi_io_send_to_all_reliable(data, packet_size);
4132 }
4133
4134 void process_ship_weapon_change( ubyte *data, header *hinfo )
4135 {
4136         int offset;
4137         ushort signature;
4138         ubyte what, new_bank, link_status;
4139         object *objp;
4140         ship *shipp;
4141
4142         offset = HEADER_LENGTH;
4143         GET_USHORT( signature );
4144         GET_DATA( what );
4145         GET_DATA( new_bank );
4146         GET_DATA( link_status );
4147         PACKET_SET_SIZE();
4148
4149         objp = multi_get_network_object( signature );
4150         if ( objp == NULL ) {
4151                 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4152                 return;
4153         }
4154         // SDL_assert( objp->type == OBJ_SHIP );
4155         if(objp->type != OBJ_SHIP){
4156                 return;
4157         }
4158
4159         // if this is my data, do nothing since I already have my own data
4160         if ( objp == Player_obj ){
4161                 return;
4162         }
4163
4164         // now, get the ship and set the new bank and link modes based on the 'what' value
4165         shipp = &Ships[objp->instance];
4166         if ( what == MULTI_PRIMARY_CHANGED ) {
4167                 shipp->weapons.current_primary_bank = new_bank;
4168                 if ( link_status ){
4169                         shipp->flags |= SF_PRIMARY_LINKED;
4170                 } else {
4171                         shipp->flags &= ~SF_PRIMARY_LINKED;
4172                 }
4173         } else {
4174                 shipp->weapons.current_secondary_bank = new_bank;
4175                 if ( link_status ){
4176                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4177                 } else {
4178                         shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4179                 }
4180         }
4181 }
4182         
4183         // ship status change procedure
4184 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4185 //                server critical.
4186 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets 
4187 //                for added redundancy.
4188 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4189 //                ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4190 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS) 
4191 //                back to the client. Also sends multiple times for redundancy
4192 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4193 //                and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4194 //                on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4195
4196 #define SHIP_STATUS_REPEAT 2
4197 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4198 {
4199         int idx, temp;
4200         ubyte data[MAX_PACKET_SIZE];
4201         int packet_size = 0;
4202
4203         if(pl == NULL){
4204                 return;
4205         }
4206
4207         BUILD_HEADER(SHIP_STATUS_CHANGE);
4208         ADD_INT(id);
4209         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4210                 temp = bi->status[idx];
4211                 ADD_INT(temp);
4212         }
4213         
4214    // server should send reliably (response packet)
4215         if(MULTIPLAYER_MASTER){         
4216                 multi_io_send_reliable(pl, data, packet_size);
4217         } else {
4218                 multi_io_send(pl, data, packet_size);
4219         }
4220 }
4221
4222 void process_ship_status_packet(ubyte *data, header *hinfo)
4223 {
4224    int idx;
4225         int offset;
4226         int player_num,unique_id;
4227         button_info bi;
4228         int i_tmp;
4229         
4230         offset = HEADER_LENGTH;
4231
4232         // zero out the button info structure for good measure
4233         memset(&bi,0,sizeof(button_info));
4234         
4235         // read the button-info
4236         GET_INT(unique_id);     
4237                 
4238         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4239                 GET_INT(i_tmp);
4240                 bi.status[idx] = i_tmp;
4241         }
4242
4243         PACKET_SET_SIZE();
4244
4245    // this will be handled differently client and server side. Duh.
4246         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){                  // SERVER SIDE
4247                 // find which net-player has sent us butotn information         
4248       player_num = find_player_id(hinfo->id);
4249                 SDL_assert(player_num >= 0);
4250                 if(player_num < 0){
4251                         return;
4252                 }
4253
4254                 // don't process critical button information for observers
4255                 // its a new button_info for this guy. apply and ack
4256                 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){        
4257                         // mark that he's pressed this button
4258          // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4259                         
4260                         // send a return packet
4261          send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4262                         
4263                         // apply the button presses to his ship as normal
4264                         multi_apply_ship_status(&Net_players[player_num], &bi, 0);         
4265                 } 
4266                 // else ignore it as a repeat from the same guy
4267         } else {                                                         // CLIENT SIDE
4268                 // this is the return from the server, so we should now apply them locally
4269       // if(lookup_ship_status(Net_player,unique_id,1)){
4270                 multi_apply_ship_status(Net_player, &bi, 1);
4271                 // }
4272         }       
4273 }
4274
4275 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4276 // for clients.  Left all details to this function instead of higher level messaging
4277 // code
4278 void send_player_order_packet(int type, int index, int cmd)
4279 {
4280         ubyte data[MAX_PACKET_SIZE];
4281         ubyte val;
4282         ushort target_signature;
4283         char t_subsys;
4284         int packet_size = 0;
4285
4286         BUILD_HEADER(PLAYER_ORDER_PACKET);
4287
4288         val = (ubyte)type;
4289         ADD_DATA(val);         // ship order or wing order, or message all fighters
4290
4291         // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4292         if ( val != SQUAD_MSG_ALL ){
4293                 ADD_INT(index);  // net signature of target ship
4294         }
4295
4296         ADD_INT(cmd);         // the command itself
4297
4298         // add target data.
4299         target_signature = 0;
4300         if ( Player_ai->target_objnum != -1 ){
4301                 target_signature = Objects[Player_ai->target_objnum].net_signature;
4302         }
4303
4304         ADD_USHORT( target_signature );
4305
4306         t_subsys = -1;
4307         if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4308                 int s_index;
4309
4310                 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4311                 SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
4312                 t_subsys = (char)s_index;
4313         }
4314         ADD_DATA(t_subsys);
4315    
4316         multi_io_send_reliable(Net_player, data, packet_size);
4317 }
4318
4319 // brief explanation :
4320 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4321 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4322 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4323 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4324 void process_player_order_packet(ubyte *data, header *hinfo)
4325 {
4326         int offset, player_num, command, index = 0, tobjnum_save;       
4327         ushort target_signature;
4328         char t_subsys, type;
4329         object *objp, *target_objp;
4330         ai_info *aip;
4331         ship *shipp;
4332         ship_subsys *tsubsys_save, *targeted_subsys;
4333
4334         SDL_assert(MULTIPLAYER_MASTER);
4335
4336         // packet values - its easier to read all of these in first
4337                 
4338         offset = HEADER_LENGTH;
4339         
4340         GET_DATA( type );
4341         if ( type != SQUAD_MSG_ALL ){
4342                 GET_INT( index );
4343         }
4344
4345         GET_INT( command );
4346         GET_USHORT( target_signature );
4347         GET_DATA( t_subsys );
4348
4349         PACKET_SET_SIZE();      
4350
4351         player_num = find_player_id(hinfo->id);
4352         if(player_num == -1){
4353                 nprintf(("Network","Received player order packet from unknown player\n"));              
4354                 return;
4355         }       
4356
4357         objp = &Objects[Net_players[player_num].player->objnum];
4358         if ( objp->type != OBJ_SHIP ) {
4359                 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4360                 return;
4361         }
4362
4363         // HACK HACK HACK HACK HACK HACK
4364         // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4365         // the data is BOGUS.  All people should be able to to these things as well.
4366         if(command == REARM_REPAIR_ME_ITEM){ 
4367                 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);          
4368                 return;
4369         } else if(command == ABORT_REARM_REPAIR_ITEM){
4370                 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);            
4371                 return;
4372         }
4373
4374         // if this player is not allowed to do messaging, quit here
4375         if( !multi_can_message(&Net_players[player_num]) ){
4376                 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4377                 return;
4378         }
4379
4380         // check to see if the type of order is a reinforcement call.  If so, intercept it, and
4381         // then call them in.
4382         if ( type == SQUAD_MSG_REINFORCEMENT ) {
4383                 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4384                 hud_squadmsg_call_reinforcement(index, player_num);
4385                 return;
4386         }
4387
4388         // set the player's ai information here
4389         shipp = &Ships[objp->instance];
4390         aip = &Ai_info[shipp->ai_index];
4391
4392         // get the target objnum and targeted subsystem.  Quick out if we don't have an object to act on.
4393         target_objp = multi_get_network_object( target_signature );
4394         if ( target_objp == NULL ) {
4395                 return;
4396         }
4397
4398         targeted_subsys = NULL;
4399         if ( t_subsys != -1 ) {
4400                 SDL_assert( target_objp != NULL );
4401                 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4402         }
4403
4404         // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4405         // here
4406         tobjnum_save = aip->target_objnum;
4407         tsubsys_save = aip->targeted_subsys;
4408
4409         if ( target_objp ) {
4410                 aip->target_objnum = OBJ_INDEX(target_objp);
4411         } else {
4412                 aip->target_objnum = -1;
4413         }
4414
4415         aip->targeted_subsys = targeted_subsys;
4416
4417         if ( type == SQUAD_MSG_SHIP ) {
4418                 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4419         } else if ( type == SQUAD_MSG_WING ) {
4420                 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4421         } else if ( type == SQUAD_MSG_ALL ) {
4422                 hud_squadmsg_send_to_all_fighters( command, player_num );
4423         }
4424
4425         SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); //      make sure not targeting self
4426         aip->target_objnum = tobjnum_save;
4427         aip->targeted_subsys = tsubsys_save;
4428 }
4429
4430 // FILE SIGNATURE stuff :
4431 // there are 2 cases for file signature sending which are handled very differently
4432 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4433 //     posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked). 
4434 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4435 //     the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4436 //     would have to keep track of up to potentially 14 other ack handles  (ouch).
4437 void send_file_sig_packet(ushort sum_sig,int length_sig)
4438 {
4439         ubyte data[MAX_PACKET_SIZE];
4440         int packet_size = 0;
4441
4442         BUILD_HEADER(FILE_SIG_INFO);
4443         ADD_USHORT(sum_sig);
4444         ADD_INT(length_sig);
4445                 
4446         multi_io_send_reliable(Net_player, data, packet_size);
4447 }
4448
4449 void process_file_sig_packet(ubyte *data, header *hinfo)
4450 {
4451         int offset;
4452         int length_sig;
4453         ushort sum_sig; 
4454         offset = HEADER_LENGTH;
4455
4456         // should only be received on the server-side
4457         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); 
4458         
4459         GET_USHORT(sum_sig);
4460         GET_INT(length_sig);
4461         PACKET_SET_SIZE();
4462         server_verify_filesig(hinfo->id, sum_sig, length_sig);  
4463 }
4464
4465 void send_file_sig_request(char *file_name)
4466 {
4467         ubyte data[MAX_PACKET_SIZE];
4468         int packet_size = 0;
4469
4470         BUILD_HEADER(FILE_SIG_REQUEST);
4471         ADD_STRING(file_name);
4472
4473         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4474                 
4475         multi_io_send_to_all_reliable(data, packet_size);
4476 }
4477
4478 void process_file_sig_request(ubyte *data, header *hinfo)
4479 {               
4480         int offset = HEADER_LENGTH;     
4481
4482         // get the mission name
4483         GET_STRING(Netgame.mission_name);        
4484         PACKET_SET_SIZE();      
4485
4486         // set the current mission filename
4487         SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4488
4489         // get the checksum
4490         multi_get_mission_checksum(Game_current_mission_filename);      
4491
4492         if(!multi_endgame_ending()){    
4493                 // reply to the server
4494                 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4495         }
4496 }
4497
4498 // functions to deal with subsystems getting whacked
4499 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4500 {
4501         ubyte data[MAX_PACKET_SIZE];
4502         int packet_size;
4503         ubyte uindex;
4504         vector tmp, local_hitpos;
4505         object *objp;
4506
4507         SDL_assert ( index < UCHAR_MAX );
4508         uindex = (ubyte)(index);
4509
4510         objp = &Objects[shipp->objnum];
4511
4512         vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4513         vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4514
4515         BUILD_HEADER(SUBSYSTEM_DESTROYED);
4516         ADD_USHORT( Objects[shipp->objnum].net_signature );
4517         ADD_DATA( uindex );
4518 //      ADD_DATA( local_hitpos );
4519         add_vector_data(data, &packet_size, local_hitpos);
4520         
4521         multi_io_send_to_all_reliable(data, packet_size);
4522 }
4523
4524 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4525 {
4526         int offset;
4527         ushort signature;
4528         ubyte uindex;
4529         object *objp;
4530         vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4531
4532         offset = HEADER_LENGTH;
4533
4534         GET_USHORT( signature );
4535         GET_DATA( uindex );
4536 //      GET_DATA( local_hit_pos );
4537         get_vector_data(data, &offset, local_hit_pos);
4538
4539         // get the network object.  process it if we find it.
4540         objp = multi_get_network_object( signature );
4541         if ( objp != NULL ) {
4542                 ship *shipp;
4543                 ship_subsys *subsysp;
4544
4545                 // be sure we have a ship!!!
4546                 // SDL_assert ( objp->type == OBJ_SHIP );
4547                 if(objp->type != OBJ_SHIP){
4548                         PACKET_SET_SIZE();
4549                         return;
4550                 }
4551
4552                 shipp = &Ships[objp->instance];
4553
4554                 // call to get the pointer to the subsystem we should be working on
4555                 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4556                 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4557                 vm_vec_add2( &world_hit_pos, &objp->pos );
4558
4559                 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4560                 if ( objp == Player_obj ) {
4561                         hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4562                 }
4563         }
4564
4565         PACKET_SET_SIZE();
4566 }
4567
4568
4569 // packet to tell clients cargo of a ship was revealed to all
4570 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4571 {
4572         ubyte data[MAX_PACKET_SIZE], uindex;
4573         int packet_size;
4574
4575         SDL_assert ( index < UCHAR_MAX );
4576         uindex = (ubyte)(index);
4577
4578         // build the header and add the data
4579         BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4580         ADD_USHORT( Objects[shipp->objnum].net_signature );
4581         ADD_DATA( uindex );
4582
4583         // server sends to all players
4584         if(MULTIPLAYER_MASTER){         
4585                 multi_io_send_to_all_reliable(data, packet_size);
4586         } 
4587         // clients just send to the server
4588         else {
4589                 multi_io_send_reliable(Net_player, data, packet_size);
4590         }
4591 }
4592
4593 // process a subsystem cargo revealed packet
4594 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4595 {
4596         int offset;
4597         ushort signature;
4598         ubyte uindex;
4599         object *objp;
4600         ship *shipp;
4601         ship_subsys *subsysp;
4602
4603         offset = HEADER_LENGTH;
4604         GET_USHORT( signature );
4605         GET_DATA( uindex );
4606         PACKET_SET_SIZE();
4607
4608         // get a ship pointer and call the ship function to reveal the cargo
4609         objp = multi_get_network_object( signature );
4610         if ( objp == NULL ) {
4611                 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4612                 return;
4613         }
4614
4615         // SDL_assert( objp->type == OBJ_SHIP );
4616         if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4617                 return;
4618         }
4619
4620         shipp = &Ships[objp->instance];
4621
4622         // call to get the pointer to the subsystem we should be working on
4623         subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4624         if (subsysp == NULL) {
4625                 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4626                 return;
4627         }
4628
4629         // this will take care of re-routing to all other clients
4630         void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4631         ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4632
4633         // server should rebroadcast
4634         if(MULTIPLAYER_MASTER){
4635                 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4636         }
4637 }
4638
4639 void send_netplayer_load_packet(net_player *pl)
4640 {
4641         ubyte data[MAX_PACKET_SIZE];
4642         int packet_size = 0;
4643
4644         BUILD_HEADER(LOAD_MISSION_NOW);
4645         ADD_STRING(Netgame.mission_name);
4646
4647         if(pl == NULL){         
4648                 multi_io_send_to_all_reliable(data, packet_size);
4649         } else {
4650                 multi_io_send_reliable(pl, data, packet_size);
4651         }
4652 }
4653
4654 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4655 {
4656         char str[100];
4657         int offset = HEADER_LENGTH;     
4658
4659         GET_STRING(str);
4660         PACKET_SET_SIZE();
4661
4662         SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4663         SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4664         if(!Multi_mission_loaded){
4665
4666                 // MWA 2/3/98 -- ingame join changes!!!
4667                 // everyone can go through the same mission loading path here!!!!
4668                 nprintf(("Network","Loading mission..."));
4669
4670                 // notify everyone that I'm loading the mission
4671                 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4672                 send_netplayer_update_packet();         
4673
4674                 // do the load itself
4675                 game_start_mission();           
4676
4677                 // ingame joiners need to "untag" all player ships as could_be_players.  The ingame joining
4678                 // code will remark the correct player ships
4679                 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4680                         multi_untag_player_ships();
4681                 }
4682
4683                 Net_player->flags |= NETINFO_FLAG_MISSION_OK;           
4684                 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4685                 send_netplayer_update_packet();
4686
4687                 Multi_mission_loaded = 1;
4688                 nprintf(("Network","Finished loading mission\n"));              
4689         }       
4690 }
4691
4692 void send_jump_into_mission_packet(net_player *pl)
4693 {
4694         ubyte data[MAX_PACKET_SIZE];
4695         int packet_size = 0;
4696
4697         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4698
4699         BUILD_HEADER(JUMP_INTO_GAME);
4700
4701         // ingame joiners will get special data.  We need to tell them about the state of the mission, like paused,
4702         // and possible other things.
4703         if ( pl != NULL ) {
4704                 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4705                         ADD_INT(Netgame.game_state);
4706                 }
4707         }
4708         
4709         // broadcast
4710         if(pl == NULL){         
4711                 multi_io_send_to_all_reliable(data, packet_size);
4712         }
4713         // send to a specific player
4714         else {
4715                 multi_io_send_reliable(pl, data, packet_size);
4716         }
4717 }
4718
4719 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4720 {
4721         int offset = HEADER_LENGTH;
4722         int state = 0;
4723
4724         // if I am ingame joining, there should be extra data.  For now, this data is the netgame state.
4725         // the game could be paused, so ingame joiner needs to deal with it.
4726         if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4727                 GET_INT( state );
4728                 Netgame.game_state = state;
4729         }
4730
4731         PACKET_SET_SIZE();      
4732
4733         // handle any special processing for being in a weird substate
4734         multi_handle_state_special();
4735
4736         // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4737         if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4738                 if(Net_player->flags & NETINFO_FLAG_OBSERVER){                                          
4739                         multi_ingame_observer_finish();                 
4740                 } else {
4741                         gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4742                         Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4743                         send_netplayer_update_packet();
4744                 }
4745         } else {
4746                 // start the mission!!
4747                 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4748                         Netgame.game_state = NETGAME_STATE_IN_MISSION;
4749                         gameseq_post_event(GS_EVENT_ENTER_GAME);
4750                         Net_player->state = NETPLAYER_STATE_IN_MISSION;
4751                         send_netplayer_update_packet();
4752                 }               
4753         }
4754
4755         extern time_t Player_multi_died_check;
4756         Player_multi_died_check = -1;
4757
4758         // recalc all object pairs now  
4759         extern void obj_reset_all_collisions();
4760         obj_reset_all_collisions();
4761
4762         // display some cool text
4763         multi_common_add_text(XSTR("Received mission start\n",720),1);
4764
4765         // NETLOG
4766         ml_string(NOX("Client received mission start from server - entering mission"));
4767 }
4768
4769 //XSTR:OFF
4770
4771 const char *repair_text[] = {
4772         "unknown",
4773         "REPAIR_INFO_BEGIN",
4774         "REPAIR_INFO_END",
4775         "REPAIR_INFO_UPDATE",
4776         "REPAIR_INFO_QUEUE",
4777         "REPAIR_INFO_ABORT",
4778         "REPAIR_INFO_BROKEN",
4779         "REPAIR_INFO_WARP_ADD",
4780         "REPAIR_INFO_WARP_REMOVE",
4781         "REPAIR_INFO_ONWAY",
4782         "REPAIR_INFO_KILLED",
4783         "REPAIR_INFO_COMPLETE",
4784 };
4785
4786 //XSTR:ON
4787
4788 // the following two routines deal with updating and sending information regarding players
4789 // rearming and repairing during the game.  The process function calls the routines to deal with
4790 // setting flags and other interesting things.
4791 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4792 {
4793         int packet_size = 0;
4794         ushort repaired_signature, repair_signature;
4795         ubyte data[MAX_PACKET_SIZE];
4796         ubyte cd;
4797
4798         // use the network signature of the destination object if there is one, -1 otherwise.
4799         // client will piece it all together
4800         repaired_signature = repaired_objp->net_signature;
4801
4802         // the repair ship may be NULL here since it might have been destroyed
4803         repair_signature = 0;
4804         if ( repair_objp ){
4805                 repair_signature = repair_objp->net_signature;
4806         }
4807
4808         BUILD_HEADER(CLIENT_REPAIR_INFO);
4809         cd = (ubyte)code;
4810         ADD_DATA(cd);
4811         ADD_USHORT( repaired_signature );
4812         ADD_USHORT( repair_signature );
4813         
4814         multi_io_send_to_all_reliable(data, packet_size);
4815
4816         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));
4817 }
4818
4819 void process_repair_info_packet(ubyte *data, header *hinfo)
4820 {
4821         int offset = HEADER_LENGTH;
4822         ushort repaired_signature, repair_signature;
4823         object *repaired_objp, *repair_objp;
4824         ubyte code;
4825
4826         GET_DATA(code);
4827         GET_USHORT( repaired_signature );
4828         GET_USHORT( repair_signature );
4829         PACKET_SET_SIZE();
4830
4831         repaired_objp = multi_get_network_object( repaired_signature );
4832         repair_objp = multi_get_network_object( repair_signature );
4833
4834         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));
4835
4836         if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4837                 return;
4838         }
4839
4840         if ( repaired_objp == NULL ) {
4841                 Int3();                         // Sandeep says this is bad bad bad.  No ship to repair.
4842                 return;
4843         }
4844
4845         // the hope is to simply call the routine in the ai code to set/unset flags
4846         // based on the code value and everything else should happen..I hope....
4847         if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4848
4849                 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4850
4851                 // set the dock flags when repair begins.  Prevents problem in lagging docking
4852                 // packet.  Also set any other flags/modes which need to be set to prevent Asserts.
4853                 // bleah.
4854                 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4855                         ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4856                         Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4857                 }
4858
4859                 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4860                 // as being done.
4861                 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4862                         ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4863                 }
4864         } else {
4865                 if ( code == REPAIR_INFO_WARP_ADD ){
4866                         mission_warp_in_support_ship( repaired_objp );
4867                 } else {
4868                         mission_remove_scheduled_repair( repaired_objp );
4869                 }
4870         }
4871 }
4872
4873 // sends information updating clients on certain AI information that clients will
4874 // need to know about to keep HUD information up to date.  objp is the object that we
4875 // are updating, and what is the type of stuff that we are updating.
4876 void send_ai_info_update_packet( object *objp, char what )
4877 {
4878         int packet_size;
4879         ushort other_signature;
4880         ubyte data[MAX_PACKET_SIZE];
4881         ai_info *aip;
4882         ubyte dock_index, dockee_index;
4883
4884         // SDL_assert( objp->type == OBJ_SHIP );
4885         if(objp->type != OBJ_SHIP){
4886                 return;
4887         }
4888         aip = &Ai_info[Ships[objp->instance].ai_index];
4889
4890         // do an out here
4891         if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4892                 return;
4893
4894         BUILD_HEADER( AI_INFO_UPDATE );
4895         ADD_USHORT( objp->net_signature );
4896         ADD_DATA( what );
4897
4898         // depending on the "what" value, we will send different information
4899         // to the clients
4900         switch( what ) {
4901
4902         case AI_UPDATE_DOCK:
4903                 // for docking ships, add the signature of the ship that we are docking with.
4904                 SDL_assert( aip->dock_objnum != -1 );
4905                 other_signature = Objects[aip->dock_objnum].net_signature;
4906                 dock_index = (ubyte)(aip->dock_index);
4907                 dockee_index = (ubyte)(aip->dockee_index);
4908                 ADD_USHORT( other_signature );
4909                 ADD_DATA(dock_index);
4910                 ADD_DATA(dockee_index);
4911                 break;
4912
4913         case AI_UPDATE_UNDOCK:
4914                 // for undocking ships, check the dock_objnum since we might or might not have it
4915                 // depending on whether or not a ship was destroyed while we were docked.
4916                 other_signature = 0;
4917                 if ( aip->dock_objnum != -1 )
4918                         other_signature = Objects[aip->dock_objnum].net_signature;
4919                 ADD_USHORT( other_signature );
4920
4921                 break;
4922
4923         case AI_UPDATE_ORDERS: {
4924                 int shipnum;
4925
4926                 // for orders, we only need to send a little bit of information here.  Be sure that the
4927                 // first order for this ship is active
4928                 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4929                 ADD_INT( aip->goals[0].ai_mode );
4930                 ADD_INT( aip->goals[0].ai_submode );
4931                 shipnum = -1;
4932                 if ( aip->goals[0].ship_name != NULL )
4933                         shipnum = ship_name_lookup( aip->goals[0].ship_name );
4934
4935                 // the ship_name member of the goals structure may or may not contain a real shipname.  If we don't
4936                 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4937                 if ( shipnum != -1 ) {
4938                         SDL_assert( Ships[shipnum].objnum != -1 );
4939                         other_signature = Objects[Ships[shipnum].objnum].net_signature;
4940                 } else
4941                         other_signature = 0;
4942                 
4943                 ADD_USHORT( other_signature );
4944
4945                 // for docking, add the dock and dockee index
4946                 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4947                         SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4948                         SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4949                         dock_index = (ubyte)aip->goals[0].docker.index;
4950                         dockee_index = (ubyte)aip->goals[0].dockee.index;
4951                         ADD_DATA( dock_index );
4952                         ADD_DATA( dockee_index );
4953                 }
4954                 break;
4955                 }
4956
4957         default:
4958                 Int3();
4959         }
4960         
4961         multi_rate_add(1, "aiu", packet_size);
4962         multi_io_send_to_all_reliable(data, packet_size);
4963 }
4964
4965 // process an ai_info update packet.  Docking/undocking, ai orders, etc. are taken care of here.  This
4966 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4967 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4968 {
4969         int offset = HEADER_LENGTH;
4970         int mode, submode;
4971         ushort net_signature, other_net_signature;
4972         object *objp, *other_objp;
4973         ai_info *aip;
4974         char code;
4975         ubyte dock_index = 0, dockee_index = 0;
4976
4977         GET_USHORT( net_signature );            // signature of the object that we are dealing with.
4978         GET_DATA( code );                                       // code of what we are doing.
4979         objp = multi_get_network_object( net_signature );
4980         if ( !objp ) {
4981                 nprintf(("Network", "Couldn't find object for ai update\n"));
4982         }
4983
4984         switch( code ) {
4985         case AI_UPDATE_DOCK:
4986                 GET_USHORT( other_net_signature );
4987                 GET_DATA( dock_index );
4988                 GET_DATA( dockee_index );
4989                 other_objp = multi_get_network_object( other_net_signature );
4990                 if ( !other_objp ) {
4991                         nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4992                 }
4993                 
4994                 // if we don't have an object to work with, break out of loop
4995                 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4996                         break;
4997                 }
4998
4999                 SDL_assert( other_objp->type == OBJ_SHIP );
5000                 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
5001                 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
5002
5003                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5004                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5005
5006                 ai_do_objects_docked_stuff( objp, other_objp );
5007                 break;
5008
5009         case AI_UPDATE_UNDOCK:
5010                 GET_USHORT( other_net_signature );
5011                 other_objp = multi_get_network_object( other_net_signature );
5012                 
5013                 // if we don't have an object to work with, break out of loop
5014                 if ( !objp )
5015                         break;
5016
5017                 ai_do_objects_undocked_stuff( objp, other_objp );
5018                 break;
5019
5020         case AI_UPDATE_ORDERS:
5021                 GET_INT( mode );
5022                 GET_INT( submode );
5023                 GET_USHORT( other_net_signature );
5024                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5025                         GET_DATA(dock_index);
5026                         GET_DATA(dockee_index);
5027                 }
5028
5029                 // be sure that we have a ship object!!!
5030                 if ( !objp || (objp->type != OBJ_SHIP) )
5031                         break;
5032
5033                 // set up the information in the first goal element of the object in question
5034                 aip = &Ai_info[Ships[objp->instance].ai_index];
5035                 aip->active_goal = 0;
5036                 aip->goals[0].ai_mode = mode;
5037                 aip->goals[0].ai_submode = submode;
5038
5039                 // for docking, add the dock and dockee index
5040                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5041                         aip->dock_index = dock_index;
5042                         aip->dockee_index = dockee_index;
5043                 }
5044
5045                 // get a shipname if we can.
5046                 other_objp = multi_get_network_object( other_net_signature );
5047                 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5048                         // get a pointer to the shipname in question.  Use the ship_name value in the
5049                         // ship.  We are only using this for HUD display, so I think that using this
5050                         // method will be fine.
5051                         aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5052
5053                         // special case for destroy subsystem -- get the ai_info pointer to our target ship
5054                         // so that we can properly set up what subsystem this ship is attacking.
5055                         if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5056                                 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5057
5058                         // if docking -- set the dock index and dockee index of this other ship
5059                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5060                                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5061                                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5062                         }
5063                 }
5064
5065                 break;
5066
5067         default:
5068                 Int3();         // this Int3() should be temporary
5069                 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5070                 break;
5071         }
5072         PACKET_SET_SIZE();
5073 }
5074
5075 // tell the standalone to move into the MISSION_SYNC_STATE
5076 void send_mission_sync_packet(int mode,int start_campaign)
5077 {
5078         ubyte data[MAX_PACKET_SIZE],is_campaign;
5079         int packet_size = 0;
5080
5081         SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5082
5083         // build the header and add the sync mode (pre or post briefing)
5084         BUILD_HEADER(MISSION_SYNC_DATA);
5085         ADD_INT(mode);
5086
5087         // if this is a campaign game
5088         if(mode == MULTI_SYNC_PRE_BRIEFING){
5089                 if(Game_mode & GM_CAMPAIGN_MODE){
5090                         // add a byte indicating campaign mode
5091                         is_campaign = 1;
5092                         ADD_DATA(is_campaign);
5093
5094                         // add a byte indicating if we should be starting a campaign or continuing it
5095                         is_campaign = (ubyte)start_campaign;
5096                         ADD_DATA(is_campaign);
5097
5098                         // add the campaign filename
5099                         ADD_STRING(Netgame.campaign_name);
5100                 }
5101                 // otherwise if this is a single mission 
5102                 else {
5103                         // add a byte indicating single mission mode
5104                         is_campaign = 0;
5105                         ADD_DATA(is_campaign);
5106
5107                         // add the mission filename
5108                         ADD_STRING(Game_current_mission_filename);
5109                 }
5110         }       
5111         multi_io_send_reliable(Net_player, data, packet_size);
5112 }
5113
5114 // move into the MISSION_SYNC state when this is received
5115 // this packet is sent only from a game host to a standalone
5116 void process_mission_sync_packet(ubyte *data, header *hinfo)
5117 {
5118         int mode;
5119         ubyte campaign_flag;
5120         int offset = HEADER_LENGTH;
5121
5122         SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5123
5124         // if this is a team vs team situation, lock the players send a final team update
5125         if(Netgame.type_flags & NG_TYPE_TEAM){
5126                 multi_team_host_lock_all();
5127                 multi_team_send_update();
5128         }
5129
5130         // get the sync mode (pre or post briefing)
5131         GET_INT(mode);
5132
5133         if(mode == MULTI_SYNC_PRE_BRIEFING){
5134                 // get the flag indicating if this is a single mission or a campaign mode
5135                 GET_DATA(campaign_flag);
5136                 if(campaign_flag){
5137                         // get the flag indicating whether we should be starting a new campaign
5138                         GET_DATA(campaign_flag);
5139
5140                         // get the campaign filename
5141                         GET_STRING(Netgame.campaign_name);
5142
5143                         // either start a new campaign or continue on to the next mission in the current campaign
5144                         if(campaign_flag){
5145                                 multi_campaign_start(Netgame.campaign_name);
5146                         } else {
5147                                 multi_campaign_next_mission();
5148                         }
5149                 } else {
5150                         // make sure we remove the campaign mode flag
5151                         Game_mode &= ~(GM_CAMPAIGN_MODE);
5152
5153                         // get the single mission filename
5154                         GET_STRING(Game_current_mission_filename);
5155                         SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5156                 }
5157         }
5158         PACKET_SET_SIZE();
5159
5160         // set the correct mode and m ove into the state
5161         Multi_sync_mode = mode;
5162         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5163 }
5164
5165 // tell a player to merge his mission stats into his alltime stats
5166 void send_store_stats_packet(int accept)
5167 {
5168         ubyte data[10],val;
5169         int packet_size = 0;
5170
5171         BUILD_HEADER(STORE_MISSION_STATS);
5172
5173         // add whether we're accepting or tossing
5174         val = (ubyte)accept;
5175         ADD_DATA(val);
5176
5177         // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5178         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5179                 multi_io_send_to_all_reliable(data, packet_size);
5180         } else {
5181                 multi_io_send_reliable(Net_player, data, packet_size);
5182         }
5183 }
5184
5185 void process_store_stats_packet(ubyte *data, header *hinfo)
5186 {
5187         int offset = HEADER_LENGTH;
5188         ubyte accept;
5189
5190         GET_DATA(accept);
5191         PACKET_SET_SIZE();
5192
5193         // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5194         if(Game_mode & GM_STANDALONE_SERVER){
5195                 // rebroadcast the packet to all others in the game
5196                 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));                             
5197                 multi_io_send_to_all_reliable(data, offset);
5198         } else {                        
5199                 if(accept){
5200                         // all players should mark the stats as being accepted in the debriefing
5201                         multi_debrief_stats_accept();                   
5202                 } else {
5203                         // all players should mark the stats as being "tossed" in the debriefing
5204                         multi_debrief_stats_toss();                     
5205                 }                       
5206         }
5207 }
5208
5209 void send_debris_update_packet(object *objp,int code)
5210 {
5211         ubyte data[MAX_PACKET_SIZE];
5212         ubyte val;
5213         int packet_size = 0;
5214
5215         BUILD_HEADER(DEBRIS_UPDATE);    
5216         ADD_USHORT(objp->net_signature);
5217         val = (ubyte) code;
5218         ADD_DATA(val);
5219         
5220         // add any extra relevant data
5221         switch(code){
5222         case DEBRIS_UPDATE_UPDATE:
5223         //      ADD_DATA(objp->pos);                                            // add position
5224                 add_vector_data(data, &packet_size, objp->pos);
5225                 ADD_ORIENT(objp->orient);                               // add orientation
5226         //      ADD_DATA(objp->phys_info.vel);          // add velocity
5227                 add_vector_data(data, &packet_size, objp->phys_info.vel);
5228         //      ADD_DATA(objp->phys_info.rotvel);       // add rotational velocity
5229                 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5230                 break;
5231         }       
5232         multi_io_send_to_all(data, packet_size);
5233 }
5234
5235 void process_debris_update_packet(ubyte *data, header *hinfo)
5236 {
5237         ushort net_sig;
5238         ubyte code;
5239         object bogus_object;
5240         object *objp;
5241         int offset = HEADER_LENGTH;
5242         
5243         GET_USHORT(net_sig);
5244         GET_DATA(code);
5245
5246         objp = NULL;
5247         objp = multi_get_network_object(net_sig);
5248         if(objp == NULL){
5249                 objp = &bogus_object;
5250         }
5251
5252         switch((int)code){
5253         // update the object
5254         case DEBRIS_UPDATE_UPDATE:
5255                 //GET_DATA(objp->pos);
5256         get_vector_data( data, &offset, objp->pos );
5257                 
5258                 GET_ORIENT(objp->orient);
5259                 GET_DATA(objp->phys_info.vel);
5260                 GET_DATA(objp->phys_info.rotvel);
5261                 break;
5262         // simply remove it (no explosion)
5263         case DEBRIS_UPDATE_REMOVE:
5264                 if(objp != &bogus_object){
5265                         SDL_assert(objp->type == OBJ_DEBRIS);
5266                         obj_delete(OBJ_INDEX(objp));
5267                 }
5268                 break;
5269         // blow it up
5270         case DEBRIS_UPDATE_NUKE:
5271                 if(objp != &bogus_object)
5272                         debris_hit(objp,NULL,&objp->pos,1000000.0f);
5273                 break;
5274         }
5275
5276         PACKET_SET_SIZE();
5277 }
5278
5279 // ALAN begin
5280 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)
5281 {
5282         ubyte data[MAX_PACKET_SIZE];
5283
5284         int packet_size = 0;
5285
5286         BUILD_HEADER(WSS_REQUEST_PACKET);
5287         
5288         // add the request information
5289         ADD_SHORT(player_id);
5290         ADD_INT(from_slot);
5291         ADD_INT(from_index);
5292         ADD_INT(to_slot);
5293         ADD_INT(to_index);
5294         ADD_INT(wl_ship_slot);  // only used in weapons loadout
5295         ADD_INT(ship_class);
5296         ADD_INT(mode);
5297
5298         // a standard request
5299         if(p == NULL){          
5300                 multi_io_send_reliable(Net_player, data, packet_size);
5301         } 
5302         // being routed through the standalone to the host of the game
5303         else {
5304                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);                   
5305                 multi_io_send_reliable(p, data, packet_size);
5306         }
5307 }
5308
5309 void process_wss_request_packet(ubyte *data, header *hinfo)
5310 {
5311         int offset = HEADER_LENGTH;
5312         int from_slot,from_index;
5313         int to_slot,to_index;
5314         int mode;
5315         int wl_ship_slot,ship_class;
5316         short player_id;        
5317         int player_num;
5318
5319         // determine who this request is from   
5320         GET_SHORT(player_id);   
5321         player_num = find_player_id(player_id); 
5322
5323         // read in the request data     
5324         GET_INT(from_slot);
5325         GET_INT(from_index);
5326         GET_INT(to_slot);
5327         GET_INT(to_index);
5328         GET_INT(wl_ship_slot); // only used in weapons loadout
5329         GET_INT(ship_class);    // only used in multi team select
5330         GET_INT(mode);
5331         PACKET_SET_SIZE();
5332
5333         SDL_assert(player_num != -1);   
5334         if(player_num == -1){
5335                 return;
5336         }
5337
5338         // if we're the standalone, we have to route this packet to the host of the game
5339         if(Game_mode & GM_STANDALONE_SERVER){
5340                 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5341         } 
5342         // otherwise we're the host and should process the request
5343         else {
5344                 switch(mode){
5345                 case WSS_WEAPON_SELECT :
5346                         wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5347                         break;
5348                 case WSS_SHIP_SELECT :
5349                         multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);                     
5350                         break;
5351                 default:
5352                         Int3();
5353                 }
5354         }
5355 }
5356
5357 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5358 {
5359         ubyte data[MAX_PACKET_SIZE],team;
5360         int packet_size = 0;
5361
5362         SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5363
5364         BUILD_HEADER(WSS_UPDATE_PACKET);
5365
5366         // add the team/pool # this is for
5367         team = (ubyte)team_num;
5368         ADD_DATA(team);
5369
5370         // add the data block size
5371         ADD_INT(size);
5372         
5373         // add the data itself
5374         memcpy(data + packet_size,wss_data,size);
5375         packet_size += size;
5376
5377         // if we're also the master of the game (not on a standalone)
5378         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5379                 multi_io_send_to_all_reliable(data, packet_size);
5380         }
5381         // if we're only the host on the standalone, then send the packet to the standalone to be routed
5382         else {
5383                 multi_io_send_reliable(Net_player, data, packet_size);
5384         }
5385 }
5386
5387 void process_wss_update_packet(ubyte *data, header *hinfo)
5388 {               
5389         ubyte team;
5390         int size,player_index,idx;
5391         int offset = HEADER_LENGTH;
5392
5393         // get the team/pool #
5394         GET_DATA(team);
5395
5396         // get the data size
5397         GET_INT(size);          
5398
5399         // if we're the standalone, then we should be routing this data to all the other clients
5400         if(Game_mode & GM_STANDALONE_SERVER){
5401                 // read in the data             
5402                 offset += size;         
5403                 PACKET_SET_SIZE();
5404
5405                 // determine where this came from               
5406                 player_index = find_player_id(hinfo->id);               
5407                 SDL_assert(player_index != -1);         
5408                 if(player_index < 0){
5409                         return;
5410                 }
5411
5412                 // route the packet (don't resend it to the host)
5413                 for(idx=0;idx<MAX_PLAYERS;idx++){
5414                         if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){                               
5415                                 multi_io_send_reliable(&Net_players[idx], data, offset);
5416                         }
5417                 }                       
5418         } else {
5419                 // set the proper pool pointers
5420                 ss_set_team_pointers((int)team);
5421
5422                 // read in the block of data, and apply it to the weapons/ship pools
5423                 offset += restore_wss_data(data + offset);
5424                 PACKET_SET_SIZE();
5425
5426                 // set the pool pointers back to my own team
5427                 ss_set_team_pointers(Net_player->p_info.team);
5428
5429                 // sync the interface if this was for my own team
5430                 if((int)team == Net_player->p_info.team){
5431                         multi_ts_sync_interface();
5432                 }               
5433         }
5434 }
5435 // ALAN END
5436
5437
5438 // function to send firing information from the client to the server once they reach
5439 // the final sync screen.
5440 void send_firing_info_packet()
5441 {
5442         ubyte data[MAX_PACKET_SIZE];
5443         int packet_size;
5444         ubyte plinked, sdual;
5445
5446         SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5447
5448         BUILD_HEADER(FIRING_INFO);
5449         plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5450         sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5451         ADD_DATA( plinked );
5452         ADD_DATA( sdual );
5453         
5454         multi_io_send_reliable(Net_player, data, packet_size);
5455 }
5456
5457 void process_firing_info_packet( ubyte *data, header *hinfo )
5458 {
5459         int offset, player_num; 
5460         ubyte plinked, sdual;
5461         ship *shipp;
5462
5463         // only the master of the game should be dealing with these packets
5464         SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5465
5466         offset = HEADER_LENGTH;
5467         GET_DATA( plinked );
5468         GET_DATA( sdual );
5469         PACKET_SET_SIZE();      
5470
5471         player_num = find_player_id(hinfo->id);
5472         if(player_num < 0){
5473                 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5474                 return;
5475         }
5476
5477         // get the ship pointer for this player and set the flags accordingly.
5478         shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5479         if ( plinked )
5480                 shipp->flags |= SF_PRIMARY_LINKED;
5481         else
5482                 shipp->flags &= ~SF_PRIMARY_LINKED;
5483
5484         if ( sdual )
5485                 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5486         else
5487                 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5488 }
5489
5490 // packet to deal with changing status of mission goals.  used to be sent every so often from server
5491 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5492 // goal_num is the index into mission_goals.  new_status means failed, success, etc.  -1 if not used.
5493 // valid means goal is changing to invalid(0) or valid(1).  only applies if new_status == -1
5494 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5495 {
5496         ubyte data[MAX_PACKET_SIZE];
5497         int packet_size;
5498
5499         BUILD_HEADER(MISSION_GOAL_INFO);
5500
5501         ADD_INT(goal_num);
5502         ADD_INT(new_status);
5503         ADD_INT(valid);
5504         
5505         multi_io_send_to_all_reliable(data, packet_size);
5506 }
5507
5508 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5509 {
5510         int offset, goal_num, new_status, valid;
5511
5512         offset = HEADER_LENGTH;
5513         GET_INT(goal_num);
5514         GET_INT(new_status);
5515         GET_INT(valid);
5516         PACKET_SET_SIZE();
5517
5518         // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5519         if ( new_status != -1 ){
5520                 mission_goal_status_change( goal_num, new_status );
5521         } else {
5522                 mission_goal_validation_change( goal_num, valid );
5523         }
5524 }
5525
5526 void send_player_settings_packet(net_player *p)
5527 {
5528         ubyte data[MAX_PACKET_SIZE];
5529         ubyte stop;
5530         int idx;
5531         int packet_size = 0;
5532
5533         // build the header
5534         BUILD_HEADER(PLAYER_SETTINGS);
5535
5536         // add all the data for all the players
5537         stop = 0x0;
5538         for(idx=0;idx<MAX_PLAYERS;idx++){
5539                 if(MULTI_CONNECTED(Net_players[idx])){
5540                         ADD_DATA(stop);
5541                         ADD_SHORT(Net_players[idx].player_id);
5542
5543                         // break the p_info structure by member, so we don't overwrite any absolute pointers
5544                         // ADD_DATA(Net_players[idx].p_info);
5545                         ADD_INT(Net_players[idx].p_info.team);
5546                         ADD_INT(Net_players[idx].p_info.ship_index);
5547                         ADD_INT(Net_players[idx].p_info.ship_class);
5548                 }
5549         }
5550         // add the stop byte
5551         stop = 0xff;
5552         ADD_DATA(stop);
5553
5554         // either broadcast the data or send to a specific player
5555         if(p == NULL){          
5556                 multi_io_send_to_all_reliable(data, packet_size);
5557         } else {
5558                 multi_io_send_reliable(p, data, packet_size);
5559         }                       
5560 }
5561
5562 void process_player_settings_packet(ubyte *data, header *hinfo)
5563 {
5564         int offset,player_num;
5565         net_player_info bogus,*ptr;
5566         short player_id;
5567         ubyte stop;
5568
5569         offset = HEADER_LENGTH;
5570
5571         // read in the data for all the players
5572         GET_DATA(stop);
5573         while(stop != 0xff){
5574                 // lookup the player
5575                 GET_SHORT(player_id);
5576                 player_num = find_player_id(player_id);
5577
5578                 // make sure this is a valid player
5579                 if(player_num == -1){
5580                         ptr = &bogus;                   
5581                 } else {
5582                         ptr = &Net_players[player_num].p_info;
5583                 }
5584                 
5585                 GET_INT(ptr->team);
5586                 GET_INT(ptr->ship_index);
5587                 GET_INT(ptr->ship_class);
5588                 
5589                 // next stop byte
5590                 GET_DATA(stop);
5591         }
5592         PACKET_SET_SIZE();
5593
5594         // update the server with my new state
5595         // MWA -- 3/31/98 -- check for in mission instead of state.
5596         //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5597         if( !(Game_mode & GM_IN_MISSION) ) {
5598                 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5599                 send_netplayer_update_packet(); 
5600         }
5601
5602
5603         // display some cool text
5604         multi_common_add_text(XSTR("Received player settings packet\n",721),1); 
5605 }
5606
5607 void send_deny_packet(net_addr *addr, int code)
5608 {
5609         ubyte data[10];
5610         int packet_size = 0;
5611
5612         // build the header and add the rejection code
5613         BUILD_HEADER(DENY);
5614
5615         ADD_INT(code);
5616         
5617         // send the packet      
5618         psnet_send(addr, data, packet_size);
5619 }
5620
5621 void process_deny_packet(ubyte *data, header *hinfo)
5622 {
5623         int offset,code;
5624
5625         // get the denial code
5626         offset = HEADER_LENGTH;
5627         GET_INT(code);
5628         PACKET_SET_SIZE();
5629
5630         // if there is already a dialog active, do nothing - who cares at this point.
5631         if(popup_active()){
5632                 return;
5633         }
5634
5635         // display the appropriate dialog
5636         switch(code){
5637         case JOIN_DENY_JR_STATE :
5638                 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));
5639                 break;
5640         case JOIN_DENY_JR_TRACKER_INVAL :
5641                 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));
5642                 break;
5643         case JOIN_DENY_JR_PASSWD :
5644                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5645                 break;  
5646         case JOIN_DENY_JR_CLOSED :
5647                 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));
5648                 break;
5649         case JOIN_DENY_JR_TEMP_CLOSED :
5650                 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));
5651                 break;
5652         case JOIN_DENY_JR_RANK_HIGH :
5653                 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));
5654                 break;
5655         case JOIN_DENY_JR_RANK_LOW :
5656                 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));
5657                 break;
5658         case JOIN_DENY_JR_DUP :
5659                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5660                 break;
5661         case JOIN_DENY_JR_FULL :
5662                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5663                 break;
5664         case JOIN_DENY_JR_BANNED :
5665                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5666                 break;
5667         case JOIN_DENY_JR_NOOBS :
5668                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5669                 break;
5670         case JOIN_DENY_JR_INGAME_JOIN :
5671                 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));
5672                 break;
5673         case JOIN_DENY_JR_BAD_VERSION :
5674                 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));
5675                 break;  
5676         case JOIN_DENY_JR_TYPE :
5677                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5678                 break;                  
5679         }       
5680
5681         // call this so that the join request timestamp automatically expires when we hear back from the server
5682         multi_join_reset_join_stamp();
5683 }
5684
5685 // this packet will consist of 
5686 // 1.) netplayer ship classes                   (85 bytes max)
5687 // 2.) ship weapon state data                   (241 bytes max)
5688 // 3.) player settings et. al.          (133 bytes max)
5689 // TOTAL                            459                         NOTE : keep this in mind when/if adding new data to this packet
5690 void send_post_sync_data_packet(net_player *p, int std_request)
5691 {
5692         ubyte data[MAX_PACKET_SIZE], val;
5693         char bval;
5694         ship *shipp;            
5695         net_player *pl;
5696         ship_obj *so;
5697         ushort sval, ship_ets;
5698         int idx, player_index;
5699         int packet_size = 0;
5700         int ship_count;
5701         short val_short;
5702
5703         BUILD_HEADER(POST_SYNC_DATA);
5704
5705         // some header information for standalone packet routing purposes
5706         val = (ubyte)std_request;
5707         ADD_DATA(val);
5708
5709         // the standalone has two situations
5710         // 1.) sending a request to the host to distribute this block of data
5711         // 2.) having recevied this block of data from the host, it redistributes it
5712         if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5713                 // case 1, send the request                                     
5714                 multi_io_send_reliable(Netgame.host, data, packet_size);
5715                 return;
5716         }
5717         // case 2 for the standalone is below (as normal)
5718
5719         // otherwise build the data now 
5720         
5721         // add all deleted ships
5722         val = (ubyte)Multi_ts_num_deleted;
5723         ADD_DATA(val);
5724         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5725                 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5726                 ADD_USHORT(sval);
5727         }
5728
5729         // ship count   
5730         ship_count = 0;
5731         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5732                 shipp = &Ships[Objects[so->objnum].instance];
5733
5734                 // don't process non player wing ships
5735                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5736                         continue;
5737
5738                 ship_count++;
5739         }
5740
5741         // # of ships - used multiple times in the packet
5742         val = (ubyte)ship_count;
5743         ADD_DATA(val);
5744
5745         // add ship class information (85 bytes max)    
5746         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5747                 shipp = &Ships[Objects[so->objnum].instance];
5748
5749                 // don't process non player wing ships
5750                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5751                         continue;               
5752                 
5753                 // add the net signature of the object for look up
5754                 ADD_USHORT( Objects[so->objnum].net_signature );
5755                 
5756                 // add the ship info index 
5757                 val = (ubyte)(shipp->ship_info_index);
5758                 ADD_DATA(val);          
5759
5760                 // add the ships's team select index
5761                 val = (ubyte)shipp->ts_index;
5762                 ADD_DATA(val);
5763         }       
5764
5765         // add weapon state information for all starting ships (241 bytes max)
5766         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5767                 shipp = &Ships[Objects[so->objnum].instance];
5768
5769                 // don't process non player wing ships
5770                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5771                         continue;                       
5772
5773                 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5774                 pl = NULL;
5775                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5776                         player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5777                         if(player_index == -1){
5778                                 pl = NULL;
5779                         } else {
5780                                 pl = &Net_players[player_index];
5781                         }
5782                 }
5783
5784                 // add the net signature and other weapon information
5785                 ADD_USHORT( Objects[so->objnum].net_signature );                
5786
5787                 // add number of primary and secondary banks
5788                 bval = (char)(shipp->weapons.num_primary_banks);
5789                 ADD_DATA(bval);
5790                 bval = (char)(shipp->weapons.num_secondary_banks);
5791                 ADD_DATA(bval);
5792
5793                 // add weapon bank status
5794                 bval = (char)(shipp->weapons.current_primary_bank);
5795                 if(pl != NULL){
5796                         pl->s_info.cur_primary_bank = bval;
5797                 }
5798                 // SDL_assert(bval != -1);
5799                 ADD_DATA(bval);
5800
5801                 bval = (char)(shipp->weapons.current_secondary_bank);
5802                 if(pl != NULL){
5803                         pl->s_info.cur_secondary_bank = bval;
5804                 }
5805                 // SDL_assert(bval != -1);
5806                 ADD_DATA(bval);
5807                                                 
5808                 // primary weapon info
5809                 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5810                 ADD_DATA(bval);
5811                 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5812                 ADD_DATA(bval);
5813
5814                 // secondary weapon info
5815                 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5816                 ADD_DATA(bval);
5817                 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5818                 ADD_SHORT(val_short);
5819                 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5820                 ADD_DATA(bval);
5821                 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5822                 ADD_SHORT(val_short);
5823                 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5824                 ADD_DATA(bval);
5825                 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5826                 ADD_SHORT(val_short);           
5827                 
5828                 // send primary and secondary weapon link status
5829                 val = 0x0;
5830                 if(shipp->flags & SF_PRIMARY_LINKED){
5831                         if(pl != NULL){
5832                                 pl->s_info.cur_link_status |= (1<<0);
5833                         }
5834                         val |= (1<<0);
5835                 }                               
5836                 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5837                         if(pl != NULL){
5838                                 pl->s_info.cur_link_status |= (1<<1);
5839                         }
5840                         val |= (1<<1);
5841                 }               
5842                 // if this is a player ship add (1<<2)
5843                 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5844                         val |= (1<<2);
5845                 }
5846                 ADD_DATA(val);
5847
5848                 // add a ship ets value
5849                 ship_ets = 0x0000;
5850                 // shield ets           
5851                 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5852                 // weapon ets
5853                 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5854                 // engine ets
5855                 ship_ets |= ((ushort)shipp->engine_recharge_index);
5856                 ADD_USHORT(ship_ets);
5857
5858         }
5859
5860         // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5861         // or if I'm the server as well as the host, I should be sending this to all players
5862         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5863                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5864                         // broadcast
5865                         if(p == NULL){                          
5866                                 multi_io_send_to_all_reliable(data, packet_size);
5867                         }
5868                         // send to a specific player
5869                         else {
5870                                 multi_io_send_reliable(p, data, packet_size);
5871                         }
5872                 } else {
5873                         multi_io_send_reliable(Net_player, data, packet_size);
5874                 }
5875         }
5876         // standalone mode
5877         else {
5878                 // broadcast
5879                 if(p == NULL){
5880                         multi_io_send_to_all_reliable(data, packet_size);
5881                 }
5882                 // send to a specific player
5883                 else {
5884                         multi_io_send_reliable(p, data, packet_size);
5885                 }
5886         }
5887 }
5888
5889 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5890 {
5891         ubyte val, sinfo_index, ts_index;
5892         char b;
5893         ushort net_sig, ship_ets, sval;
5894         ship *shipp;
5895         object *objp;
5896         int idx;
5897         int offset = HEADER_LENGTH;
5898         int ship_count;
5899         short val_short;
5900
5901         // packet routing information
5902         GET_DATA(val);
5903
5904         // 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
5905         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5906                 PACKET_SET_SIZE();
5907
5908                 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5909                 multi_ts_create_wings();
5910                 
5911                 // send to the standalone through my socket
5912                 send_post_sync_data_packet(Net_player);
5913                 return;
5914         }
5915
5916         // process player
5917
5918         // add all deleted ships
5919         GET_DATA(val);
5920         Multi_ts_num_deleted = (int)val;
5921         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5922                 // get the ship's objnum
5923                 GET_USHORT(sval);
5924                 objp = NULL;
5925                 objp = multi_get_network_object(sval);
5926                 if(objp != NULL){
5927                         // delete the ship appropriately
5928                         // mark the object as having been deleted
5929                         Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5930
5931                         // delete the ship
5932                         ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5933                         obj_delete(Multi_ts_deleted_objnums[idx]);                      
5934                         ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5935                 } else {
5936                         Multi_ts_num_deleted--;
5937                         nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5938                 }
5939         }
5940
5941         // ship count
5942         GET_DATA(val);
5943         ship_count = val;
5944
5945         // process ship class information
5946         for(idx=0; idx<ship_count; idx++){      
5947                 // get the object's net signature
5948                 GET_USHORT(net_sig);
5949                 GET_DATA(sinfo_index);
5950                 GET_DATA(ts_index);
5951
5952                 // attempt to get the object
5953                 objp = multi_get_network_object(net_sig);
5954
5955                 // make sure we found a ship
5956                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5957
5958                 // set the ship to be the right class
5959                 change_ship_type(objp->instance,(int)sinfo_index);
5960
5961                 // set the ship's team select index
5962                 Ships[objp->instance].ts_index = (int)ts_index;         
5963         }
5964
5965         // process ship weapon state info
5966         for(idx=0; idx<ship_count; idx++){      
5967                 // get the object's net signature
5968                 GET_USHORT(net_sig);
5969
5970                 // attempt to get the object
5971                 objp = multi_get_network_object(net_sig);
5972
5973                 // make sure we found a ship
5974                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5975
5976                 // get a pointer to the ship
5977                 shipp = &Ships[objp->instance];
5978
5979                 // get number of primary and secondary banks;
5980                 GET_DATA(b);
5981                 SDL_assert( b != -1 );
5982                 shipp->weapons.num_primary_banks = (int)b;
5983
5984                 GET_DATA(b);
5985                 SDL_assert( b != -1 );
5986                 shipp->weapons.num_secondary_banks = (int)b;
5987
5988                 // get bank selection info
5989                 GET_DATA(b);
5990                 if ( b == -1 ){
5991                         b = 0;
5992                 }
5993                 shipp->weapons.current_primary_bank = (int)b;
5994
5995                 GET_DATA(b);
5996                 if ( b == -1 ){
5997                         b = 0;
5998                 }
5999                 shipp->weapons.current_secondary_bank = (int)b;         
6000
6001                         // primary weapon info
6002                 GET_DATA(b);
6003                 shipp->weapons.primary_bank_weapons[0] = (int)b;
6004
6005                 GET_DATA(b);
6006                 shipp->weapons.primary_bank_weapons[1] = (int)b;
6007
6008                 // secondary weapon info
6009                 GET_DATA(b);
6010                 shipp->weapons.secondary_bank_weapons[0] = (int)b;
6011                 GET_SHORT(val_short);
6012                 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
6013
6014                 GET_DATA(b);
6015                 shipp->weapons.secondary_bank_weapons[1] = (int)b;
6016                 GET_SHORT(val_short);
6017                 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
6018
6019                 GET_DATA(b);
6020                 shipp->weapons.secondary_bank_weapons[2] = (int)b;
6021                 GET_SHORT(val_short);
6022                 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6023
6024                 // other flags
6025                 val = 0x0;
6026                 GET_DATA(val);
6027
6028                 if(val & (1<<0)){
6029                         shipp->flags |= SF_PRIMARY_LINKED;                              
6030                 }                               
6031                 if(val & (1<<1)){               
6032                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;                 
6033                 }
6034                 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6035                 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6036                 if(val & (1<<2)){
6037                         Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6038                 } else {
6039                         obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6040                 }
6041
6042                 // get ship ets
6043                 GET_USHORT(ship_ets);
6044                 // shield ets
6045                 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6046                 // weapon ets
6047                 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6048                 // engine ets
6049                 shipp->engine_recharge_index = (ship_ets & 0x000f);     
6050         }
6051         PACKET_SET_SIZE();
6052
6053         // ack the server
6054         Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6055         send_netplayer_update_packet();
6056
6057         // the standalone server will receive this packet from the host of the game, to be applied locally and
6058         // also to be rebroadcast. 
6059         if(Game_mode & GM_STANDALONE_SERVER){
6060                 // update player ets settings
6061                 for(idx=0;idx<MAX_PLAYERS;idx++){
6062                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6063                                 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6064                         }
6065                 }                       
6066                 
6067                 send_post_sync_data_packet(NULL,0);
6068         }
6069 }
6070
6071 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6072 {
6073         ubyte data[MAX_PACKET_SIZE],val;
6074         short val_short;
6075         int idx,i;
6076         int packet_size = 0;
6077
6078         // build the header
6079         BUILD_HEADER(WSS_SLOTS_DATA);
6080
6081         // some header information for standalone packet routing purposes
6082         val = (ubyte)std_request;
6083         ADD_DATA(val);
6084
6085         // add the team #
6086         val = (ubyte)team_num;
6087         ADD_DATA(val);
6088         
6089         // add whether this is the final packet or not
6090         val = (ubyte)final;
6091         ADD_DATA(val);
6092
6093         // the standalone has two situations
6094         // 1.) sending a request to the host to distribute this block of data
6095         // 2.) having recevied this block of data from the host, it redistributes it
6096         if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6097                 // case 1, send the request                                     
6098                 multi_io_send_reliable(Netgame.host, data, packet_size);
6099                 return;
6100         }
6101         // case 2 for the standalone is below (as normal)
6102
6103         // add all the slots
6104         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6105                 // add the ship class
6106                 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6107                 ADD_DATA(val);
6108
6109                 // add the weapons
6110                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6111                         val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6112                         ADD_DATA(val);
6113                 }
6114
6115                 // add the weapon counts
6116                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6117                         val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6118                         ADD_SHORT(val_short);
6119                 }
6120         }
6121
6122                 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6123         // or if I'm the server as well as the host, I should be sending this to all players
6124         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6125                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6126                         // broadcast
6127                         if(p == NULL){                          
6128                                 multi_io_send_to_all_reliable(data, packet_size);
6129                         }
6130                         // send to a specific player
6131                         else {
6132                                 multi_io_send_reliable(p, data, packet_size);
6133                         }
6134                 } else {
6135                         multi_io_send_reliable(Net_player, data, packet_size);
6136                 }
6137         }
6138         // standalone mode
6139         else {
6140                 // broadcast
6141                 if(p == NULL){
6142                         multi_io_send_to_all_reliable(data, packet_size);                       
6143                 }
6144                 // send to a specific player
6145                 else {
6146                         multi_io_send_reliable(p, data, packet_size);
6147                 }
6148         }       
6149 }
6150
6151 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6152 {
6153         ubyte val,team_num,final;
6154         int idx,i;
6155         int offset = HEADER_LENGTH;
6156         short val_short;
6157
6158         // packet routing information
6159         GET_DATA(val);
6160
6161         // get team data
6162         GET_DATA(team_num);
6163
6164         // get whether this is the final packet or not
6165         GET_DATA(final);
6166
6167         // 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
6168         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6169                 PACKET_SET_SIZE();
6170
6171                 // send to the standalone through my socket
6172                 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6173                 return;
6174         }       
6175
6176         // read in all the slot data
6177         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6178                 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6179
6180                 // get the ship class
6181                 GET_DATA(val);
6182                 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6183
6184                 // get the weapons
6185                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6186                         GET_DATA(val);
6187                         Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6188
6189                         // check for signed/unsigned problems
6190                         if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6191                                 Wss_slots_teams[team_num][idx].wep[i] = -1;
6192                         }
6193                 } 
6194
6195                 // get the weapon counts
6196                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6197                         GET_SHORT(val_short);
6198                         Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6199                 }
6200         }
6201         PACKET_SET_SIZE();
6202
6203         // update my netplayer state if this is the final packet
6204         if(final){
6205                 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6206                 send_netplayer_update_packet();
6207         }
6208
6209         // the standalone server will receive this packet from the host of the game, to be applied locally and
6210         // also to be rebroadcast. 
6211         if(Game_mode & GM_STANDALONE_SERVER){
6212                 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6213         } else {
6214                 // add some mission sync text
6215                 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6216         }
6217 }
6218
6219 #define OBJ_VISIBILITY_DOT                                      0.6f    
6220
6221 // send and receive packets for shield explosion information
6222 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6223 {
6224         int packet_size, i;
6225         ubyte data[MAX_PACKET_SIZE], utri_num;
6226
6227         Int3();
6228         // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6229
6230         SDL_assert( tri_num < UCHAR_MAX );
6231         utri_num = (ubyte)tri_num;
6232
6233         // for each player, determine if this object is behind the player -- if so, don't
6234         // send the packet.
6235         for ( i = 0; i < MAX_PLAYERS; i++ ) {
6236                 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6237                         float           dot;
6238                         vector  eye_to_obj_vec, diff, eye_pos;
6239                         matrix  eye_orient;
6240
6241                         eye_pos = Net_players[i].s_info.eye_pos;
6242                         eye_orient = Net_players[i].s_info.eye_orient;
6243
6244                         // check for same vectors
6245                         vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6246                         if ( vm_vec_mag_quick(&diff) < 0.01 ){
6247                                 continue;
6248                         }
6249
6250                         vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6251                         dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6252
6253                         if ( dot < OBJ_VISIBILITY_DOT ){
6254                                 continue;
6255                         }
6256
6257                         BUILD_HEADER(SHIELD_EXPLOSION);
6258
6259                         ADD_USHORT( Objects[objnum].net_signature );
6260                         ADD_DATA(utri_num);                     
6261                         
6262                         multi_io_send(&Net_players[i], data, packet_size);
6263                 }
6264         }
6265 }
6266
6267 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6268
6269 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6270 {
6271         int offset;
6272         ushort signature;
6273         ubyte utri_num;
6274         object *objp;
6275
6276         // get the shield hit data
6277         offset = HEADER_LENGTH;
6278         GET_USHORT(signature);
6279         GET_DATA(utri_num);
6280         //GET_DATA(hit_pos);
6281         PACKET_SET_SIZE();
6282
6283         // find the object with this signature.  If found, then do a shield explosion
6284         objp = multi_get_network_object( signature );
6285         if ( objp ) {
6286                 polymodel *pm;
6287                 shield_info *shieldp;
6288                 shield_tri stri;
6289                 vector hit_pos;
6290                 int i;
6291
6292                 // given the tri num, find the local position which is the average of the
6293                 // three vertices of the triangle affected.  Use this average point as the hit
6294                 // point
6295                 // SDL_assert( objp->type == OBJ_SHIP );
6296                 if(objp->type != OBJ_SHIP){
6297                         return;
6298                 }
6299
6300                 pm = model_get(Ships[objp->instance].modelnum);
6301                 shieldp = &pm->shield;
6302                 SDL_assert( utri_num < shieldp->ntris );
6303                 stri = shieldp->tris[utri_num];
6304                 vm_vec_zero(&hit_pos);
6305                 for ( i = 0; i < 3; i++ ) {
6306                         vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6307                 }
6308                 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6309                 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6310         }
6311 }
6312
6313 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6314 {
6315         scoring_struct *sc;
6316         ubyte data[MAX_PACKET_SIZE], val;
6317         int idx;                
6318         int packet_size = 0;
6319
6320         ushort u_tmp;
6321         int i_tmp;
6322
6323         sc = &pl->player->stats;
6324
6325         // build the header
6326         BUILD_HEADER(PLAYER_STATS);     
6327
6328         // add the player id
6329         ADD_SHORT(pl->player_id);
6330
6331         // add the byte indicating whether these stats are all-time or not
6332         val = (ubyte)stats_code;
6333         ADD_DATA(val);  
6334         
6335         // kill information - alltime
6336         switch(stats_code){
6337         case STATS_ALLTIME:     
6338                 // alltime kills
6339                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6340                         u_tmp = sc->kills[idx];
6341                         ADD_USHORT(u_tmp);
6342                 }
6343                 // medal information
6344                 for(idx=0;idx<NUM_MEDALS;idx++){
6345                         i_tmp = sc->medals[idx];
6346                         ADD_INT(i_tmp);
6347                 }
6348
6349                 ADD_INT(sc->score);
6350                 ADD_INT(sc->rank);
6351                 ADD_INT(sc->assists);
6352                 ADD_INT(sc->kill_count);
6353                 ADD_INT(sc->kill_count_ok);
6354                 ADD_UINT(sc->p_shots_fired);
6355                 ADD_UINT(sc->s_shots_fired);
6356                 ADD_UINT(sc->p_shots_hit);
6357                 ADD_UINT(sc->s_shots_hit);
6358                 ADD_UINT(sc->p_bonehead_hits);
6359                 ADD_UINT(sc->s_bonehead_hits);
6360                 ADD_INT(sc->bonehead_kills);
6361
6362                 ADD_UINT(sc->missions_flown);
6363                 ADD_UINT(sc->flight_time);
6364                 ADD_INT(sc->last_flown);
6365                 ADD_INT(sc->last_backup);
6366                 break;
6367
6368         case STATS_MISSION:     
6369                 // mission OKkills              
6370                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6371                         u_tmp = sc->m_okKills[idx];
6372                         ADD_USHORT(u_tmp);                      
6373                 }
6374         
6375                 ADD_INT(sc->m_score);
6376                 ADD_INT(sc->m_assists);
6377                 ADD_INT(sc->m_kill_count);
6378                 ADD_INT(sc->m_kill_count_ok);
6379                 ADD_UINT(sc->mp_shots_fired);
6380                 ADD_UINT(sc->ms_shots_fired);
6381                 ADD_UINT(sc->mp_shots_hit);
6382                 ADD_UINT(sc->ms_shots_hit);
6383                 ADD_UINT(sc->mp_bonehead_hits);
6384                 ADD_UINT(sc->ms_bonehead_hits);
6385                 ADD_INT(sc->m_bonehead_kills);
6386                 ADD_INT(sc->m_player_deaths);
6387                 ADD_INT(sc->m_medal_earned);
6388                 break;
6389
6390         case STATS_MISSION_KILLS:               
6391                 ADD_INT(sc->m_kill_count);
6392                 ADD_INT(sc->m_kill_count_ok);
6393                 ADD_INT(sc->m_assists);
6394                 break;          
6395
6396         case STATS_DOGFIGHT_KILLS:
6397                 for(idx=0; idx<MAX_PLAYERS; idx++){
6398 #ifndef MAKE_FS1
6399                         u_tmp = sc->m_dogfight_kills[idx];
6400 #else
6401                         u_tmp = 0;
6402 #endif
6403                         ADD_USHORT(u_tmp);
6404                 }
6405                 ADD_INT(sc->m_kill_count);
6406                 ADD_INT(sc->m_kill_count_ok);
6407                 ADD_INT(sc->m_assists);
6408                 break;          
6409         }
6410
6411         SDL_assert(packet_size < MAX_PACKET_SIZE);
6412
6413         // if we're a client, always send the data to the server
6414         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6415                 multi_io_send_reliable(Net_player, data, packet_size);          
6416         }
6417         // otherwise do server specific stuff
6418         else {
6419                 // send to a specific target
6420                 if(target != NULL){
6421                         multi_io_send_reliable(target, data, packet_size);                      
6422                 }
6423                 // otherwise, send to everyone
6424                 else {                  
6425                         multi_io_send_to_all_reliable(data, packet_size);
6426                 }
6427         }
6428 }
6429
6430 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6431 {
6432         ubyte val;
6433         int player_num,idx;
6434         scoring_struct *sc,bogus;
6435         short player_id;
6436         int offset = HEADER_LENGTH;
6437         ushort u_tmp;
6438         int i_tmp;
6439
6440         // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6441
6442         // get the player who these stats are for
6443         GET_SHORT(player_id);   
6444         player_num = find_player_id(player_id);
6445         if (player_num == -1) {
6446                 nprintf(("Network", "Couldn't find player for stats update!\n"));
6447                 ml_string("Couldn't find player for stats update!");
6448
6449                 sc = &bogus;
6450                 Int3();
6451         } else {
6452                 sc = &Net_players[player_num].player->stats;
6453         }
6454
6455         // get the stats code
6456         GET_DATA(val);  
6457         switch(val){
6458         case STATS_ALLTIME:
6459                 ml_string("Received STATS_ALLTIME");
6460
6461                 // kills - alltime
6462                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6463                         GET_USHORT(u_tmp);
6464                         sc->kills[idx] = u_tmp;
6465                 }
6466
6467                 // read in the stats
6468                 for (idx=0; idx<NUM_MEDALS; idx++) {
6469                         GET_INT(i_tmp);
6470                         sc->medals[idx] = i_tmp;
6471                 }
6472
6473                 GET_INT(sc->score);
6474                 GET_INT(sc->rank);
6475                 GET_INT(sc->assists);
6476                 GET_INT(sc->kill_count);
6477                 GET_INT(sc->kill_count_ok);
6478                 GET_UINT(sc->p_shots_fired);
6479                 GET_UINT(sc->s_shots_fired);
6480                 GET_UINT(sc->p_shots_hit);
6481                 GET_UINT(sc->s_shots_hit);
6482                 GET_UINT(sc->p_bonehead_hits);
6483                 GET_UINT(sc->s_bonehead_hits);
6484                 GET_INT(sc->bonehead_kills);
6485
6486                 GET_UINT(sc->missions_flown);
6487                 GET_UINT(sc->flight_time);
6488                 GET_INT(sc->last_flown);
6489                 GET_INT(sc->last_backup);
6490                 break;
6491
6492         case STATS_MISSION:
6493                 ml_string("Received STATS_MISSION");
6494
6495                 // kills - mission OK                   
6496                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6497                         GET_USHORT(u_tmp);
6498                         sc->m_okKills[idx] = u_tmp;                     
6499                 }
6500                 
6501                 GET_INT(sc->m_score);
6502                 GET_INT(sc->m_assists);
6503                 GET_INT(sc->m_kill_count);
6504                 GET_INT(sc->m_kill_count_ok);
6505                 GET_UINT(sc->mp_shots_fired);
6506                 GET_UINT(sc->ms_shots_fired);
6507                 GET_UINT(sc->mp_shots_hit);
6508                 GET_UINT(sc->ms_shots_hit);
6509                 GET_UINT(sc->mp_bonehead_hits);
6510                 GET_UINT(sc->ms_bonehead_hits);
6511                 GET_INT(sc->m_bonehead_kills);
6512                 GET_INT(sc->m_player_deaths);
6513                 GET_INT(sc->m_medal_earned);
6514                 break;
6515
6516         case STATS_MISSION_KILLS:               
6517                 ml_string("Received STATS_MISSION_KILLS");
6518
6519                 GET_INT(sc->m_kill_count);
6520                 GET_INT(sc->m_kill_count_ok);
6521                 GET_INT(sc->m_assists);
6522                 break;          
6523
6524         case STATS_DOGFIGHT_KILLS:
6525                 ml_string("Received STATS_DOGFIGHT_KILLS");
6526                 if(player_num >= 0){
6527                         ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6528                 }
6529                 for(idx=0; idx<MAX_PLAYERS; idx++){
6530                         GET_USHORT(u_tmp);
6531 #ifndef MAKE_FS1
6532                         sc->m_dogfight_kills[idx] = u_tmp;
6533                         if(player_num >= 0){                            
6534                                 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6535                         }
6536 #endif
6537                 }
6538                 GET_INT(sc->m_kill_count);
6539                 GET_INT(sc->m_kill_count_ok);
6540                 GET_INT(sc->m_assists);         
6541                 break;          
6542         }
6543         PACKET_SET_SIZE();
6544
6545         // if I'm the server of the game, I should always rebroadcast these stats
6546         if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6547                 // make sure these are alltime stats
6548                 SDL_assert(val == STATS_ALLTIME);
6549
6550                 multi_broadcast_stats(STATS_ALLTIME);
6551         }
6552 }
6553
6554 // called to create asteroid stuff
6555 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6556 {
6557         int packet_size;
6558         ubyte data[MAX_PACKET_SIZE];
6559         ubyte packet_type, atype;
6560         vector vec;
6561
6562         vm_vec_zero(&vec);
6563         if (relvec != NULL )
6564                 vec = *relvec;
6565
6566         BUILD_HEADER( ASTEROID_INFO );
6567         packet_type = ASTEROID_CREATE;
6568
6569         SDL_assert( asteroid_type < UCHAR_MAX );
6570         atype = (ubyte)asteroid_type;
6571
6572         ADD_DATA( packet_type );
6573         ADD_USHORT( parent_objp->net_signature );
6574         ADD_USHORT( new_objp->net_signature );
6575         ADD_DATA( atype );
6576         //ADD_DATA( vec );
6577         add_vector_data( data, &packet_size, vec );
6578
6579         multi_io_send_to_all(data, packet_size);
6580 }
6581
6582 void send_asteroid_throw( object *objp )
6583 {
6584         int packet_size;
6585         ubyte data[MAX_PACKET_SIZE], packet_type;
6586
6587         BUILD_HEADER( ASTEROID_INFO );
6588
6589         // this packet type is an asteroid throw
6590         packet_type = ASTEROID_THROW;
6591         ADD_DATA( packet_type );
6592         ADD_USHORT( objp->net_signature );
6593         //ADD_DATA( objp->pos );
6594         add_vector_data( data, &packet_size, objp->pos );
6595         //ADD_DATA( objp->phys_info.vel );
6596         add_vector_data( data, &packet_size, objp->phys_info.vel );
6597         
6598         multi_io_send_to_all(data, packet_size);
6599 }
6600
6601 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6602 {
6603         int packet_size;
6604         ubyte data[MAX_PACKET_SIZE], packet_type;
6605         vector vec;
6606
6607         vm_vec_zero(&vec);
6608         if ( hitpos != NULL )
6609                 vec = *hitpos;
6610
6611         // build up an asteroid hit packet
6612         BUILD_HEADER( ASTEROID_INFO );
6613         packet_type = ASTEROID_HIT;
6614         ADD_DATA( packet_type );
6615         ADD_USHORT( objp->net_signature );
6616
6617         if(other_objp == NULL){
6618                 ushort invalid_sig = 0xffff;
6619                 ADD_USHORT(invalid_sig);
6620         } else {
6621                 ADD_USHORT( other_objp->net_signature );
6622         }
6623         //ADD_DATA( vec );
6624         add_vector_data( data, &packet_size, vec );
6625         ADD_FLOAT( damage );
6626         
6627         multi_io_send_to_all(data, packet_size);
6628 }
6629
6630 void process_asteroid_info( ubyte *data, header *hinfo )
6631 {
6632         int offset;
6633         ubyte packet_type;
6634
6635         offset = HEADER_LENGTH;
6636         GET_DATA( packet_type );
6637
6638         // based on the packet type, do something interesting with an asteroid!
6639         switch( packet_type ) {
6640
6641         case ASTEROID_CREATE: {
6642                 ushort psignature, signature;
6643                 ubyte atype;
6644                 vector relvec = ZERO_VECTOR;
6645                 object *parent_objp;
6646
6647                 GET_USHORT( psignature );
6648                 GET_USHORT( signature );
6649                 GET_DATA( atype );
6650                 //GET_DATA( relvec );
6651                 get_vector_data( data, &offset, relvec );
6652
6653                 // after getting the values, set the next network signature, and call the create sub function
6654                 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6655                 parent_objp = multi_get_network_object( psignature );
6656                 if ( parent_objp ) {
6657                         asteroid_sub_create( parent_objp, atype, &relvec );
6658                 } else {
6659                         nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6660                 }
6661
6662
6663                 break;
6664         }
6665
6666                 // asteroid throw packet -- asteroid has wrapped bounds
6667         case ASTEROID_THROW: {
6668                 ushort signature;
6669                 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6670                 object *objp;
6671
6672                 GET_USHORT( signature );
6673                 //GET_DATA( pos );
6674                 get_vector_data( data, &offset, pos );
6675                 //GET_DATA( vel );
6676                 get_vector_data( data, &offset, vel );
6677                 objp = multi_get_network_object( signature );
6678                 if ( !objp ) {
6679                         nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6680                         break;
6681                 }
6682                 objp->pos = pos;
6683                 objp->phys_info.vel = vel;
6684                 objp->phys_info.desired_vel = vel;
6685                 break;
6686         }
6687
6688         case ASTEROID_HIT: {
6689                 ushort signature, osignature;
6690                 object *objp, *other_objp;
6691                 vector hitpos = ZERO_VECTOR;
6692                 float damage;
6693
6694                 GET_USHORT( signature );
6695                 GET_USHORT( osignature );
6696                 //GET_DATA( hitpos );
6697                 get_vector_data( data, &offset, hitpos );
6698                 GET_FLOAT( damage );
6699
6700                 objp = multi_get_network_object( signature );
6701                 if(osignature == 0xffff){
6702                         other_objp = NULL; 
6703                 } else {
6704                         other_objp = multi_get_network_object( osignature );
6705                 }
6706                 if ( !objp ) {
6707                         nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6708                         break;
6709                 }
6710
6711                 if ( IS_VEC_NULL(&hitpos) ){
6712                         asteroid_hit( objp, other_objp, NULL, damage );
6713                 } else {
6714                         asteroid_hit( objp, other_objp, &hitpos, damage );
6715                 }
6716                 
6717                 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6718                 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6719                         weapon_hit( other_objp, objp, &hitpos );
6720                 }
6721                 break;
6722         }
6723
6724         default:
6725                 Int3();
6726                 break;
6727         }
6728
6729         PACKET_SET_SIZE();
6730 }
6731
6732 void send_host_restr_packet(const char *callsign, int code, int mode)
6733 {
6734         ubyte data[MAX_PACKET_SIZE],val;
6735         int packet_size = 0;
6736
6737         // build the header and add the opcode
6738         BUILD_HEADER(HOST_RESTR_QUERY);
6739         val = (ubyte)code;
6740         ADD_DATA(val);
6741         val = (ubyte)mode;
6742         ADD_DATA(val);
6743
6744         // add the callsign
6745         ADD_STRING(callsign);
6746
6747         // if I'm the standalone server, I should be sending this to the game host
6748         if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){               
6749                 multi_io_send_reliable(Netgame.host, data, packet_size);
6750         } 
6751         // otherwise if I'm the host, I should be sending a reply back to the standalone server
6752         else {
6753                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);         
6754                 multi_io_send_reliable(Net_player, data, packet_size);
6755         }
6756 }       
6757
6758 void process_host_restr_packet(ubyte *data, header *hinfo)
6759 {
6760         char callsign[255];
6761         ubyte code,mode;
6762         int offset = HEADER_LENGTH;
6763
6764         // get the opcode and the callsign
6765         GET_DATA(code);
6766         GET_DATA(mode);
6767         GET_STRING(callsign);
6768         PACKET_SET_SIZE();
6769
6770         // do code specific operations
6771         switch(code){
6772         // query to the host from standalone
6773         case 0:         
6774                 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6775
6776                 // set the join mode
6777                 Multi_join_restr_mode = mode;
6778
6779                 // set the timestamp
6780                 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6781
6782                 // notify the host of the event
6783                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6784                 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6785                 break;
6786                 
6787         // affirmative reply from the host to the standalone
6788         case 1:
6789                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);           
6790
6791                 // let the player join if the timestamp has not already elapsed on the server
6792                 if(Multi_restr_query_timestamp != -1){
6793                         multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6794                 }
6795                 break;  
6796
6797         // negative reply
6798         case 2 :
6799                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6800                 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6801                 Multi_restr_query_timestamp = -1;
6802                 break;
6803         }
6804 }
6805
6806 void send_netgame_end_error_packet(int notify_code,int err_code)
6807 {
6808         ubyte data[10];
6809         char code;
6810         int packet_size = 0;
6811
6812         // only the server should ever be here - although this might change if for some reason the host wants to end the game
6813         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6814         
6815         // build the header and add the notification and error codes
6816         BUILD_HEADER(NETGAME_END_ERROR);
6817         code = (char)notify_code;
6818         ADD_DATA(code);
6819         code = (char)err_code;
6820         ADD_DATA(code);
6821
6822         // send the packet      
6823         multi_io_send_to_all_reliable(data, packet_size);
6824 }
6825
6826 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6827 {
6828         int offset = HEADER_LENGTH;
6829         char notify_code,error_code;
6830
6831         // get the error and notification codes
6832         GET_DATA(notify_code);
6833         GET_DATA(error_code);
6834         PACKET_SET_SIZE();
6835
6836         // quit the game
6837         multi_quit_game(PROMPT_NONE,notify_code,error_code);    
6838 }
6839
6840 // sends info that a countermeasure succeeded.
6841 void send_countermeasure_success_packet( int objnum )
6842 {
6843         int pnum, packet_size;
6844         ubyte data[MAX_PACKET_SIZE];
6845
6846         pnum = multi_find_player_by_object( &Objects[objnum] );
6847         if ( pnum == -1 ) {
6848                 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6849                 return;
6850         }
6851
6852         BUILD_HEADER(COUNTERMEASURE_SUCCESS);   
6853         multi_io_send(&Net_players[pnum], data, packet_size);
6854 }
6855
6856 // start the flashing of my hud gauge
6857 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6858 {
6859         int offset;
6860
6861         offset = HEADER_LENGTH;
6862         PACKET_SET_SIZE();
6863
6864         hud_start_text_flash(XSTR("Evaded", 1430), 800);
6865         snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6866 }
6867
6868 #define UPDATE_IS_PAUSED                (1<<0)
6869 #define UPDATE_HULL_INFO                (1<<1)
6870
6871 void send_client_update_packet(net_player *pl)
6872 {
6873         ubyte data[MAX_PACKET_SIZE],val;
6874         int packet_size = 0;
6875
6876         // build the header
6877         BUILD_HEADER(CLIENT_UPDATE);
6878
6879         val = 0;        
6880
6881         // add the pause status
6882         if ( Multi_pause_status ) {
6883                 val |= UPDATE_IS_PAUSED;
6884         } 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) ) {
6885                 val |= UPDATE_HULL_INFO;
6886                 SDL_assert( Player_ship );                      // I"d better have one of these!!!!
6887         }
6888
6889         ADD_DATA(val);
6890
6891         // if paused, add the net address of the guy who paused
6892         if(val & UPDATE_IS_PAUSED){
6893                 SDL_assert(Multi_pause_pauser != NULL);
6894                 ADD_SHORT(Multi_pause_pauser->player_id);
6895         }
6896
6897         // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6898         if ( val & UPDATE_HULL_INFO ) {
6899                 object *objp;
6900                 ubyte percent, ns, threats;
6901                 ship_info *sip;
6902                 ship *shipp;
6903                 ship_subsys *subsysp;
6904                 int i;
6905
6906                 // get the object for the player
6907                 SDL_assert( pl->player->objnum != -1 );
6908
6909                 objp = &Objects[pl->player->objnum];
6910
6911                 SDL_assert ( objp->type == OBJ_SHIP );
6912                 shipp = &Ships[objp->instance];
6913                 sip = &Ship_info[shipp->ship_info_index];
6914
6915                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
6916                 // percentage value since that should be close enough
6917                 float temp = (objp->hull_strength  / sip->initial_hull_strength * 100.0f);              
6918                 if(temp < 0.0f){
6919                         percent = 0;
6920                 } else {
6921                         percent = (ubyte)temp;
6922                 }
6923                 ADD_DATA( percent );
6924
6925                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6926                         percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6927                         ADD_DATA( percent );
6928                 }
6929
6930                 // add the data for the subsystem hits.  We can assume that the lists will be the same side of
6931                 // both machines. Added as percent since that number <= 100
6932
6933                 // also write out the number of subsystems.  We do this because the client might not know
6934                 // about the object he is getting data for.  (i.e. he killed the object already).
6935                 ns = (ubyte)sip->n_subsystems;
6936                 ADD_DATA( ns );
6937
6938                 // now the subsystems.
6939                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6940                         percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6941                         ADD_DATA( percent );
6942                 }
6943
6944                 // compute the threats for this player.  Only compute the threats if this player is actually
6945                 // playing (i.e. he has a ship)
6946                 hud_update_reticle( pl->player );
6947                 threats = (ubyte)pl->player->threat_flags;
6948                 ADD_DATA( threats );
6949
6950                 // add his energy level for guns
6951                 ADD_FLOAT(shipp->weapon_energy);
6952
6953                 // add his secondary bank ammo
6954                 ADD_INT(shipp->weapons.num_secondary_banks);
6955                 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6956                         ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6957                 }
6958         }
6959
6960         // add pl
6961         ADD_INT(pl->sv_last_pl);
6962
6963         // send the packet reliably to the player       
6964         multi_io_send(pl, data, packet_size);
6965 }
6966
6967 void process_client_update_packet(ubyte *data, header *hinfo)
6968 {
6969         ubyte val;
6970         short pauser;
6971         int player_index;
6972         int is_paused, have_hull_info;
6973         int ammo_count;
6974         int ammo[10];
6975         float weapon_energy;
6976         int offset = HEADER_LENGTH;
6977
6978         // get the header byte containing useful information
6979         GET_DATA(val);
6980
6981         is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6982         have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6983
6984         // if we are paused, get who paused
6985         if(is_paused){          
6986                 GET_SHORT(pauser);
6987                 player_index = find_player_id(pauser);
6988                 if(player_index != -1){
6989                         Multi_pause_pauser = &Net_players[player_index];
6990                 } else {
6991                         Multi_pause_pauser = NULL;
6992                 }       
6993         }
6994
6995         // if we have hull information, then read it in.
6996         if ( have_hull_info ) {
6997                 float fval;
6998                 ship_info *sip;
6999                 ship *shipp;
7000                 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
7001                 ubyte ub_tmp;
7002                 ship_subsys *subsysp;
7003                 object *objp;
7004                 int i;
7005
7006                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
7007                 // percentage value since that should be close enough
7008                 GET_DATA( hull_percent );
7009
7010                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
7011                         GET_DATA(ub_tmp);
7012                         shield_percent[i] = ub_tmp;
7013                 }
7014
7015                 // get the data for the subsystems
7016                 GET_DATA( n_subsystems );
7017                 for ( i = 0; i < n_subsystems; i++ ){
7018                         GET_DATA(ub_tmp);
7019                         subsystem_percent[i] = ub_tmp;
7020                 }
7021
7022                 GET_DATA( threats );
7023
7024                 // add his energy level for guns
7025                 GET_FLOAT(weapon_energy);
7026                 
7027                 // add his secondary bank ammo
7028                 GET_INT(ammo_count);
7029                 for(i=0; i<ammo_count; i++){
7030                         GET_INT(ammo[i]);
7031                 }
7032
7033                 // assign the above information to my ship, assuming that I can find it!  Ingame joiners might get this
7034                 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7035                 // UDP client update packets.  Only read this info if I have a ship.
7036                 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {                        
7037                         shipp = Player_ship;
7038                         objp = Player_obj;
7039                         sip = &Ship_info[shipp->ship_info_index];
7040
7041                         fval = hull_percent * sip->initial_hull_strength / 100.0f;
7042                         objp->hull_strength = fval;
7043
7044                         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7045                                 fval = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7046                                 objp->shields[i] = fval;
7047                         }
7048
7049                         // for sanity, be sure that the number of susbystems that I read in matches the player.  If not,
7050                         // then don't read these in.
7051                         if ( n_subsystems == sip->n_subsystems ) {
7052
7053                                 n_subsystems = 0;               // reuse this variable
7054                                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7055                                         int subsys_type;
7056
7057                                         fval = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7058                                         subsysp->current_hits = fval;
7059
7060                                         // add the value just generated (it was zero'ed above) into the array of generic system types
7061                                         subsys_type = subsysp->system_info->type;                                       // this is the generic type of subsystem
7062                                         SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7063                                         shipp->subsys_info[subsys_type].current_hits += fval;
7064                                         n_subsystems++;
7065                                 }
7066                         }
7067                         ship_recalc_subsys_strength( shipp );
7068
7069                         shipp->weapon_energy = weapon_energy;
7070                         for(i=0; i<ammo_count; i++){
7071                                 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7072                         }
7073
7074                         // update my threat flags.
7075                         // temporarily commented out until tested.
7076                         Net_player->player->threat_flags = threats;
7077                 }
7078         }
7079
7080         // get pl
7081         int pl;
7082         GET_INT(pl);
7083         if(Net_player != NULL){
7084                 Net_player->cl_last_pl = pl;
7085         }
7086
7087         PACKET_SET_SIZE();
7088         // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7089         if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7090                 if( is_paused ) {
7091                         multi_pause_pause();
7092                 } else {
7093                         multi_pause_unpause();
7094                 }
7095         }
7096 }
7097
7098 void send_countdown_packet(int time)
7099 {
7100         ubyte data[20];
7101         char val;
7102         int packet_size = 0;
7103
7104         // build the header and add the time
7105         BUILD_HEADER(COUNTDOWN);
7106         val = (char)time;
7107         ADD_DATA(val);
7108
7109         // if we're the server, we should broadcast to everyone
7110         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
7111                 multi_io_send_to_all_reliable(data, packet_size);
7112         }
7113         // otherwise we'de better be a host sending to the standalone
7114         else {
7115                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7116                 multi_io_send_reliable(Net_player, data, packet_size);
7117         }
7118 }
7119
7120 void process_countdown_packet(ubyte *data, header *hinfo)
7121 {
7122         int offset = HEADER_LENGTH;
7123         char time;
7124
7125         // get the time
7126         GET_DATA(time);
7127         PACKET_SET_SIZE();
7128
7129         // if we're not in the post sync data screen, ignore it
7130         if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7131                 return;
7132         }
7133
7134         // if we're the standalone, this should be a -1 telling us to start the countdown
7135         if(Game_mode & GM_STANDALONE_SERVER){
7136                 SDL_assert((int)time == -1);
7137
7138                 // start the countdown
7139                 multi_sync_start_countdown();
7140         }
7141         // otherwise if we're clients, just bash the countdown
7142         else {          
7143                 Multi_sync_countdown = (int)time;
7144         }
7145 }
7146
7147 // packets for debriefing information
7148 void send_debrief_info( int stage_count[], int *stages[] )
7149 {
7150         ubyte data[MAX_PACKET_SIZE];
7151         int packet_size, i, j;
7152         int i_tmp;
7153
7154         BUILD_HEADER(DEBRIEF_INFO);
7155
7156         // add the data for the teams
7157         for ( i = 0; i < Num_teams; i++ ) {
7158                 int count;
7159
7160                 count = stage_count[i];
7161                 ADD_INT( count );
7162                 for ( j = 0; j < count; j++ ) {
7163                         i_tmp = stages[i][j];
7164                         ADD_INT( i_tmp );
7165                 }
7166         }
7167         
7168         multi_io_send_to_all_reliable(data, packet_size);
7169 }
7170
7171 // process a debrief info packet from the server
7172 void process_debrief_info( ubyte *data, header *hinfo )
7173 {
7174         int offset, i, j;
7175         int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7176         int i_tmp;
7177
7178         offset = HEADER_LENGTH;
7179         for ( i = 0; i < Num_teams; i++ ) {
7180                 int count;
7181
7182                 GET_INT( count );
7183                 stage_counts[i] = count;
7184                 stages[i] = active_stages[i];
7185                 for ( j = 0; j < count; j++ ) {
7186                         GET_INT(i_tmp);
7187                         active_stages[i][j] = i_tmp;
7188                 }
7189         }
7190         PACKET_SET_SIZE();
7191
7192         // now that we have the stage data for the debriefing stages, call debrief function with the
7193         // data so that clients can now see the debriefing stuff.  Do it only for my team.
7194         SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7195         debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7196 }
7197
7198 // sends homing information to all clients.  We only need signature and num_missiles (because of hornets).
7199 // sends homing_object and homing_subsystem to all clients.
7200 void send_homing_weapon_info( int weapon_num )
7201 {
7202         ubyte data[MAX_PACKET_SIZE];
7203         char t_subsys;
7204         int packet_size;
7205         object *homing_object;
7206         ushort homing_signature;
7207         weapon *wp;
7208
7209         wp = &Weapons[weapon_num];
7210
7211         // be sure that this weapon object is a homing object.
7212         if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7213                 return;
7214
7215         // get the homing signature.  If this weapon isn't homing on anything, then sent 0 as the
7216         // homing signature.
7217         homing_signature = 0;
7218         homing_object = wp->homing_object;
7219         if ( homing_object != NULL ) {
7220                 homing_signature = homing_object->net_signature;
7221
7222                 // get the subsystem index.
7223                 t_subsys = -1;
7224                 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7225                         int s_index;
7226
7227                         s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7228                         SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
7229                         t_subsys = (char)s_index;
7230                 }
7231         }
7232
7233         BUILD_HEADER(HOMING_WEAPON_UPDATE);
7234         ADD_USHORT( Objects[wp->objnum].net_signature );
7235         ADD_USHORT( homing_signature );
7236         ADD_DATA( t_subsys );
7237         
7238         multi_io_send_to_all(data, packet_size);
7239 }
7240
7241 // process a homing weapon info change packet.  multiple_missiles parameter specifies is this
7242 // packet contains information for multiple weapons (like hornets).
7243 void process_homing_weapon_info( ubyte *data, header *hinfo )
7244 {
7245         int offset;
7246         ushort weapon_signature, homing_signature;
7247         char h_subsys;
7248         object *homing_object, *weapon_objp;
7249         weapon *wp;
7250
7251         offset = HEADER_LENGTH;
7252
7253         // get the data for the packet
7254         GET_USHORT( weapon_signature );
7255         GET_USHORT( homing_signature );
7256         GET_DATA( h_subsys );
7257         PACKET_SET_SIZE();
7258
7259         // deal with changing this weapons homing information
7260         weapon_objp = multi_get_network_object( weapon_signature );
7261         if ( weapon_objp == NULL ) {
7262                 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7263                 return;
7264         }
7265         SDL_assert( weapon_objp->type == OBJ_WEAPON );
7266         wp = &Weapons[weapon_objp->instance];
7267
7268         // be sure that we can find these weapons and 
7269         homing_object = multi_get_network_object( homing_signature );
7270         if ( homing_object == NULL ) {
7271                 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7272                 return;
7273         }
7274
7275         if ( homing_object->type == OBJ_WEAPON ) {
7276                 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7277         }
7278
7279         wp->homing_object = homing_object;
7280         wp->homing_subsys = NULL;
7281         wp->target_num = OBJ_INDEX(homing_object);
7282         wp->target_sig = homing_object->signature;
7283         if ( h_subsys != -1 ) {
7284                 SDL_assert( homing_object->type == OBJ_SHIP );
7285                 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7286         }
7287
7288         if ( homing_object->type == OBJ_SHIP ) {
7289                 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7290         }
7291 }
7292
7293 void send_emp_effect(ushort net_sig, float intensity, float time)
7294 {
7295         ubyte data[25];
7296         int packet_size;
7297
7298         SDL_assert(MULTIPLAYER_MASTER);
7299
7300         // build the packet and add the opcode
7301         BUILD_HEADER(EMP_EFFECT);
7302         ADD_USHORT(net_sig);
7303         ADD_FLOAT(intensity);
7304         ADD_FLOAT(time);
7305
7306         // send it to the player                
7307         multi_io_send_to_all(data, packet_size);
7308 }
7309
7310 void process_emp_effect(ubyte *data, header *hinfo)
7311 {
7312         float intensity, time;
7313         ushort net_sig;
7314         object *objp;
7315         int offset = HEADER_LENGTH;
7316
7317         // read in the EMP effect data
7318         GET_USHORT(net_sig);
7319         GET_FLOAT(intensity);
7320         GET_FLOAT(time);
7321         PACKET_SET_SIZE();
7322
7323         // try and find the object
7324         objp = multi_get_network_object(net_sig);
7325         if((objp != NULL) && (objp->type == OBJ_SHIP)){         
7326                 // if i'm not an observer and I have a valid ship, play the EMP effect
7327                 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7328                         emp_start_local(intensity, time);
7329                 }
7330
7331                 // start the effect for the ship itself
7332                 emp_start_ship(objp, intensity, time);
7333         }
7334 }
7335
7336 // tells whether or not reinforcements are available
7337 void send_reinforcement_avail( int rnum )
7338 {
7339         ubyte data[25];
7340         int packet_size;
7341
7342         BUILD_HEADER(REINFORCEMENT_AVAIL);
7343         ADD_INT( rnum );        
7344         multi_io_send_to_all_reliable(data, packet_size);
7345 }
7346
7347 void process_reinforcement_avail( ubyte *data, header *hinfo )
7348 {
7349         int offset;
7350         int rnum;
7351
7352         offset = HEADER_LENGTH;
7353         GET_INT( rnum );
7354         PACKET_SET_SIZE();
7355
7356         // sanity check for a valid reinforcement number
7357         if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7358                 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7359         }
7360 }
7361
7362 void send_change_iff_packet(ushort net_signature, int new_team)
7363 {
7364         ubyte data[MAX_PACKET_SIZE];
7365         int packet_size = 0;
7366
7367         if(Net_player == NULL){
7368                 return;
7369         }
7370         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7371                 return;
7372         }
7373
7374         // build the packet and add the data
7375         BUILD_HEADER(CHANGE_IFF);
7376         ADD_USHORT(net_signature);
7377         ADD_INT(new_team);
7378
7379         // send to all players  
7380         multi_io_send_to_all_reliable(data, packet_size);
7381 }
7382
7383 void process_change_iff_packet( ubyte *data, header *hinfo)
7384 {
7385         int offset = HEADER_LENGTH;
7386         ushort net_signature;
7387         int new_team;   
7388         object *objp;
7389
7390         // get the data
7391         GET_USHORT(net_signature);
7392         GET_INT(new_team);
7393         PACKET_SET_SIZE();
7394
7395         // lookup the object
7396         objp = multi_get_network_object(net_signature);
7397         if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7398                 Ships[objp->instance].team = new_team;
7399         }       
7400 }
7401
7402 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7403 {
7404         int packet_size, objnum;
7405         ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7406         object *objp;   
7407         int np_index;
7408         net_player *ignore = NULL;
7409
7410         // sanity checking for now
7411         SDL_assert ( banks_fired <= 3 );
7412
7413         // get an object pointer for this ship.
7414         objnum = shipp->objnum;
7415         objp = &Objects[objnum];
7416
7417         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7418         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7419                 return;
7420         }
7421
7422         // just in case nothing got fired
7423         if(banks_fired <= 0){
7424                 return;
7425         }
7426
7427         // ubanks_fired = (ubyte)banks_fired;
7428         // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7429         // SDL_assert( current_bank <= 3 );
7430
7431         // insert the current primary bank into this byte
7432         // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7433
7434         // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7435         // if ( shipp->flags & SF_PRIMARY_LINKED ){
7436                 // ubanks_fired |= (1<<7);
7437         // }    
7438
7439         // determine if its a player ship and don't send to him if we're in "client firing" mode
7440         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7441         if(MULTIPLAYER_MASTER){
7442                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7443                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7444                         ignore = &Net_players[np_index];
7445                 }
7446         }
7447
7448         // build up the standard weapon fired packet.  This packet will get sent to all players if an AI
7449         // ship fired the primary weapons.  If a player fired the weaspon, then this packet will get sent
7450         // to every player but the guy who actullly fired the weapon.  This method is used to help keep client
7451         // and server in sync w.r.t. weapon energy for player ship
7452         BUILD_HEADER( PRIMARY_FIRED_NEW );
7453         ADD_USHORT(objp->net_signature);
7454         // ADD_DATA(ubanks_fired);
7455
7456         // if I'm a server, broadcast to all players
7457         if(MULTIPLAYER_MASTER){         
7458                 multi_io_send_to_all(data, packet_size, ignore);
7459
7460                 // TEST CODE
7461                 multi_rate_add(1, "wfi", packet_size);
7462         }
7463         // otherwise just send to the server
7464         else {
7465                 multi_io_send(Net_player, data, packet_size);           
7466         }
7467 }
7468
7469 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7470 {
7471         int offset; // linked;  
7472         // ubyte banks_fired, current_bank;
7473         object* objp;   
7474 //      ship *shipp;
7475         ushort shooter_sig;     
7476
7477         // read all packet info
7478         offset = HEADER_LENGTH;
7479         GET_USHORT(shooter_sig);
7480         // GET_DATA(banks_fired);
7481         PACKET_SET_SIZE();
7482
7483         // find the object this fired packet is operating on
7484         objp = multi_get_network_object( shooter_sig );
7485         if ( objp == NULL ) {
7486                 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7487                 return;
7488         }
7489         // if this object is not actually a valid ship, don't do anything
7490         if(objp->type != OBJ_SHIP){
7491                 return;
7492         }
7493         if(objp->instance < 0){
7494                 return;
7495         }
7496 //      shipp = &Ships[objp->instance];
7497         
7498         // get the link status of the primary banks
7499         // linked = 0;
7500         // if ( banks_fired & (1<<7) ) {
7501                 // linked = 1;
7502                 // banks_fired ^= (1<<7);
7503         // }
7504
7505         // get the current primary bank
7506         // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7507         // current_bank &= 0x3;
7508         // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7509         // shipp->weapons.current_primary_bank = current_bank;
7510
7511         // strip off all remaining bits and just keep which banks were actually fired.
7512         // banks_fired &= 0x3;
7513         
7514         // set the link status of the ship if not the player.  If it is the player, we will do sanity checking
7515         // only (for now).      
7516         // if ( !linked ){
7517 //              shipp->flags &= ~SF_PRIMARY_LINKED;
7518         // } else {
7519                 // shipp->flags |= SF_PRIMARY_LINKED;
7520         // }
7521
7522         // if we're in client firing mode, ignore ones for myself       
7523         if((Player_obj != NULL) && (Player_obj == objp)){               
7524                 return;
7525         }
7526                 
7527         ship_fire_primary( objp, 0, 1 );
7528 }
7529
7530 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7531 {
7532         ubyte data[MAX_PACKET_SIZE];
7533         int packet_size;
7534         int np_index;   
7535         net_player *ignore = NULL;
7536
7537         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7538         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7539                 return;
7540         }
7541
7542         SDL_assert ( cmeasure_count < UCHAR_MAX );
7543         BUILD_HEADER(COUNTERMEASURE_NEW);
7544         ADD_USHORT( objp->net_signature );
7545         ADD_INT( rand_val );
7546
7547         nprintf(("Network","Sending NEW countermeasure packet!\n"));
7548
7549         // determine if its a player ship and don't send to him if we're in "client firing" mode
7550         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7551         if(MULTIPLAYER_MASTER){
7552                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7553                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7554                         ignore = &Net_players[np_index];
7555                 }
7556         }
7557         
7558         // if I'm the server, send to all players
7559         if(MULTIPLAYER_MASTER){                 
7560                 multi_io_send_to_all(data, packet_size, ignore);
7561         } 
7562         // otherwise send to the server
7563         else {
7564                 multi_io_send(Net_player, data, packet_size);
7565         }
7566 }
7567
7568 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7569 {
7570         int offset;
7571         ushort signature;
7572         int rand_val;
7573         object *objp;   
7574
7575         offset = HEADER_LENGTH;
7576         GET_USHORT( signature );
7577         GET_INT( rand_val );
7578         PACKET_SET_SIZE();
7579
7580         objp = multi_get_network_object( signature );
7581         if ( objp == NULL ) {
7582                 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7583                 return;
7584         }
7585         if(objp->type != OBJ_SHIP){
7586                 return;
7587         }       
7588
7589         // if we're in client firing mode, ignore ones for myself
7590         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){         
7591         if((Player_obj != NULL) && (Player_obj == objp)){               
7592                 return;
7593         }
7594                 
7595         // make it so ship can fire right away!
7596         Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7597         if ( objp == Player_obj ){              
7598                 nprintf(("network", "firing countermeasure from my ship\n"));
7599         }
7600         ship_launch_countermeasure( objp, rand_val );                   
7601 }
7602
7603 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7604 {
7605         ubyte data[MAX_PACKET_SIZE];
7606         int packet_size = 0;    
7607         ubyte u_beam_info;
7608         char subsys_index;
7609         beam_info b_info;
7610
7611         // only the server should ever be doing this
7612         SDL_assert(MULTIPLAYER_MASTER);
7613
7614         // setup outgoing data
7615         SDL_assert(shooter != NULL);
7616         SDL_assert(turret != NULL);
7617         SDL_assert(target != NULL);
7618         SDL_assert(override != NULL);
7619         if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7620                 return;
7621         }
7622         u_beam_info = (ubyte)beam_info_index;
7623         subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7624         SDL_assert(subsys_index >= 0);
7625         if(subsys_index < 0){
7626                 return;
7627         }
7628
7629         // swap the beam_info override info into little endian byte order
7630         b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7631         b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7632         b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7633          
7634         b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7635         b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7636         b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7637          
7638         b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7639         b_info.shot_count = override->shot_count;
7640          
7641         for (int i = 0; i < b_info.shot_count; i++) {
7642                 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7643         }
7644
7645         // build the header
7646         BUILD_HEADER(BEAM_FIRED);
7647         ADD_USHORT(shooter->net_signature);
7648         ADD_DATA(subsys_index);
7649         ADD_USHORT(target->net_signature);
7650         ADD_DATA(u_beam_info);
7651         ADD_DATA(b_info);  // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7652
7653         // send to all clients  
7654         multi_io_send_to_all_reliable(data, packet_size);
7655 }
7656
7657 void process_beam_fired_packet(ubyte *data, header *hinfo)
7658 {
7659         int i,offset;
7660         ushort shooter_sig, target_sig;
7661         char subsys_index;
7662         ubyte u_beam_info;
7663         beam_info b_info;
7664         beam_fire_info fire_info;
7665
7666         // only clients should ever get this
7667         SDL_assert(MULTIPLAYER_CLIENT);
7668
7669         // read in packet data
7670         offset = HEADER_LENGTH;
7671         GET_USHORT(shooter_sig);
7672         GET_DATA(subsys_index);
7673         GET_USHORT(target_sig);
7674         GET_DATA(u_beam_info);
7675         GET_DATA(b_info);
7676
7677         PACKET_SET_SIZE();
7678
7679         // swap the beam_info override info into native byte order
7680         b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7681         b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7682         b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7683         b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7684         b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7685         b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7686         b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7687
7688         for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7689                 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7690         }
7691
7692         // lookup all relevant data
7693         fire_info.beam_info_index = (int)u_beam_info;
7694         fire_info.shooter = NULL;
7695         fire_info.target = NULL;
7696         fire_info.turret = NULL;
7697         fire_info.target_subsys = NULL;
7698         fire_info.beam_info_override = NULL;            
7699         fire_info.shooter = multi_get_network_object(shooter_sig);
7700         fire_info.target = multi_get_network_object(target_sig);
7701         fire_info.beam_info_override = &b_info;
7702         fire_info.accuracy = 1.0f;
7703         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)){
7704                 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7705                 return;
7706         }
7707         fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7708         if(fire_info.turret == NULL){
7709                 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7710                 return;
7711         }
7712
7713         // fire da beam
7714         beam_fire(&fire_info);
7715 }
7716
7717 void send_sw_query_packet(ubyte code, char *txt)
7718 {
7719         ubyte data[MAX_PACKET_SIZE];
7720         int packet_size = 0;
7721
7722         // build the packet and add the code
7723         BUILD_HEADER(SW_STD_QUERY);
7724         ADD_DATA(code);
7725         if((code == SW_STD_START) || (code == SW_STD_BAD)){             
7726                 ADD_STRING(txt);
7727         }
7728
7729         // if I'm the host, send to standalone
7730         if(MULTIPLAYER_HOST){
7731                 SDL_assert(!MULTIPLAYER_MASTER);
7732                 SDL_assert(code == SW_STD_START);               
7733                 multi_io_send_reliable(Net_player, data, packet_size);
7734         }
7735         // otherwise standalone sends back to host
7736         else {
7737                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7738                 SDL_assert(code != SW_STD_START);
7739                 SDL_assert(Netgame.host != NULL);
7740                 if(Netgame.host != NULL){                       
7741                         multi_io_send_reliable(Netgame.host, data, packet_size);
7742                 }
7743         }
7744 }
7745
7746 void process_sw_query_packet(ubyte *data, header *hinfo)
7747 {       
7748 }
7749
7750 void send_event_update_packet(int event)
7751 {
7752         ubyte data[MAX_PACKET_SIZE];
7753         ushort u_event = (ushort)event;
7754         int packet_size = 0;
7755
7756         // build the header and add the event
7757         BUILD_HEADER(EVENT_UPDATE);
7758         ADD_USHORT(u_event);
7759         ADD_INT(Mission_events[event].flags);
7760         ADD_INT(Mission_events[event].formula);
7761         ADD_INT(Mission_events[event].result);
7762         ADD_INT(Mission_events[event].count);
7763
7764         // send to all players  
7765         multi_io_send_to_all_reliable(data, packet_size);
7766 }
7767
7768 void process_event_update_packet(ubyte *data, header *hinfo)
7769 {
7770         int offset = HEADER_LENGTH;
7771         int store_flags;
7772         ushort u_event;
7773         
7774         // get the data
7775         GET_USHORT(u_event);
7776         store_flags = Mission_events[u_event].flags;
7777         GET_INT(Mission_events[u_event].flags);
7778         GET_INT(Mission_events[u_event].formula);
7779         GET_INT(Mission_events[u_event].result);
7780         GET_INT(Mission_events[u_event].count);
7781         PACKET_SET_SIZE();
7782
7783         // went from non directive special to directive special
7784         if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7785                 mission_event_set_directive_special(u_event);
7786         }
7787         // if we went directive special to non directive special
7788         else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7789                 mission_event_unset_directive_special(u_event);
7790         }       
7791 }
7792
7793 // weapon detonate packet
7794 void send_weapon_detonate_packet(object *objp)
7795 {
7796         ubyte data[MAX_PACKET_SIZE];
7797         int packet_size = 0;
7798
7799         // sanity checks
7800         SDL_assert(MULTIPLAYER_MASTER);
7801         if(!MULTIPLAYER_MASTER){
7802                 return;
7803         }
7804         SDL_assert(objp != NULL);
7805         if(objp == NULL){
7806                 return;
7807         }
7808
7809         // build the header and add the data
7810         BUILD_HEADER(WEAPON_DET);
7811         ADD_USHORT(objp->net_signature);
7812
7813         // send to all players
7814         multi_io_send_to_all(data, packet_size);
7815 }
7816
7817 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7818 {
7819         ushort net_sig;
7820         int offset = HEADER_LENGTH;
7821         object *objp = NULL;
7822
7823         // get the weapon signature
7824         GET_USHORT(net_sig);
7825         PACKET_SET_SIZE();
7826
7827         // lookup the weapon
7828         objp = multi_get_network_object(net_sig);
7829         if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7830                 weapon_detonate(objp);
7831         }
7832 }       
7833
7834 // flak fired packet
7835 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7836 {
7837         int packet_size;
7838         ushort pnet_signature;
7839         ubyte data[MAX_PACKET_SIZE], cindex;
7840         object *objp;   
7841         ship_subsys *ssp;
7842         short val;
7843
7844         // sanity
7845         if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7846                 return;
7847         }
7848
7849         // local setup -- be sure we are actually passing a weapon!!!!
7850         objp = &Objects[weapon_objnum];
7851         SDL_assert ( objp->type == OBJ_WEAPON );        
7852         pnet_signature = Objects[ship_objnum].net_signature;
7853
7854         SDL_assert( subsys_index < UCHAR_MAX );
7855         cindex = (ubyte)subsys_index;
7856
7857         ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7858         if(ssp == NULL){
7859                 return;
7860         }
7861
7862         // build the fire turret packet.  
7863         BUILD_HEADER(FLAK_FIRED);       
7864         packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7865         ADD_USHORT( pnet_signature );           
7866         ADD_DATA( cindex );
7867         val = (short)ssp->submodel_info_1.angs.h;
7868         ADD_SHORT( val );
7869         val = (short)ssp->submodel_info_2.angs.p;
7870         ADD_SHORT( val );       
7871         ADD_FLOAT( flak_range );
7872         
7873         multi_io_send_to_all(data, packet_size);
7874
7875         multi_rate_add(1, "flk", packet_size);
7876 }
7877
7878 void process_flak_fired_packet(ubyte *data, header *hinfo)
7879 {
7880         int offset, weapon_objnum, wid;
7881         ushort pnet_signature;
7882         vector pos, dir;
7883         matrix orient;
7884         vector o_fvec;
7885         ubyte turret_index;
7886         object *objp;
7887         ship_subsys *ssp;       
7888         ship *shipp;
7889         short pitch, heading;
7890         float flak_range;
7891
7892         // get the data for the turret fired packet
7893         offset = HEADER_LENGTH;         
7894         offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7895         GET_USHORT( pnet_signature );
7896         GET_DATA( turret_index );
7897         GET_SHORT( heading );
7898         GET_SHORT( pitch );     
7899         GET_FLOAT( flak_range );
7900         PACKET_SET_SIZE();                              // move our counter forward the number of bytes we have read
7901
7902         // find the object
7903         objp = multi_get_network_object( pnet_signature );
7904         if ( objp == NULL ) {
7905                 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7906                 return;
7907         }
7908
7909         // if this isn't a ship, do nothing
7910         if ( objp->type != OBJ_SHIP ){
7911                 return;
7912         }
7913
7914         // make an orientation matrix from the o_fvec
7915         vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7916
7917         // find this turret, and set the position of the turret that just fired to be where it fired.  Quite a
7918         // hack, but should be suitable.
7919         shipp = &Ships[objp->instance];
7920         ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7921         if(ssp == NULL){
7922                 return;
7923         }
7924         wid = ssp->system_info->turret_weapon_type;
7925         if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7926                 return;
7927         }
7928
7929         // bash the position and orientation of the turret
7930         ssp->submodel_info_1.angs.h = (float)heading;
7931         ssp->submodel_info_2.angs.p = (float)pitch;
7932
7933         // get the world position of the weapon
7934         ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7935
7936         // create the weapon object     
7937         weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7938         if (weapon_objnum != -1) {
7939                 if ( Weapon_info[wid].launch_snd != -1 ) {
7940                         snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7941                 }
7942
7943                 // create a muzzle flash from a flak gun based upon firing position and weapon type
7944                 flak_muzzle_flash(&pos, &dir, wid);
7945
7946                 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7947                 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7948         }
7949 }
7950
7951 #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);
7952 #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);
7953
7954 // player pain packet
7955 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7956 {
7957         ubyte data[MAX_PACKET_SIZE];
7958         ubyte windex;
7959         ushort udamage;
7960         int packet_size = 0;
7961
7962         SDL_assert(MULTIPLAYER_MASTER);
7963         if(!MULTIPLAYER_MASTER){
7964                 return;
7965         }
7966         SDL_assert(pl != NULL);
7967         if(pl == NULL){
7968                 return;
7969         }
7970
7971         // build the packet and add the code
7972         BUILD_HEADER(NETPLAYER_PAIN);
7973         windex = (ubyte)weapon_info_index;
7974         ADD_DATA(windex);
7975         udamage = (ushort)damage;
7976         ADD_USHORT(udamage);
7977         //ADD_DATA((*force));
7978         add_vector_data( data, &packet_size, *force );
7979         //ADD_DATA((*hitpos));
7980         add_vector_data( data, &packet_size, *hitpos );
7981
7982         // send to the player
7983         multi_io_send(pl, data, packet_size);
7984
7985         multi_rate_add(1, "pai", packet_size);
7986 }       
7987
7988 void process_player_pain_packet(ubyte *data, header *hinfo)
7989 {
7990         int offset;
7991         ubyte windex;
7992         ushort udamage;
7993         vector force = ZERO_VECTOR;
7994         vector local_hit_pos = ZERO_VECTOR;
7995         weapon_info *wip;
7996
7997         // get the data for the pain packet
7998         offset = HEADER_LENGTH;         
7999         GET_DATA(windex);
8000         GET_USHORT(udamage);
8001         //GET_DATA(force);
8002         get_vector_data( data, &offset, force );
8003         //GET_DATA(local_hit_pos);
8004         get_vector_data( data, &offset, local_hit_pos );
8005         PACKET_SET_SIZE();
8006
8007         mprintf(("PAIN!\n"));
8008
8009         // get weapon info pointer
8010         //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER));        // always true
8011         if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
8012                 return;
8013         }
8014         wip = &Weapon_info[windex];
8015
8016         // play the weapon hit sound
8017         SDL_assert(Player_obj != NULL);
8018         if(Player_obj == NULL){
8019                 return;
8020         }
8021         weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
8022
8023         // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
8024         ship_hit_pain((float)udamage);
8025
8026         // apply the whack      
8027         ship_apply_whack(&force, &local_hit_pos, Player_obj);   
8028 }
8029
8030 // lightning packet
8031 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8032 {
8033         ubyte data[MAX_PACKET_SIZE];
8034         char val;
8035         int packet_size = 0;
8036
8037         // build the header and add the data
8038         BUILD_HEADER(LIGHTNING_PACKET);
8039         val = (char)bolt_type;
8040         ADD_DATA(val);
8041         //ADD_DATA((*start));
8042         add_vector_data( data, &packet_size, *start );
8043         //ADD_DATA((*strike));
8044         add_vector_data( data, &packet_size, *strike );
8045
8046         // send to everyone unreliable for now
8047         multi_io_send_to_all(data, packet_size);
8048 }
8049
8050 void process_lightning_packet(ubyte *data, header *hinfo)
8051 {
8052         int offset;
8053         char bolt_type;
8054         vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8055
8056         // read the data
8057         offset = HEADER_LENGTH;
8058         GET_DATA(bolt_type);
8059 //      GET_DATA(start);
8060         get_vector_data(data, &offset, start);
8061 //      GET_DATA(strike);
8062         get_vector_data(data, &offset, strike);
8063         PACKET_SET_SIZE();
8064
8065         // invalid bolt?
8066         if(bolt_type < 0){
8067                 return;
8068         }
8069
8070         // fire it up
8071         nebl_bolt(bolt_type, &start, &strike);
8072 }
8073
8074 void send_bytes_recvd_packet(net_player *pl)
8075 {
8076         // only clients should ever be doing this
8077         if(pl == NULL){
8078                 return;
8079         }       
8080
8081         ubyte data[MAX_PACKET_SIZE];
8082         int packet_size = 0;
8083         BUILD_HEADER(BYTES_SENT);
8084         ADD_INT(pl->cl_bytes_recvd);
8085
8086         // send to the server
8087         multi_io_send_reliable(pl, data, packet_size);
8088 }
8089
8090 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8091 {
8092         int bytes;
8093         int pid;
8094         net_player *pl = NULL;
8095         int offset = HEADER_LENGTH;
8096         
8097         GET_INT(bytes);
8098         PACKET_SET_SIZE();
8099
8100         // not server?
8101         if(Net_player == NULL){
8102                 return;
8103         }
8104         if(!MULTIPLAYER_MASTER){
8105                 return;
8106         }
8107
8108         // make sure we know what player sent this
8109         pid = find_player_id(hinfo->id);
8110         if((pid < 0) || (pid >= MAX_PLAYERS)){
8111                 return;
8112         }
8113         pl = &Net_players[pid];
8114
8115         // compute his pl
8116         pl->cl_bytes_recvd = bytes;
8117         if(bytes < 0){
8118                 return;
8119         }
8120         pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8121
8122         // reset bytes sent
8123         pl->sv_bytes_sent = 0;
8124 }
8125
8126 // host transfer
8127 void send_host_captain_change_packet(short player_id, int captain_change)
8128 {
8129         ubyte data[MAX_PACKET_SIZE];
8130         int packet_size = 0;
8131
8132         // build the packet
8133         BUILD_HEADER(TRANSFER_HOST);
8134         ADD_SHORT(player_id);
8135         ADD_INT(captain_change);
8136
8137         // send to all
8138         multi_io_send_to_all_reliable(data, packet_size);
8139 }
8140
8141 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8142 {
8143         int offset = HEADER_LENGTH;
8144         int idx, found_player, captain_change;
8145         short player_id;
8146
8147         // get the player id
8148         GET_SHORT(player_id);
8149         GET_INT(captain_change);
8150         PACKET_SET_SIZE();
8151
8152         // captain change
8153         if(captain_change){
8154                 // flag the new guy             
8155                 for(idx=0; idx<MAX_PLAYERS; idx++){
8156                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8157                                 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8158                                 break;
8159                         }
8160                 }
8161         } else {
8162                 // unflag all old players
8163                 for(idx=0; idx<MAX_PLAYERS; idx++){
8164                         Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8165                 }
8166
8167                 // flag the new guy
8168                 found_player = 0;
8169                 for(idx=0; idx<MAX_PLAYERS; idx++){
8170                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8171                                 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8172
8173                                 // spew to the HUD config
8174                                 if(Net_players[idx].player != NULL){
8175                                         HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8176                                 }
8177
8178                                 found_player = 1;
8179                                 break;
8180                         }
8181                 }
8182
8183                 // doh
8184                 if(!found_player){
8185                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8186                 }
8187         }       
8188 }
8189
8190 void send_self_destruct_packet()
8191 {
8192         ubyte data[MAX_PACKET_SIZE];
8193         int packet_size = 0;
8194
8195         // bogus
8196         if(Net_player == NULL){
8197                 return;
8198         }
8199
8200         // if i'm the server, I shouldn't be here
8201         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8202         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8203                 return;
8204         }
8205         
8206         // only if this is valid
8207         if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8208                 return;
8209         }
8210
8211         // bogus object?
8212         if((Player_ship == NULL) || (Player_obj == NULL)){
8213                 return;
8214         }
8215
8216         // self destruct
8217         BUILD_HEADER(SELF_DESTRUCT);
8218         ADD_USHORT(Player_obj->net_signature);
8219
8220         // send to the server
8221         multi_io_send_reliable(Net_player, data, packet_size);
8222 }
8223
8224 void process_self_destruct_packet(ubyte *data, header *hinfo)
8225 {
8226         int offset = HEADER_LENGTH;
8227         ushort net_sig;
8228         int np_index;
8229
8230         // get the net signature
8231         GET_USHORT(net_sig);
8232         PACKET_SET_SIZE();
8233
8234         // get the player
8235         np_index = find_player_id(hinfo->id);
8236         if(np_index < 0){
8237                 return;
8238         }
8239         if(MULTI_OBSERVER(Net_players[np_index])){
8240                 return;
8241         }
8242         if(Net_players[np_index].player == NULL){
8243                 return;
8244         }
8245         if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8246                 return;
8247         }
8248         if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8249                 return;
8250         }
8251         if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8252                 return;
8253         }
8254         if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8255                 return;
8256         }
8257
8258         // do eet
8259         ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);
8260 }