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