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