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