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