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