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