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