]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multimsgs.cpp
make gtrack compatible with FS1
[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                 // mark his socket as still alive (extra precaution)
3543                 psnet_mark_received(Net_players[lookup].reliable_socket);
3544         }
3545         // otherwise, do any special processing
3546         else {
3547                 // if we're in the join game state, see if this pong came from a server on our
3548                 // list
3549                 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3550                         multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3551                 }
3552         }
3553 }
3554
3555 // send a ping packet
3556 void send_ping(net_addr *addr)
3557 {
3558         unsigned char data[8];
3559         int packet_size;
3560
3561         // build the header and send the packet
3562         BUILD_HEADER( PING );           
3563         psnet_send(addr, &data[0], packet_size);
3564 }
3565
3566 // send a pong packet
3567 void send_pong(net_addr *addr)
3568 {
3569    unsigned char data[8];
3570         int packet_size;        
3571
3572         // build the header and send the packet
3573         BUILD_HEADER(PONG);             
3574         psnet_send(addr, &data[0], packet_size);   
3575 }
3576
3577 // sent from host to master. give me the list of missions you have.
3578 // this will be used only in a standalone mode
3579 void send_mission_list_request( int what )
3580 {
3581         ubyte data[MAX_PACKET_SIZE];
3582         int packet_size;
3583
3584         // build the header and ask for a list of missions or campaigns (depending
3585         // on the 'what' flag).
3586         BUILD_HEADER(MISSION_REQUEST);
3587                 
3588         multi_io_send_reliable(Net_player, data, packet_size);
3589 }
3590
3591 // maximum number of bytes that we can send in a mission items packet.
3592 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3593
3594 // defines used to tell what type of packets are being sent
3595 #define MISSION_LIST_ITEMS                      1
3596 #define CAMPAIGN_LIST_ITEMS             2
3597
3598 // send an individual mission file item
3599 void send_mission_items( net_player *pl )
3600 {
3601         ubyte data[MAX_PACKET_SIZE];
3602         int packet_size, i;
3603         ubyte stop, type;
3604
3605         // build the header     
3606         BUILD_HEADER(MISSION_ITEM);     
3607
3608         // send the list of missions and campaigns avilable on the server.  Stop when
3609         // reaching a certain maximum
3610         type = MISSION_LIST_ITEMS;
3611         ADD_DATA( type );
3612         for (i = 0; i < Multi_create_mission_count; i++ ) {             
3613                 stop = 0;
3614                 ADD_DATA( stop );
3615
3616                 ADD_STRING( Multi_create_mission_list[i].filename );
3617                 ADD_STRING( Multi_create_mission_list[i].name );
3618                 ADD_INT( Multi_create_mission_list[i].flags );
3619                 ADD_DATA( Multi_create_mission_list[i].max_players );
3620                 ADD_UINT( Multi_create_mission_list[i].respawn );               
3621
3622                 // STANDALONE_ONLY              
3623                 ADD_DATA( Multi_create_mission_list[i].valid_status );
3624
3625                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3626                         stop = 1;
3627                         ADD_DATA( stop );                       
3628                         multi_io_send_reliable(pl, data, packet_size);
3629                         BUILD_HEADER( MISSION_ITEM );
3630                         ADD_DATA( type );
3631                 }               
3632         }
3633         stop = 1;
3634         ADD_DATA(stop); 
3635         multi_io_send_reliable(pl, data, packet_size);
3636
3637         // send the campaign information
3638         type = CAMPAIGN_LIST_ITEMS;
3639         BUILD_HEADER(MISSION_ITEM);
3640         ADD_DATA( type );
3641         for (i = 0; i < Multi_create_campaign_count; i++ ) {            
3642                 stop = 0;
3643                 ADD_DATA( stop );
3644
3645                 ADD_STRING( Multi_create_campaign_list[i].filename );
3646                 ADD_STRING( Multi_create_campaign_list[i].name );
3647                 ADD_INT( Multi_create_campaign_list[i].flags ); 
3648                 ADD_DATA( Multi_create_campaign_list[i].max_players );          
3649
3650                 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3651                         stop = 1;
3652                         ADD_DATA( stop );                       
3653                         multi_io_send_reliable(pl, data, packet_size);
3654                         BUILD_HEADER( MISSION_ITEM );
3655                         ADD_DATA( type );
3656                 }               
3657         }
3658         stop = 1;
3659         ADD_DATA(stop); 
3660         multi_io_send_reliable(pl, data, packet_size);
3661 }
3662
3663 // process a request for a list of missions
3664 void process_mission_request_packet(ubyte *data, header *hinfo)
3665 {   
3666         int player_num,offset;  
3667         
3668         offset = HEADER_LENGTH;
3669         PACKET_SET_SIZE();
3670
3671         // fill in the address information of where this came from      
3672         player_num = find_player_id(hinfo->id);
3673         if(player_num == -1){
3674                 nprintf(("Network","Could not find player to send mission list items to!\n"));
3675                 return;
3676         }
3677
3678         send_mission_items( &Net_players[player_num] );
3679 }
3680
3681 // process an individual mission file item
3682 void process_mission_item_packet(ubyte *data,header *hinfo)
3683 {
3684    int offset, flags;           
3685         char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3686         ubyte stop, type,max_players;
3687         uint respawn;
3688
3689         SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3690         offset = HEADER_LENGTH;
3691
3692         GET_DATA( type );
3693         GET_DATA(stop);
3694         while( !stop ) {
3695                 GET_STRING( filename );
3696                 GET_STRING( name );
3697                 GET_INT( flags );
3698                 GET_DATA( max_players );
3699
3700                 // missions also have respawns and a crc32 associated with them
3701                 if(type == MISSION_LIST_ITEMS){
3702                         GET_UINT(respawn);
3703
3704                         // STANDALONE_ONLY                      
3705                         GET_DATA(valid_status);
3706
3707                         if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3708                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3709                                 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3710                                 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3711                                 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3712                                 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3713
3714                                 // STANDALONE_ONLY                              
3715                                 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3716
3717                                 Multi_create_mission_count++;
3718                         }
3719                 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3720                         if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3721                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3722                                 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3723                                 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3724                                 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3725                                 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3726                                 Multi_create_campaign_count++;
3727                         }
3728                 }
3729
3730                 GET_DATA( stop );
3731         }
3732         
3733         PACKET_SET_SIZE();      
3734
3735         // this will cause whatever list to get resorted (although they should be appearing in order)
3736         multi_create_setup_list_data(-1);               
3737 }
3738
3739 // send a request to the server to pause or unpause the game
3740 void send_multi_pause_packet(int pause)
3741 {
3742         ubyte data[MAX_PACKET_SIZE];
3743         ubyte val;
3744         int packet_size = 0;
3745         
3746         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3747         
3748         // build the header
3749         BUILD_HEADER(MULTI_PAUSE_REQUEST);
3750         val = (ubyte) pause;
3751         
3752         // add the pause info
3753         ADD_DATA(val);  
3754
3755         // send the request to the server       
3756         multi_io_send_reliable(Net_player, data, packet_size);
3757 }
3758
3759 // process a pause update packet (pause, unpause, etc)
3760 void process_multi_pause_packet(ubyte *data, header *hinfo)
3761 {
3762         int offset;
3763         ubyte val;              
3764         int player_index;
3765
3766         offset = HEADER_LENGTH;
3767
3768         // get the data
3769         GET_DATA(val);  
3770         PACKET_SET_SIZE();
3771
3772         // get who sent the packet      
3773         player_index = find_player_id(hinfo->id);
3774         // if we don't know who sent the packet, don't do anything
3775         if(player_index == -1){
3776                 return;
3777         }
3778
3779         // if we're the server, we should evaluate whether this guy is allowed to send the packet
3780         multi_pause_server_eval_request(&Net_players[player_index],(int)val);   
3781 }
3782
3783 // send a game information update
3784 void send_game_info_packet()
3785 {
3786         int packet_size;
3787         ubyte data[MAX_PACKET_SIZE], paused;
3788
3789         // set the paused variable
3790         paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3791
3792         BUILD_HEADER(GAME_INFO);
3793         ADD_INT( Missiontime );
3794         ADD_DATA( paused );
3795         
3796         multi_io_send_to_all(data, packet_size);
3797 }
3798
3799 // process a game information update
3800 void process_game_info_packet( ubyte *data, header *hinfo )
3801 {
3802         int offset;
3803         fix mission_time;
3804         ubyte paused;
3805
3806         offset = HEADER_LENGTH;
3807
3808         // get the mission time -- we should examine our time and the time from the server.  If off by some delta
3809         // time, set our time to server time (should take ping time into account!!!)
3810         GET_DATA( mission_time );
3811         GET_DATA( paused );
3812         PACKET_SET_SIZE();      
3813 }
3814
3815 // send an ingame nak packet
3816 void send_ingame_nak(int state, net_player *p)
3817 {
3818         ubyte data[MAX_PACKET_SIZE];
3819         int packet_size = 0;
3820
3821         BUILD_HEADER(INGAME_NAK);
3822
3823         ADD_INT(state);
3824                 
3825         multi_io_send_reliable(p, data, packet_size);
3826 }
3827
3828 // process an ingame nak packet
3829 void process_ingame_nak(ubyte *data, header *hinfo)
3830 {
3831         int offset,state,pid;   
3832
3833         offset = HEADER_LENGTH;
3834         GET_INT(state); 
3835         PACKET_SET_SIZE();
3836         
3837    pid = find_player_id(hinfo->id);
3838         if(pid < 0){
3839                 return;
3840         }
3841         
3842         switch(state){
3843         case ACK_FILE_ACCEPTED :
3844                 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3845                 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3846                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);           
3847                 break;
3848         }       
3849 }
3850
3851 // send a packet telling players to end the mission
3852 void send_endgame_packet(net_player *pl)
3853 {
3854         ubyte data[MAX_PACKET_SIZE];
3855         int packet_size = 0;
3856         
3857         BUILD_HEADER(MISSION_END);      
3858
3859         // sending to a specific player?
3860         if(pl != NULL){
3861                 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3862                 multi_io_send_reliable(pl, data, packet_size);
3863                 return;
3864         }
3865
3866         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
3867                 // send all player stats here
3868                 multi_broadcast_stats(STATS_MISSION);           
3869
3870                 // if in dogfight mode, send all dogfight stats as well
3871                 ml_string("Before dogfight stats!");
3872                 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3873                         ml_string("Sending dogfight stats!");
3874
3875                         multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3876                 }
3877                 ml_string("After dogfight stats!");
3878
3879                 // tell everyone to leave the game              
3880                 multi_io_send_to_all_reliable(data, packet_size);
3881         } else {
3882                 multi_io_send_reliable(Net_player, data, packet_size);
3883         }
3884 }
3885
3886 // process a packet indicating we should end the current mission
3887 void process_endgame_packet(ubyte *data, header *hinfo)
3888 {
3889         int offset;     
3890         int player_num;
3891                         
3892         offset = HEADER_LENGTH;
3893         
3894         PACKET_SET_SIZE();
3895
3896         ml_string("Receiving endgame packet");
3897         
3898         // if I'm the server, I should evaluate whether the sender is authorized to end the game
3899         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3900                 // determine who this came from and make sure he is allowed to end the game             
3901                 player_num = find_player_id(hinfo->id);
3902                 SDL_assert(player_num != -1);
3903                 if(player_num < 0){
3904                         return;
3905                 }
3906
3907                 // if the player is allowed to end the mission
3908                 if(!multi_can_end_mission(&Net_players[player_num])){
3909                         return;
3910                 }               
3911
3912                 // act as if we hit alt+j locally 
3913                 multi_handle_end_mission_request();
3914         }
3915         // all clients process immediately
3916         else {
3917                 // ingame joiners should quit when they receive an endgame packet since the game is over
3918                 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3919                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3920                         return;
3921                 }
3922
3923                 // do any special processing for being in a state other than the gameplay state
3924                 multi_handle_state_special();
3925
3926                 // make sure we're not already in the debrief state
3927                 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3928                         multi_warpout_all_players();                    
3929                 }
3930         }       
3931 }
3932
3933 // send a position/orientation update for myself (if I'm an observer)
3934 void send_observer_update_packet()
3935 {
3936         ubyte data[MAX_PACKET_SIZE];
3937         int packet_size = 0;
3938         int ret;
3939         ushort target_sig;
3940         
3941         // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3942         // to send any update packets to anyone.
3943         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3944                 return;
3945         }
3946
3947         if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3948                 return;
3949         }
3950         
3951         BUILD_HEADER(OBSERVER_UPDATE);
3952
3953         ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3954         packet_size += ret;
3955         ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3956         packet_size += ret;
3957
3958         // add targeting infomation
3959         if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3960                 target_sig = Objects[Player_ai->target_objnum].net_signature;
3961         } else {
3962                 target_sig = 0;
3963         }
3964         ADD_USHORT(target_sig);
3965         
3966         multi_io_send(Net_player, data, packet_size);
3967 }
3968
3969 // process a position/orientation update from an observer
3970 void process_observer_update_packet(ubyte *data, header *hinfo)
3971 {
3972         int offset,ret;
3973         int obs_num;
3974         vector g_vec;
3975         matrix g_mat;
3976         physics_info bogus_pi;  
3977         ushort target_sig;
3978         object *target_obj;
3979         offset = HEADER_LENGTH;
3980
3981         obs_num = find_player_id(hinfo->id);
3982         
3983         memset(&bogus_pi,0,sizeof(physics_info));
3984         ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3985         offset += ret;
3986         ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3987         offset += ret;
3988
3989         // targeting information
3990         GET_USHORT(target_sig); 
3991         PACKET_SET_SIZE();      
3992
3993         if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
3994                 return;
3995         }
3996
3997         // set targeting info
3998         if(target_sig == 0){
3999                 Net_players[obs_num].s_info.target_objnum = -1;
4000         } else {
4001                 target_obj = multi_get_network_object(target_sig);
4002                 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4003         }
4004
4005         Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4006         Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4007         Net_players[obs_num].s_info.eye_pos = g_vec;
4008         Net_players[obs_num].s_info.eye_orient = g_mat;
4009 }
4010
4011 void send_netplayer_slot_packet()
4012 {
4013         ubyte data[MAX_PACKET_SIZE];
4014         int packet_size = 0, idx;
4015         ubyte stop;
4016
4017
4018         stop = 0xff;
4019    BUILD_HEADER(NETPLAYER_SLOTS_P);
4020    for(idx=0;idx<MAX_PLAYERS;idx++){
4021                 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4022                         ADD_DATA(stop);
4023                         ADD_SHORT(Net_players[idx].player_id);  
4024                         ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4025                         ADD_INT(Net_players[idx].p_info.ship_class);
4026                         ADD_INT(Net_players[idx].p_info.ship_index);                    
4027                 }
4028         }
4029         stop = 0x0;
4030         ADD_DATA(stop);
4031                 
4032         // standalone case or not
4033         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
4034                 multi_io_send_to_all_reliable(data, packet_size);
4035         } else {
4036                 multi_io_send_reliable(Net_player, data, packet_size);
4037         }
4038 }
4039
4040 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4041 {
4042         int offset;
4043         int player_num,ship_class,ship_index;
4044         ushort net_sig;
4045         object *objp;   
4046         ubyte stop;
4047         short player_id;
4048         
4049         offset = HEADER_LENGTH; 
4050
4051    // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4052         multi_untag_player_ships();
4053
4054         GET_DATA(stop);
4055         while(stop != 0x0){
4056                 GET_SHORT(player_id);
4057                 GET_USHORT(net_sig);
4058                 GET_INT(ship_class);
4059                 GET_INT(ship_index);
4060                 player_num = find_player_id(player_id);
4061                 if(player_num < 0){
4062                         nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4063                 } else {
4064                         // call the function in multiutil.cpp to set up the player object stuff
4065                         // being careful not to muck with the standalone object
4066                         if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4067                                 objp = multi_get_network_object(net_sig);
4068                                 SDL_assert(objp != NULL);
4069                                 multi_assign_player_ship( player_num, objp, ship_class );
4070                                 Net_players[player_num].p_info.ship_index = ship_index;
4071                                 objp->flags &= ~(OF_COULD_BE_PLAYER);
4072                                 objp->flags |= OF_PLAYER_SHIP;
4073                         }
4074                 }
4075                 GET_DATA(stop);
4076         }
4077         PACKET_SET_SIZE();
4078
4079         // standalone should forward the packet and wait for a response
4080         if(Game_mode & GM_STANDALONE_SERVER){
4081                 send_netplayer_slot_packet();
4082         } 
4083
4084         Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4085         send_netplayer_update_packet(); 
4086 }
4087
4088 // two functions to deal with ships changing their primary/secondary weapon status.  'what' indicates
4089 // if this change is a primary or secondary change.  new_bank is the new current primary/secondary
4090 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4091 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4092 {
4093         ubyte data[MAX_PACKET_SIZE], utmp;
4094         int packet_size;
4095
4096         BUILD_HEADER(SHIP_WSTATE_CHANGE);
4097         ADD_USHORT( Objects[shipp->objnum].net_signature );
4098         utmp = (ubyte)(what);
4099         ADD_DATA( utmp );
4100         utmp = (ubyte)(new_bank);
4101         ADD_DATA( utmp );
4102         utmp = (ubyte)(link_status);
4103         ADD_DATA( utmp );
4104
4105         // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB   
4106         multi_io_send_to_all_reliable(data, packet_size);
4107 }
4108
4109 void process_ship_weapon_change( ubyte *data, header *hinfo )
4110 {
4111         int offset;
4112         ushort signature;
4113         ubyte what, new_bank, link_status;
4114         object *objp;
4115         ship *shipp;
4116
4117         offset = HEADER_LENGTH;
4118         GET_USHORT( signature );
4119         GET_DATA( what );
4120         GET_DATA( new_bank );
4121         GET_DATA( link_status );
4122         PACKET_SET_SIZE();
4123
4124         objp = multi_get_network_object( signature );
4125         if ( objp == NULL ) {
4126                 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4127                 return;
4128         }
4129         // SDL_assert( objp->type == OBJ_SHIP );
4130         if(objp->type != OBJ_SHIP){
4131                 return;
4132         }
4133
4134         // if this is my data, do nothing since I already have my own data
4135         if ( objp == Player_obj ){
4136                 return;
4137         }
4138
4139         // now, get the ship and set the new bank and link modes based on the 'what' value
4140         shipp = &Ships[objp->instance];
4141         if ( what == MULTI_PRIMARY_CHANGED ) {
4142                 shipp->weapons.current_primary_bank = new_bank;
4143                 if ( link_status ){
4144                         shipp->flags |= SF_PRIMARY_LINKED;
4145                 } else {
4146                         shipp->flags &= ~SF_PRIMARY_LINKED;
4147                 }
4148         } else {
4149                 shipp->weapons.current_secondary_bank = new_bank;
4150                 if ( link_status ){
4151                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4152                 } else {
4153                         shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4154                 }
4155         }
4156 }
4157         
4158         // ship status change procedure
4159 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4160 //                server critical.
4161 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets 
4162 //                for added redundancy.
4163 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4164 //                ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4165 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS) 
4166 //                back to the client. Also sends multiple times for redundancy
4167 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4168 //                and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4169 //                on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4170
4171 #define SHIP_STATUS_REPEAT 2
4172 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4173 {
4174         int idx, temp;
4175         ubyte data[MAX_PACKET_SIZE];
4176         int packet_size = 0;
4177
4178         if(pl == NULL){
4179                 return;
4180         }
4181
4182         BUILD_HEADER(SHIP_STATUS_CHANGE);
4183         ADD_INT(id);
4184         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4185                 temp = bi->status[idx];
4186                 ADD_INT(temp);
4187         }
4188         
4189    // server should send reliably (response packet)
4190         if(MULTIPLAYER_MASTER){         
4191                 multi_io_send_reliable(pl, data, packet_size);
4192         } else {
4193                 multi_io_send(pl, data, packet_size);
4194         }
4195 }
4196
4197 void process_ship_status_packet(ubyte *data, header *hinfo)
4198 {
4199    int idx;
4200         int offset;
4201         int player_num,unique_id;
4202         button_info bi;
4203         int i_tmp;
4204         
4205         offset = HEADER_LENGTH;
4206
4207         // zero out the button info structure for good measure
4208         memset(&bi,0,sizeof(button_info));
4209         
4210         // read the button-info
4211         GET_INT(unique_id);     
4212                 
4213         for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4214                 GET_INT(i_tmp);
4215                 bi.status[idx] = i_tmp;
4216         }
4217
4218         PACKET_SET_SIZE();
4219
4220    // this will be handled differently client and server side. Duh.
4221         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){                  // SERVER SIDE
4222                 // find which net-player has sent us butotn information         
4223       player_num = find_player_id(hinfo->id);
4224                 SDL_assert(player_num >= 0);
4225                 if(player_num < 0){
4226                         return;
4227                 }
4228
4229                 // don't process critical button information for observers
4230                 // its a new button_info for this guy. apply and ack
4231                 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){        
4232                         // mark that he's pressed this button
4233          // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4234                         
4235                         // send a return packet
4236          send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4237                         
4238                         // apply the button presses to his ship as normal
4239                         multi_apply_ship_status(&Net_players[player_num], &bi, 0);         
4240                 } 
4241                 // else ignore it as a repeat from the same guy
4242         } else {                                                         // CLIENT SIDE
4243                 // this is the return from the server, so we should now apply them locally
4244       // if(lookup_ship_status(Net_player,unique_id,1)){
4245                 multi_apply_ship_status(Net_player, &bi, 1);
4246                 // }
4247         }       
4248 }
4249
4250 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4251 // for clients.  Left all details to this function instead of higher level messaging
4252 // code
4253 void send_player_order_packet(int type, int index, int cmd)
4254 {
4255         ubyte data[MAX_PACKET_SIZE];
4256         ubyte val;
4257         ushort target_signature;
4258         char t_subsys;
4259         int packet_size = 0;
4260
4261         BUILD_HEADER(PLAYER_ORDER_PACKET);
4262
4263         val = (ubyte)type;
4264         ADD_DATA(val);         // ship order or wing order, or message all fighters
4265
4266         // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4267         if ( val != SQUAD_MSG_ALL ){
4268                 ADD_INT(index);  // net signature of target ship
4269         }
4270
4271         ADD_INT(cmd);         // the command itself
4272
4273         // add target data.
4274         target_signature = 0;
4275         if ( Player_ai->target_objnum != -1 ){
4276                 target_signature = Objects[Player_ai->target_objnum].net_signature;
4277         }
4278
4279         ADD_USHORT( target_signature );
4280
4281         t_subsys = -1;
4282         if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4283                 int s_index;
4284
4285                 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4286                 SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
4287                 t_subsys = (char)s_index;
4288         }
4289         ADD_DATA(t_subsys);
4290    
4291         multi_io_send_reliable(Net_player, data, packet_size);
4292 }
4293
4294 // brief explanation :
4295 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4296 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4297 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4298 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4299 void process_player_order_packet(ubyte *data, header *hinfo)
4300 {
4301         int offset, player_num, command, index = 0, tobjnum_save;       
4302         ushort target_signature;
4303         char t_subsys, type;
4304         object *objp, *target_objp;
4305         ai_info *aip;
4306         ship *shipp;
4307         ship_subsys *tsubsys_save, *targeted_subsys;
4308
4309         SDL_assert(MULTIPLAYER_MASTER);
4310
4311         // packet values - its easier to read all of these in first
4312                 
4313         offset = HEADER_LENGTH;
4314         
4315         GET_DATA( type );
4316         if ( type != SQUAD_MSG_ALL ){
4317                 GET_INT( index );
4318         }
4319
4320         GET_INT( command );
4321         GET_USHORT( target_signature );
4322         GET_DATA( t_subsys );
4323
4324         PACKET_SET_SIZE();      
4325
4326         player_num = find_player_id(hinfo->id);
4327         if(player_num == -1){
4328                 nprintf(("Network","Received player order packet from unknown player\n"));              
4329                 return;
4330         }       
4331
4332         objp = &Objects[Net_players[player_num].player->objnum];
4333         if ( objp->type != OBJ_SHIP ) {
4334                 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4335                 return;
4336         }
4337
4338         // HACK HACK HACK HACK HACK HACK
4339         // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4340         // the data is BOGUS.  All people should be able to to these things as well.
4341         if(command == REARM_REPAIR_ME_ITEM){ 
4342                 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);          
4343                 return;
4344         } else if(command == ABORT_REARM_REPAIR_ITEM){
4345                 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);            
4346                 return;
4347         }
4348
4349         // if this player is not allowed to do messaging, quit here
4350         if( !multi_can_message(&Net_players[player_num]) ){
4351                 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4352                 return;
4353         }
4354
4355         // check to see if the type of order is a reinforcement call.  If so, intercept it, and
4356         // then call them in.
4357         if ( type == SQUAD_MSG_REINFORCEMENT ) {
4358                 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4359                 hud_squadmsg_call_reinforcement(index, player_num);
4360                 return;
4361         }
4362
4363         // set the player's ai information here
4364         shipp = &Ships[objp->instance];
4365         aip = &Ai_info[shipp->ai_index];
4366
4367         // get the target objnum and targeted subsystem.  Quick out if we don't have an object to act on.
4368         target_objp = multi_get_network_object( target_signature );
4369         if ( target_objp == NULL ) {
4370                 return;
4371         }
4372
4373         targeted_subsys = NULL;
4374         if ( t_subsys != -1 ) {
4375                 SDL_assert( target_objp != NULL );
4376                 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4377         }
4378
4379         // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4380         // here
4381         tobjnum_save = aip->target_objnum;
4382         tsubsys_save = aip->targeted_subsys;
4383
4384         if ( target_objp ) {
4385                 aip->target_objnum = OBJ_INDEX(target_objp);
4386         } else {
4387                 aip->target_objnum = -1;
4388         }
4389
4390         aip->targeted_subsys = targeted_subsys;
4391
4392         if ( type == SQUAD_MSG_SHIP ) {
4393                 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4394         } else if ( type == SQUAD_MSG_WING ) {
4395                 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4396         } else if ( type == SQUAD_MSG_ALL ) {
4397                 hud_squadmsg_send_to_all_fighters( command, player_num );
4398         }
4399
4400         SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); //      make sure not targeting self
4401         aip->target_objnum = tobjnum_save;
4402         aip->targeted_subsys = tsubsys_save;
4403 }
4404
4405 // FILE SIGNATURE stuff :
4406 // there are 2 cases for file signature sending which are handled very differently
4407 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4408 //     posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked). 
4409 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4410 //     the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4411 //     would have to keep track of up to potentially 14 other ack handles  (ouch).
4412 void send_file_sig_packet(ushort sum_sig,int length_sig)
4413 {
4414         ubyte data[MAX_PACKET_SIZE];
4415         int packet_size = 0;
4416
4417         BUILD_HEADER(FILE_SIG_INFO);
4418         ADD_USHORT(sum_sig);
4419         ADD_INT(length_sig);
4420                 
4421         multi_io_send_reliable(Net_player, data, packet_size);
4422 }
4423
4424 void process_file_sig_packet(ubyte *data, header *hinfo)
4425 {
4426         int offset;
4427         int length_sig;
4428         ushort sum_sig; 
4429         offset = HEADER_LENGTH;
4430
4431         // should only be received on the server-side
4432         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER); 
4433         
4434         GET_USHORT(sum_sig);
4435         GET_INT(length_sig);
4436         PACKET_SET_SIZE();
4437         server_verify_filesig(hinfo->id, sum_sig, length_sig);  
4438 }
4439
4440 void send_file_sig_request(char *file_name)
4441 {
4442         ubyte data[MAX_PACKET_SIZE];
4443         int packet_size = 0;
4444
4445         BUILD_HEADER(FILE_SIG_REQUEST);
4446         ADD_STRING(file_name);
4447
4448         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4449                 
4450         multi_io_send_to_all_reliable(data, packet_size);
4451 }
4452
4453 void process_file_sig_request(ubyte *data, header *hinfo)
4454 {               
4455         int offset = HEADER_LENGTH;     
4456
4457         // get the mission name
4458         GET_STRING(Netgame.mission_name);        
4459         PACKET_SET_SIZE();      
4460
4461         // set the current mission filename
4462         SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4463
4464         // get the checksum
4465         multi_get_mission_checksum(Game_current_mission_filename);      
4466
4467         if(!multi_endgame_ending()){    
4468                 // reply to the server
4469                 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4470         }
4471 }
4472
4473 // functions to deal with subsystems getting whacked
4474 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4475 {
4476         ubyte data[MAX_PACKET_SIZE];
4477         int packet_size;
4478         ubyte uindex;
4479         vector tmp, local_hitpos;
4480         object *objp;
4481
4482         SDL_assert ( index < UCHAR_MAX );
4483         uindex = (ubyte)(index);
4484
4485         objp = &Objects[shipp->objnum];
4486
4487         vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4488         vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4489
4490         BUILD_HEADER(SUBSYSTEM_DESTROYED);
4491         ADD_USHORT( Objects[shipp->objnum].net_signature );
4492         ADD_DATA( uindex );
4493 //      ADD_DATA( local_hitpos );
4494         add_vector_data(data, &packet_size, local_hitpos);
4495         
4496         multi_io_send_to_all_reliable(data, packet_size);
4497 }
4498
4499 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4500 {
4501         int offset;
4502         ushort signature;
4503         ubyte uindex;
4504         object *objp;
4505         vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4506
4507         offset = HEADER_LENGTH;
4508
4509         GET_USHORT( signature );
4510         GET_DATA( uindex );
4511 //      GET_DATA( local_hit_pos );
4512         get_vector_data(data, &offset, local_hit_pos);
4513
4514         // get the network object.  process it if we find it.
4515         objp = multi_get_network_object( signature );
4516         if ( objp != NULL ) {
4517                 ship *shipp;
4518                 ship_subsys *subsysp;
4519
4520                 // be sure we have a ship!!!
4521                 // SDL_assert ( objp->type == OBJ_SHIP );
4522                 if(objp->type != OBJ_SHIP){
4523                         PACKET_SET_SIZE();
4524                         return;
4525                 }
4526
4527                 shipp = &Ships[objp->instance];
4528
4529                 // call to get the pointer to the subsystem we should be working on
4530                 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4531                 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4532                 vm_vec_add2( &world_hit_pos, &objp->pos );
4533
4534                 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4535                 if ( objp == Player_obj ) {
4536                         hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4537                 }
4538         }
4539
4540         PACKET_SET_SIZE();
4541 }
4542
4543
4544 // packet to tell clients cargo of a ship was revealed to all
4545 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4546 {
4547         ubyte data[MAX_PACKET_SIZE], uindex;
4548         int packet_size;
4549
4550         SDL_assert ( index < UCHAR_MAX );
4551         uindex = (ubyte)(index);
4552
4553         // build the header and add the data
4554         BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4555         ADD_USHORT( Objects[shipp->objnum].net_signature );
4556         ADD_DATA( uindex );
4557
4558         // server sends to all players
4559         if(MULTIPLAYER_MASTER){         
4560                 multi_io_send_to_all_reliable(data, packet_size);
4561         } 
4562         // clients just send to the server
4563         else {
4564                 multi_io_send_reliable(Net_player, data, packet_size);
4565         }
4566 }
4567
4568 // process a subsystem cargo revealed packet
4569 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4570 {
4571         int offset;
4572         ushort signature;
4573         ubyte uindex;
4574         object *objp;
4575         ship *shipp;
4576         ship_subsys *subsysp;
4577
4578         offset = HEADER_LENGTH;
4579         GET_USHORT( signature );
4580         GET_DATA( uindex );
4581         PACKET_SET_SIZE();
4582
4583         // get a ship pointer and call the ship function to reveal the cargo
4584         objp = multi_get_network_object( signature );
4585         if ( objp == NULL ) {
4586                 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4587                 return;
4588         }
4589
4590         // SDL_assert( objp->type == OBJ_SHIP );
4591         if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4592                 return;
4593         }
4594
4595         shipp = &Ships[objp->instance];
4596
4597         // call to get the pointer to the subsystem we should be working on
4598         subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4599         if (subsysp == NULL) {
4600                 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4601                 return;
4602         }
4603
4604         // this will take care of re-routing to all other clients
4605         void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4606         ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4607
4608         // server should rebroadcast
4609         if(MULTIPLAYER_MASTER){
4610                 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4611         }
4612 }
4613
4614 void send_netplayer_load_packet(net_player *pl)
4615 {
4616         ubyte data[MAX_PACKET_SIZE];
4617         int packet_size = 0;
4618
4619         BUILD_HEADER(LOAD_MISSION_NOW);
4620         ADD_STRING(Netgame.mission_name);
4621
4622         if(pl == NULL){         
4623                 multi_io_send_to_all_reliable(data, packet_size);
4624         } else {
4625                 multi_io_send_reliable(pl, data, packet_size);
4626         }
4627 }
4628
4629 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4630 {
4631         char str[100];
4632         int offset = HEADER_LENGTH;     
4633
4634         GET_STRING(str);
4635         PACKET_SET_SIZE();
4636
4637         SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4638         SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4639         if(!Multi_mission_loaded){
4640
4641                 // MWA 2/3/98 -- ingame join changes!!!
4642                 // everyone can go through the same mission loading path here!!!!
4643                 nprintf(("Network","Loading mission..."));
4644
4645                 // notify everyone that I'm loading the mission
4646                 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4647                 send_netplayer_update_packet();         
4648
4649                 // do the load itself
4650                 game_start_mission();           
4651
4652                 // ingame joiners need to "untag" all player ships as could_be_players.  The ingame joining
4653                 // code will remark the correct player ships
4654                 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4655                         multi_untag_player_ships();
4656                 }
4657
4658                 Net_player->flags |= NETINFO_FLAG_MISSION_OK;           
4659                 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4660                 send_netplayer_update_packet();
4661
4662                 Multi_mission_loaded = 1;
4663                 nprintf(("Network","Finished loading mission\n"));              
4664         }       
4665 }
4666
4667 void send_jump_into_mission_packet(net_player *pl)
4668 {
4669         ubyte data[MAX_PACKET_SIZE];
4670         int packet_size = 0;
4671
4672         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4673
4674         BUILD_HEADER(JUMP_INTO_GAME);
4675
4676         // ingame joiners will get special data.  We need to tell them about the state of the mission, like paused,
4677         // and possible other things.
4678         if ( pl != NULL ) {
4679                 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4680                         ADD_INT(Netgame.game_state);
4681                 }
4682         }
4683         
4684         // broadcast
4685         if(pl == NULL){         
4686                 multi_io_send_to_all_reliable(data, packet_size);
4687         }
4688         // send to a specific player
4689         else {
4690                 multi_io_send_reliable(pl, data, packet_size);
4691         }
4692 }
4693
4694 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4695 {
4696         int offset = HEADER_LENGTH;
4697         int state = 0;
4698
4699         // if I am ingame joining, there should be extra data.  For now, this data is the netgame state.
4700         // the game could be paused, so ingame joiner needs to deal with it.
4701         if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4702                 GET_INT( state );
4703                 Netgame.game_state = state;
4704         }
4705
4706         PACKET_SET_SIZE();      
4707
4708         // handle any special processing for being in a weird substate
4709         multi_handle_state_special();
4710
4711         // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4712         if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4713                 if(Net_player->flags & NETINFO_FLAG_OBSERVER){                                          
4714                         multi_ingame_observer_finish();                 
4715                 } else {
4716                         gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4717                         Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4718                         send_netplayer_update_packet();
4719                 }
4720         } else {
4721                 // start the mission!!
4722                 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4723                         Netgame.game_state = NETGAME_STATE_IN_MISSION;
4724                         gameseq_post_event(GS_EVENT_ENTER_GAME);
4725                         Net_player->state = NETPLAYER_STATE_IN_MISSION;
4726                         send_netplayer_update_packet();
4727                 }               
4728         }
4729
4730         extern time_t Player_multi_died_check;
4731         Player_multi_died_check = -1;
4732
4733         // recalc all object pairs now  
4734         extern void obj_reset_all_collisions();
4735         obj_reset_all_collisions();
4736
4737         // display some cool text
4738         multi_common_add_text(XSTR("Received mission start\n",720),1);
4739
4740         // NETLOG
4741         ml_string(NOX("Client received mission start from server - entering mission"));
4742 }
4743
4744 //XSTR:OFF
4745
4746 const char *repair_text[] = {
4747         "unknown",
4748         "REPAIR_INFO_BEGIN",
4749         "REPAIR_INFO_END",
4750         "REPAIR_INFO_UPDATE",
4751         "REPAIR_INFO_QUEUE",
4752         "REPAIR_INFO_ABORT",
4753         "REPAIR_INFO_BROKEN",
4754         "REPAIR_INFO_WARP_ADD",
4755         "REPAIR_INFO_WARP_REMOVE",
4756         "REPAIR_INFO_ONWAY",
4757         "REPAIR_INFO_KILLED",
4758         "REPAIR_INFO_COMPLETE",
4759 };
4760
4761 //XSTR:ON
4762
4763 // the following two routines deal with updating and sending information regarding players
4764 // rearming and repairing during the game.  The process function calls the routines to deal with
4765 // setting flags and other interesting things.
4766 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4767 {
4768         int packet_size = 0;
4769         ushort repaired_signature, repair_signature;
4770         ubyte data[MAX_PACKET_SIZE];
4771         ubyte cd;
4772
4773         // use the network signature of the destination object if there is one, -1 otherwise.
4774         // client will piece it all together
4775         repaired_signature = repaired_objp->net_signature;
4776
4777         // the repair ship may be NULL here since it might have been destroyed
4778         repair_signature = 0;
4779         if ( repair_objp ){
4780                 repair_signature = repair_objp->net_signature;
4781         }
4782
4783         BUILD_HEADER(CLIENT_REPAIR_INFO);
4784         cd = (ubyte)code;
4785         ADD_DATA(cd);
4786         ADD_USHORT( repaired_signature );
4787         ADD_USHORT( repair_signature );
4788         
4789         multi_io_send_to_all_reliable(data, packet_size);
4790
4791         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));
4792 }
4793
4794 void process_repair_info_packet(ubyte *data, header *hinfo)
4795 {
4796         int offset = HEADER_LENGTH;
4797         ushort repaired_signature, repair_signature;
4798         object *repaired_objp, *repair_objp;
4799         ubyte code;
4800
4801         GET_DATA(code);
4802         GET_USHORT( repaired_signature );
4803         GET_USHORT( repair_signature );
4804         PACKET_SET_SIZE();
4805
4806         repaired_objp = multi_get_network_object( repaired_signature );
4807         repair_objp = multi_get_network_object( repair_signature );
4808
4809         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));
4810
4811         if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4812                 return;
4813         }
4814
4815         if ( repaired_objp == NULL ) {
4816                 Int3();                         // Sandeep says this is bad bad bad.  No ship to repair.
4817                 return;
4818         }
4819
4820         // the hope is to simply call the routine in the ai code to set/unset flags
4821         // based on the code value and everything else should happen..I hope....
4822         if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4823
4824                 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4825
4826                 // set the dock flags when repair begins.  Prevents problem in lagging docking
4827                 // packet.  Also set any other flags/modes which need to be set to prevent Asserts.
4828                 // bleah.
4829                 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4830                         ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4831                         Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4832                 }
4833
4834                 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4835                 // as being done.
4836                 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4837                         ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4838                 }
4839         } else {
4840                 if ( code == REPAIR_INFO_WARP_ADD ){
4841                         mission_warp_in_support_ship( repaired_objp );
4842                 } else {
4843                         mission_remove_scheduled_repair( repaired_objp );
4844                 }
4845         }
4846 }
4847
4848 // sends information updating clients on certain AI information that clients will
4849 // need to know about to keep HUD information up to date.  objp is the object that we
4850 // are updating, and what is the type of stuff that we are updating.
4851 void send_ai_info_update_packet( object *objp, char what )
4852 {
4853         int packet_size;
4854         ushort other_signature;
4855         ubyte data[MAX_PACKET_SIZE];
4856         ai_info *aip;
4857         ubyte dock_index, dockee_index;
4858
4859         // SDL_assert( objp->type == OBJ_SHIP );
4860         if(objp->type != OBJ_SHIP){
4861                 return;
4862         }
4863         aip = &Ai_info[Ships[objp->instance].ai_index];
4864
4865         // do an out here
4866         if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4867                 return;
4868
4869         BUILD_HEADER( AI_INFO_UPDATE );
4870         ADD_USHORT( objp->net_signature );
4871         ADD_DATA( what );
4872
4873         // depending on the "what" value, we will send different information
4874         // to the clients
4875         switch( what ) {
4876
4877         case AI_UPDATE_DOCK:
4878                 // for docking ships, add the signature of the ship that we are docking with.
4879                 SDL_assert( aip->dock_objnum != -1 );
4880                 other_signature = Objects[aip->dock_objnum].net_signature;
4881                 dock_index = (ubyte)(aip->dock_index);
4882                 dockee_index = (ubyte)(aip->dockee_index);
4883                 ADD_USHORT( other_signature );
4884                 ADD_DATA(dock_index);
4885                 ADD_DATA(dockee_index);
4886                 break;
4887
4888         case AI_UPDATE_UNDOCK:
4889                 // for undocking ships, check the dock_objnum since we might or might not have it
4890                 // depending on whether or not a ship was destroyed while we were docked.
4891                 other_signature = 0;
4892                 if ( aip->dock_objnum != -1 )
4893                         other_signature = Objects[aip->dock_objnum].net_signature;
4894                 ADD_USHORT( other_signature );
4895
4896                 break;
4897
4898         case AI_UPDATE_ORDERS: {
4899                 int shipnum;
4900
4901                 // for orders, we only need to send a little bit of information here.  Be sure that the
4902                 // first order for this ship is active
4903                 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4904                 ADD_INT( aip->goals[0].ai_mode );
4905                 ADD_INT( aip->goals[0].ai_submode );
4906                 shipnum = -1;
4907                 if ( aip->goals[0].ship_name != NULL )
4908                         shipnum = ship_name_lookup( aip->goals[0].ship_name );
4909
4910                 // the ship_name member of the goals structure may or may not contain a real shipname.  If we don't
4911                 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4912                 if ( shipnum != -1 ) {
4913                         SDL_assert( Ships[shipnum].objnum != -1 );
4914                         other_signature = Objects[Ships[shipnum].objnum].net_signature;
4915                 } else
4916                         other_signature = 0;
4917                 
4918                 ADD_USHORT( other_signature );
4919
4920                 // for docking, add the dock and dockee index
4921                 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4922                         SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4923                         SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4924                         dock_index = (ubyte)aip->goals[0].docker.index;
4925                         dockee_index = (ubyte)aip->goals[0].dockee.index;
4926                         ADD_DATA( dock_index );
4927                         ADD_DATA( dockee_index );
4928                 }
4929                 break;
4930                 }
4931
4932         default:
4933                 Int3();
4934         }
4935         
4936         multi_rate_add(1, "aiu", packet_size);
4937         multi_io_send_to_all_reliable(data, packet_size);
4938 }
4939
4940 // process an ai_info update packet.  Docking/undocking, ai orders, etc. are taken care of here.  This
4941 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4942 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4943 {
4944         int offset = HEADER_LENGTH;
4945         int mode, submode;
4946         ushort net_signature, other_net_signature;
4947         object *objp, *other_objp;
4948         ai_info *aip;
4949         char code;
4950         ubyte dock_index = 0, dockee_index = 0;
4951
4952         GET_USHORT( net_signature );            // signature of the object that we are dealing with.
4953         GET_DATA( code );                                       // code of what we are doing.
4954         objp = multi_get_network_object( net_signature );
4955         if ( !objp ) {
4956                 nprintf(("Network", "Couldn't find object for ai update\n"));
4957         }
4958
4959         switch( code ) {
4960         case AI_UPDATE_DOCK:
4961                 GET_USHORT( other_net_signature );
4962                 GET_DATA( dock_index );
4963                 GET_DATA( dockee_index );
4964                 other_objp = multi_get_network_object( other_net_signature );
4965                 if ( !other_objp ) {
4966                         nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4967                 }
4968                 
4969                 // if we don't have an object to work with, break out of loop
4970                 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4971                         break;
4972                 }
4973
4974                 SDL_assert( other_objp->type == OBJ_SHIP );
4975                 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4976                 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4977
4978                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4979                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4980
4981                 ai_do_objects_docked_stuff( objp, other_objp );
4982                 break;
4983
4984         case AI_UPDATE_UNDOCK:
4985                 GET_USHORT( other_net_signature );
4986                 other_objp = multi_get_network_object( other_net_signature );
4987                 
4988                 // if we don't have an object to work with, break out of loop
4989                 if ( !objp )
4990                         break;
4991
4992                 ai_do_objects_undocked_stuff( objp, other_objp );
4993                 break;
4994
4995         case AI_UPDATE_ORDERS:
4996                 GET_INT( mode );
4997                 GET_INT( submode );
4998                 GET_USHORT( other_net_signature );
4999                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5000                         GET_DATA(dock_index);
5001                         GET_DATA(dockee_index);
5002                 }
5003
5004                 // be sure that we have a ship object!!!
5005                 if ( !objp || (objp->type != OBJ_SHIP) )
5006                         break;
5007
5008                 // set up the information in the first goal element of the object in question
5009                 aip = &Ai_info[Ships[objp->instance].ai_index];
5010                 aip->active_goal = 0;
5011                 aip->goals[0].ai_mode = mode;
5012                 aip->goals[0].ai_submode = submode;
5013
5014                 // for docking, add the dock and dockee index
5015                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5016                         aip->dock_index = dock_index;
5017                         aip->dockee_index = dockee_index;
5018                 }
5019
5020                 // get a shipname if we can.
5021                 other_objp = multi_get_network_object( other_net_signature );
5022                 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5023                         // get a pointer to the shipname in question.  Use the ship_name value in the
5024                         // ship.  We are only using this for HUD display, so I think that using this
5025                         // method will be fine.
5026                         aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5027
5028                         // special case for destroy subsystem -- get the ai_info pointer to our target ship
5029                         // so that we can properly set up what subsystem this ship is attacking.
5030                         if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5031                                 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5032
5033                         // if docking -- set the dock index and dockee index of this other ship
5034                 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5035                                 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5036                                 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5037                         }
5038                 }
5039
5040                 break;
5041
5042         default:
5043                 Int3();         // this Int3() should be temporary
5044                 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5045                 break;
5046         }
5047         PACKET_SET_SIZE();
5048 }
5049
5050 // tell the standalone to move into the MISSION_SYNC_STATE
5051 void send_mission_sync_packet(int mode,int start_campaign)
5052 {
5053         ubyte data[MAX_PACKET_SIZE],is_campaign;
5054         int packet_size = 0;
5055
5056         SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5057
5058         // build the header and add the sync mode (pre or post briefing)
5059         BUILD_HEADER(MISSION_SYNC_DATA);
5060         ADD_INT(mode);
5061
5062         // if this is a campaign game
5063         if(mode == MULTI_SYNC_PRE_BRIEFING){
5064                 if(Game_mode & GM_CAMPAIGN_MODE){
5065                         // add a byte indicating campaign mode
5066                         is_campaign = 1;
5067                         ADD_DATA(is_campaign);
5068
5069                         // add a byte indicating if we should be starting a campaign or continuing it
5070                         is_campaign = (ubyte)start_campaign;
5071                         ADD_DATA(is_campaign);
5072
5073                         // add the campaign filename
5074                         ADD_STRING(Netgame.campaign_name);
5075                 }
5076                 // otherwise if this is a single mission 
5077                 else {
5078                         // add a byte indicating single mission mode
5079                         is_campaign = 0;
5080                         ADD_DATA(is_campaign);
5081
5082                         // add the mission filename
5083                         ADD_STRING(Game_current_mission_filename);
5084                 }
5085         }       
5086         multi_io_send_reliable(Net_player, data, packet_size);
5087 }
5088
5089 // move into the MISSION_SYNC state when this is received
5090 // this packet is sent only from a game host to a standalone
5091 void process_mission_sync_packet(ubyte *data, header *hinfo)
5092 {
5093         int mode;
5094         ubyte campaign_flag;
5095         int offset = HEADER_LENGTH;
5096
5097         SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5098
5099         // if this is a team vs team situation, lock the players send a final team update
5100         if(Netgame.type_flags & NG_TYPE_TEAM){
5101                 multi_team_host_lock_all();
5102                 multi_team_send_update();
5103         }
5104
5105         // get the sync mode (pre or post briefing)
5106         GET_INT(mode);
5107
5108         if(mode == MULTI_SYNC_PRE_BRIEFING){
5109                 // get the flag indicating if this is a single mission or a campaign mode
5110                 GET_DATA(campaign_flag);
5111                 if(campaign_flag){
5112                         // get the flag indicating whether we should be starting a new campaign
5113                         GET_DATA(campaign_flag);
5114
5115                         // get the campaign filename
5116                         GET_STRING(Netgame.campaign_name);
5117
5118                         // either start a new campaign or continue on to the next mission in the current campaign
5119                         if(campaign_flag){
5120                                 multi_campaign_start(Netgame.campaign_name);
5121                         } else {
5122                                 multi_campaign_next_mission();
5123                         }
5124                 } else {
5125                         // make sure we remove the campaign mode flag
5126                         Game_mode &= ~(GM_CAMPAIGN_MODE);
5127
5128                         // get the single mission filename
5129                         GET_STRING(Game_current_mission_filename);
5130                         SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5131                 }
5132         }
5133         PACKET_SET_SIZE();
5134
5135         // set the correct mode and m ove into the state
5136         Multi_sync_mode = mode;
5137         gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5138 }
5139
5140 // tell a player to merge his mission stats into his alltime stats
5141 void send_store_stats_packet(int accept)
5142 {
5143         ubyte data[10],val;
5144         int packet_size = 0;
5145
5146         BUILD_HEADER(STORE_MISSION_STATS);
5147
5148         // add whether we're accepting or tossing
5149         val = (ubyte)accept;
5150         ADD_DATA(val);
5151
5152         // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5153         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5154                 multi_io_send_to_all_reliable(data, packet_size);
5155         } else {
5156                 multi_io_send_reliable(Net_player, data, packet_size);
5157         }
5158 }
5159
5160 void process_store_stats_packet(ubyte *data, header *hinfo)
5161 {
5162         int offset = HEADER_LENGTH;
5163         ubyte accept;
5164
5165         GET_DATA(accept);
5166         PACKET_SET_SIZE();
5167
5168         // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5169         if(Game_mode & GM_STANDALONE_SERVER){
5170                 // rebroadcast the packet to all others in the game
5171                 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));                             
5172                 multi_io_send_to_all_reliable(data, offset);
5173         } else {                        
5174                 if(accept){
5175                         // all players should mark the stats as being accepted in the debriefing
5176                         multi_debrief_stats_accept();                   
5177                 } else {
5178                         // all players should mark the stats as being "tossed" in the debriefing
5179                         multi_debrief_stats_toss();                     
5180                 }                       
5181         }
5182 }
5183
5184 void send_debris_update_packet(object *objp,int code)
5185 {
5186         ubyte data[MAX_PACKET_SIZE];
5187         ubyte val;
5188         int packet_size = 0;
5189
5190         BUILD_HEADER(DEBRIS_UPDATE);    
5191         ADD_USHORT(objp->net_signature);
5192         val = (ubyte) code;
5193         ADD_DATA(val);
5194         
5195         // add any extra relevant data
5196         switch(code){
5197         case DEBRIS_UPDATE_UPDATE:
5198         //      ADD_DATA(objp->pos);                                            // add position
5199                 add_vector_data(data, &packet_size, objp->pos);
5200                 ADD_ORIENT(objp->orient);                               // add orientation
5201         //      ADD_DATA(objp->phys_info.vel);          // add velocity
5202                 add_vector_data(data, &packet_size, objp->phys_info.vel);
5203         //      ADD_DATA(objp->phys_info.rotvel);       // add rotational velocity
5204                 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5205                 break;
5206         }       
5207         multi_io_send_to_all(data, packet_size);
5208 }
5209
5210 void process_debris_update_packet(ubyte *data, header *hinfo)
5211 {
5212         ushort net_sig;
5213         ubyte code;
5214         object bogus_object;
5215         object *objp;
5216         int offset = HEADER_LENGTH;
5217         
5218         GET_USHORT(net_sig);
5219         GET_DATA(code);
5220
5221         objp = NULL;
5222         objp = multi_get_network_object(net_sig);
5223         if(objp == NULL){
5224                 objp = &bogus_object;
5225         }
5226
5227         switch((int)code){
5228         // update the object
5229         case DEBRIS_UPDATE_UPDATE:
5230                 //GET_DATA(objp->pos);
5231         get_vector_data( data, &offset, objp->pos );
5232                 
5233                 GET_ORIENT(objp->orient);
5234                 GET_DATA(objp->phys_info.vel);
5235                 GET_DATA(objp->phys_info.rotvel);
5236                 break;
5237         // simply remove it (no explosion)
5238         case DEBRIS_UPDATE_REMOVE:
5239                 if(objp != &bogus_object){
5240                         SDL_assert(objp->type == OBJ_DEBRIS);
5241                         obj_delete(OBJ_INDEX(objp));
5242                 }
5243                 break;
5244         // blow it up
5245         case DEBRIS_UPDATE_NUKE:
5246                 if(objp != &bogus_object)
5247                         debris_hit(objp,NULL,&objp->pos,1000000.0f);
5248                 break;
5249         }
5250
5251         PACKET_SET_SIZE();
5252 }
5253
5254 // ALAN begin
5255 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)
5256 {
5257         ubyte data[MAX_PACKET_SIZE];
5258
5259         int packet_size = 0;
5260
5261         BUILD_HEADER(WSS_REQUEST_PACKET);
5262         
5263         // add the request information
5264         ADD_SHORT(player_id);
5265         ADD_INT(from_slot);
5266         ADD_INT(from_index);
5267         ADD_INT(to_slot);
5268         ADD_INT(to_index);
5269         ADD_INT(wl_ship_slot);  // only used in weapons loadout
5270         ADD_INT(ship_class);
5271         ADD_INT(mode);
5272
5273         // a standard request
5274         if(p == NULL){          
5275                 multi_io_send_reliable(Net_player, data, packet_size);
5276         } 
5277         // being routed through the standalone to the host of the game
5278         else {
5279                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);                   
5280                 multi_io_send_reliable(p, data, packet_size);
5281         }
5282 }
5283
5284 void process_wss_request_packet(ubyte *data, header *hinfo)
5285 {
5286         int offset = HEADER_LENGTH;
5287         int from_slot,from_index;
5288         int to_slot,to_index;
5289         int mode;
5290         int wl_ship_slot,ship_class;
5291         short player_id;        
5292         int player_num;
5293
5294         // determine who this request is from   
5295         GET_SHORT(player_id);   
5296         player_num = find_player_id(player_id); 
5297
5298         // read in the request data     
5299         GET_INT(from_slot);
5300         GET_INT(from_index);
5301         GET_INT(to_slot);
5302         GET_INT(to_index);
5303         GET_INT(wl_ship_slot); // only used in weapons loadout
5304         GET_INT(ship_class);    // only used in multi team select
5305         GET_INT(mode);
5306         PACKET_SET_SIZE();
5307
5308         SDL_assert(player_num != -1);   
5309         if(player_num == -1){
5310                 return;
5311         }
5312
5313         // if we're the standalone, we have to route this packet to the host of the game
5314         if(Game_mode & GM_STANDALONE_SERVER){
5315                 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5316         } 
5317         // otherwise we're the host and should process the request
5318         else {
5319                 switch(mode){
5320                 case WSS_WEAPON_SELECT :
5321                         wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5322                         break;
5323                 case WSS_SHIP_SELECT :
5324                         multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);                     
5325                         break;
5326                 default:
5327                         Int3();
5328                 }
5329         }
5330 }
5331
5332 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5333 {
5334         ubyte data[MAX_PACKET_SIZE],team;
5335         int packet_size = 0;
5336
5337         SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5338
5339         BUILD_HEADER(WSS_UPDATE_PACKET);
5340
5341         // add the team/pool # this is for
5342         team = (ubyte)team_num;
5343         ADD_DATA(team);
5344
5345         // add the data block size
5346         ADD_INT(size);
5347         
5348         // add the data itself
5349         memcpy(data + packet_size,wss_data,size);
5350         packet_size += size;
5351
5352         // if we're also the master of the game (not on a standalone)
5353         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
5354                 multi_io_send_to_all_reliable(data, packet_size);
5355         }
5356         // if we're only the host on the standalone, then send the packet to the standalone to be routed
5357         else {
5358                 multi_io_send_reliable(Net_player, data, packet_size);
5359         }
5360 }
5361
5362 void process_wss_update_packet(ubyte *data, header *hinfo)
5363 {               
5364         ubyte team;
5365         int size,player_index,idx;
5366         int offset = HEADER_LENGTH;
5367
5368         // get the team/pool #
5369         GET_DATA(team);
5370
5371         // get the data size
5372         GET_INT(size);          
5373
5374         // if we're the standalone, then we should be routing this data to all the other clients
5375         if(Game_mode & GM_STANDALONE_SERVER){
5376                 // read in the data             
5377                 offset += size;         
5378                 PACKET_SET_SIZE();
5379
5380                 // determine where this came from               
5381                 player_index = find_player_id(hinfo->id);               
5382                 SDL_assert(player_index != -1);         
5383                 if(player_index < 0){
5384                         return;
5385                 }
5386
5387                 // route the packet (don't resend it to the host)
5388                 for(idx=0;idx<MAX_PLAYERS;idx++){
5389                         if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){                               
5390                                 multi_io_send_reliable(&Net_players[idx], data, offset);
5391                         }
5392                 }                       
5393         } else {
5394                 // set the proper pool pointers
5395                 ss_set_team_pointers((int)team);
5396
5397                 // read in the block of data, and apply it to the weapons/ship pools
5398                 offset += restore_wss_data(data + offset);
5399                 PACKET_SET_SIZE();
5400
5401                 // set the pool pointers back to my own team
5402                 ss_set_team_pointers(Net_player->p_info.team);
5403
5404                 // sync the interface if this was for my own team
5405                 if((int)team == Net_player->p_info.team){
5406                         multi_ts_sync_interface();
5407                 }               
5408         }
5409 }
5410 // ALAN END
5411
5412
5413 // function to send firing information from the client to the server once they reach
5414 // the final sync screen.
5415 void send_firing_info_packet()
5416 {
5417         ubyte data[MAX_PACKET_SIZE];
5418         int packet_size;
5419         ubyte plinked, sdual;
5420
5421         SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5422
5423         BUILD_HEADER(FIRING_INFO);
5424         plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5425         sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5426         ADD_DATA( plinked );
5427         ADD_DATA( sdual );
5428         
5429         multi_io_send_reliable(Net_player, data, packet_size);
5430 }
5431
5432 void process_firing_info_packet( ubyte *data, header *hinfo )
5433 {
5434         int offset, player_num; 
5435         ubyte plinked, sdual;
5436         ship *shipp;
5437
5438         // only the master of the game should be dealing with these packets
5439         SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5440
5441         offset = HEADER_LENGTH;
5442         GET_DATA( plinked );
5443         GET_DATA( sdual );
5444         PACKET_SET_SIZE();      
5445
5446         player_num = find_player_id(hinfo->id);
5447         if(player_num < 0){
5448                 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5449                 return;
5450         }
5451
5452         // get the ship pointer for this player and set the flags accordingly.
5453         shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5454         if ( plinked )
5455                 shipp->flags |= SF_PRIMARY_LINKED;
5456         else
5457                 shipp->flags &= ~SF_PRIMARY_LINKED;
5458
5459         if ( sdual )
5460                 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5461         else
5462                 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5463 }
5464
5465 // packet to deal with changing status of mission goals.  used to be sent every so often from server
5466 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5467 // goal_num is the index into mission_goals.  new_status means failed, success, etc.  -1 if not used.
5468 // valid means goal is changing to invalid(0) or valid(1).  only applies if new_status == -1
5469 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5470 {
5471         ubyte data[MAX_PACKET_SIZE];
5472         int packet_size;
5473
5474         BUILD_HEADER(MISSION_GOAL_INFO);
5475
5476         ADD_INT(goal_num);
5477         ADD_INT(new_status);
5478         ADD_INT(valid);
5479         
5480         multi_io_send_to_all_reliable(data, packet_size);
5481 }
5482
5483 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5484 {
5485         int offset, goal_num, new_status, valid;
5486
5487         offset = HEADER_LENGTH;
5488         GET_INT(goal_num);
5489         GET_INT(new_status);
5490         GET_INT(valid);
5491         PACKET_SET_SIZE();
5492
5493         // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5494         if ( new_status != -1 ){
5495                 mission_goal_status_change( goal_num, new_status );
5496         } else {
5497                 mission_goal_validation_change( goal_num, valid );
5498         }
5499 }
5500
5501 void send_player_settings_packet(net_player *p)
5502 {
5503         ubyte data[MAX_PACKET_SIZE];
5504         ubyte stop;
5505         int idx;
5506         int packet_size = 0;
5507
5508         // build the header
5509         BUILD_HEADER(PLAYER_SETTINGS);
5510
5511         // add all the data for all the players
5512         stop = 0x0;
5513         for(idx=0;idx<MAX_PLAYERS;idx++){
5514                 if(MULTI_CONNECTED(Net_players[idx])){
5515                         ADD_DATA(stop);
5516                         ADD_SHORT(Net_players[idx].player_id);
5517
5518                         // break the p_info structure by member, so we don't overwrite any absolute pointers
5519                         // ADD_DATA(Net_players[idx].p_info);
5520                         ADD_INT(Net_players[idx].p_info.team);
5521                         ADD_INT(Net_players[idx].p_info.ship_index);
5522                         ADD_INT(Net_players[idx].p_info.ship_class);
5523                 }
5524         }
5525         // add the stop byte
5526         stop = 0xff;
5527         ADD_DATA(stop);
5528
5529         // either broadcast the data or send to a specific player
5530         if(p == NULL){          
5531                 multi_io_send_to_all_reliable(data, packet_size);
5532         } else {
5533                 multi_io_send_reliable(p, data, packet_size);
5534         }                       
5535 }
5536
5537 void process_player_settings_packet(ubyte *data, header *hinfo)
5538 {
5539         int offset,player_num;
5540         net_player_info bogus,*ptr;
5541         short player_id;
5542         ubyte stop;
5543
5544         offset = HEADER_LENGTH;
5545
5546         // read in the data for all the players
5547         GET_DATA(stop);
5548         while(stop != 0xff){
5549                 // lookup the player
5550                 GET_SHORT(player_id);
5551                 player_num = find_player_id(player_id);
5552
5553                 // make sure this is a valid player
5554                 if(player_num == -1){
5555                         ptr = &bogus;                   
5556                 } else {
5557                         ptr = &Net_players[player_num].p_info;
5558                 }
5559                 
5560                 GET_INT(ptr->team);
5561                 GET_INT(ptr->ship_index);
5562                 GET_INT(ptr->ship_class);
5563                 
5564                 // next stop byte
5565                 GET_DATA(stop);
5566         }
5567         PACKET_SET_SIZE();
5568
5569         // update the server with my new state
5570         // MWA -- 3/31/98 -- check for in mission instead of state.
5571         //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5572         if( !(Game_mode & GM_IN_MISSION) ) {
5573                 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5574                 send_netplayer_update_packet(); 
5575         }
5576
5577
5578         // display some cool text
5579         multi_common_add_text(XSTR("Received player settings packet\n",721),1); 
5580 }
5581
5582 void send_deny_packet(net_addr *addr, int code)
5583 {
5584         ubyte data[10];
5585         int packet_size = 0;
5586
5587         // build the header and add the rejection code
5588         BUILD_HEADER(DENY);
5589
5590         ADD_INT(code);
5591         
5592         // send the packet      
5593         psnet_send(addr, data, packet_size);
5594 }
5595
5596 void process_deny_packet(ubyte *data, header *hinfo)
5597 {
5598         int offset,code;
5599
5600         // get the denial code
5601         offset = HEADER_LENGTH;
5602         GET_INT(code);
5603         PACKET_SET_SIZE();
5604
5605         // if there is already a dialog active, do nothing - who cares at this point.
5606         if(popup_active()){
5607                 return;
5608         }
5609
5610         // display the appropriate dialog
5611         switch(code){
5612         case JOIN_DENY_JR_STATE :
5613                 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));
5614                 break;
5615         case JOIN_DENY_JR_TRACKER_INVAL :
5616                 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));
5617                 break;
5618         case JOIN_DENY_JR_PASSWD :
5619                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5620                 break;  
5621         case JOIN_DENY_JR_CLOSED :
5622                 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));
5623                 break;
5624         case JOIN_DENY_JR_TEMP_CLOSED :
5625                 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));
5626                 break;
5627         case JOIN_DENY_JR_RANK_HIGH :
5628                 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));
5629                 break;
5630         case JOIN_DENY_JR_RANK_LOW :
5631                 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));
5632                 break;
5633         case JOIN_DENY_JR_DUP :
5634                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5635                 break;
5636         case JOIN_DENY_JR_FULL :
5637                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5638                 break;
5639         case JOIN_DENY_JR_BANNED :
5640                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5641                 break;
5642         case JOIN_DENY_JR_NOOBS :
5643                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5644                 break;
5645         case JOIN_DENY_JR_INGAME_JOIN :
5646                 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));
5647                 break;
5648         case JOIN_DENY_JR_BAD_VERSION :
5649                 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));
5650                 break;  
5651         case JOIN_DENY_JR_TYPE :
5652                 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5653                 break;                  
5654         }       
5655
5656         // call this so that the join request timestamp automatically expires when we hear back from the server
5657         multi_join_reset_join_stamp();
5658 }
5659
5660 // this packet will consist of 
5661 // 1.) netplayer ship classes                   (85 bytes max)
5662 // 2.) ship weapon state data                   (241 bytes max)
5663 // 3.) player settings et. al.          (133 bytes max)
5664 // TOTAL                            459                         NOTE : keep this in mind when/if adding new data to this packet
5665 void send_post_sync_data_packet(net_player *p, int std_request)
5666 {
5667         ubyte data[MAX_PACKET_SIZE], val;
5668         char bval;
5669         ship *shipp;            
5670         net_player *pl;
5671         ship_obj *so;
5672         ushort sval, ship_ets;
5673         int idx, player_index;
5674         int packet_size = 0;
5675         int ship_count;
5676         short val_short;
5677
5678         BUILD_HEADER(POST_SYNC_DATA);
5679
5680         // some header information for standalone packet routing purposes
5681         val = (ubyte)std_request;
5682         ADD_DATA(val);
5683
5684         // the standalone has two situations
5685         // 1.) sending a request to the host to distribute this block of data
5686         // 2.) having recevied this block of data from the host, it redistributes it
5687         if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5688                 // case 1, send the request                                     
5689                 multi_io_send_reliable(Netgame.host, data, packet_size);
5690                 return;
5691         }
5692         // case 2 for the standalone is below (as normal)
5693
5694         // otherwise build the data now 
5695         
5696         // add all deleted ships
5697         val = (ubyte)Multi_ts_num_deleted;
5698         ADD_DATA(val);
5699         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5700                 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5701                 ADD_USHORT(sval);
5702         }
5703
5704         // ship count   
5705         ship_count = 0;
5706         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5707                 shipp = &Ships[Objects[so->objnum].instance];
5708
5709                 // don't process non player wing ships
5710                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5711                         continue;
5712
5713                 ship_count++;
5714         }
5715
5716         // # of ships - used multiple times in the packet
5717         val = (ubyte)ship_count;
5718         ADD_DATA(val);
5719
5720         // add ship class information (85 bytes max)    
5721         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
5722                 shipp = &Ships[Objects[so->objnum].instance];
5723
5724                 // don't process non player wing ships
5725                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5726                         continue;               
5727                 
5728                 // add the net signature of the object for look up
5729                 ADD_USHORT( Objects[so->objnum].net_signature );
5730                 
5731                 // add the ship info index 
5732                 val = (ubyte)(shipp->ship_info_index);
5733                 ADD_DATA(val);          
5734
5735                 // add the ships's team select index
5736                 val = (ubyte)shipp->ts_index;
5737                 ADD_DATA(val);
5738         }       
5739
5740         // add weapon state information for all starting ships (241 bytes max)
5741         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5742                 shipp = &Ships[Objects[so->objnum].instance];
5743
5744                 // don't process non player wing ships
5745                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5746                         continue;                       
5747
5748                 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5749                 pl = NULL;
5750                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5751                         player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5752                         if(player_index == -1){
5753                                 pl = NULL;
5754                         } else {
5755                                 pl = &Net_players[player_index];
5756                         }
5757                 }
5758
5759                 // add the net signature and other weapon information
5760                 ADD_USHORT( Objects[so->objnum].net_signature );                
5761
5762                 // add number of primary and secondary banks
5763                 bval = (char)(shipp->weapons.num_primary_banks);
5764                 ADD_DATA(bval);
5765                 bval = (char)(shipp->weapons.num_secondary_banks);
5766                 ADD_DATA(bval);
5767
5768                 // add weapon bank status
5769                 bval = (char)(shipp->weapons.current_primary_bank);
5770                 if(pl != NULL){
5771                         pl->s_info.cur_primary_bank = bval;
5772                 }
5773                 // SDL_assert(bval != -1);
5774                 ADD_DATA(bval);
5775
5776                 bval = (char)(shipp->weapons.current_secondary_bank);
5777                 if(pl != NULL){
5778                         pl->s_info.cur_secondary_bank = bval;
5779                 }
5780                 // SDL_assert(bval != -1);
5781                 ADD_DATA(bval);
5782                                                 
5783                 // primary weapon info
5784                 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5785                 ADD_DATA(bval);
5786                 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5787                 ADD_DATA(bval);
5788
5789                 // secondary weapon info
5790                 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5791                 ADD_DATA(bval);
5792                 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5793                 ADD_SHORT(val_short);
5794                 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5795                 ADD_DATA(bval);
5796                 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5797                 ADD_SHORT(val_short);
5798                 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5799                 ADD_DATA(bval);
5800                 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5801                 ADD_SHORT(val_short);           
5802                 
5803                 // send primary and secondary weapon link status
5804                 val = 0x0;
5805                 if(shipp->flags & SF_PRIMARY_LINKED){
5806                         if(pl != NULL){
5807                                 pl->s_info.cur_link_status |= (1<<0);
5808                         }
5809                         val |= (1<<0);
5810                 }                               
5811                 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5812                         if(pl != NULL){
5813                                 pl->s_info.cur_link_status |= (1<<1);
5814                         }
5815                         val |= (1<<1);
5816                 }               
5817                 // if this is a player ship add (1<<2)
5818                 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5819                         val |= (1<<2);
5820                 }
5821                 ADD_DATA(val);
5822
5823                 // add a ship ets value
5824                 ship_ets = 0x0000;
5825                 // shield ets           
5826                 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5827                 // weapon ets
5828                 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5829                 // engine ets
5830                 ship_ets |= ((ushort)shipp->engine_recharge_index);
5831                 ADD_USHORT(ship_ets);
5832
5833         }
5834
5835         // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5836         // or if I'm the server as well as the host, I should be sending this to all players
5837         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5838                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5839                         // broadcast
5840                         if(p == NULL){                          
5841                                 multi_io_send_to_all_reliable(data, packet_size);
5842                         }
5843                         // send to a specific player
5844                         else {
5845                                 multi_io_send_reliable(p, data, packet_size);
5846                         }
5847                 } else {
5848                         multi_io_send_reliable(Net_player, data, packet_size);
5849                 }
5850         }
5851         // standalone mode
5852         else {
5853                 // broadcast
5854                 if(p == NULL){
5855                         multi_io_send_to_all_reliable(data, packet_size);
5856                 }
5857                 // send to a specific player
5858                 else {
5859                         multi_io_send_reliable(p, data, packet_size);
5860                 }
5861         }
5862 }
5863
5864 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5865 {
5866         ubyte val, sinfo_index, ts_index;
5867         char b;
5868         ushort net_sig, ship_ets, sval;
5869         ship *shipp;
5870         object *objp;
5871         int idx;
5872         int offset = HEADER_LENGTH;
5873         int ship_count;
5874         short val_short;
5875
5876         // packet routing information
5877         GET_DATA(val);
5878
5879         // 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
5880         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5881                 PACKET_SET_SIZE();
5882
5883                 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5884                 multi_ts_create_wings();
5885                 
5886                 // send to the standalone through my socket
5887                 send_post_sync_data_packet(Net_player);
5888                 return;
5889         }
5890
5891         // process player
5892
5893         // add all deleted ships
5894         GET_DATA(val);
5895         Multi_ts_num_deleted = (int)val;
5896         for(idx=0;idx<Multi_ts_num_deleted;idx++){
5897                 // get the ship's objnum
5898                 GET_USHORT(sval);
5899                 objp = NULL;
5900                 objp = multi_get_network_object(sval);
5901                 if(objp != NULL){
5902                         // delete the ship appropriately
5903                         // mark the object as having been deleted
5904                         Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5905
5906                         // delete the ship
5907                         ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5908                         obj_delete(Multi_ts_deleted_objnums[idx]);                      
5909                         ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5910                 } else {
5911                         Multi_ts_num_deleted--;
5912                         nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5913                 }
5914         }
5915
5916         // ship count
5917         GET_DATA(val);
5918         ship_count = val;
5919
5920         // process ship class information
5921         for(idx=0; idx<ship_count; idx++){      
5922                 // get the object's net signature
5923                 GET_USHORT(net_sig);
5924                 GET_DATA(sinfo_index);
5925                 GET_DATA(ts_index);
5926
5927                 // attempt to get the object
5928                 objp = multi_get_network_object(net_sig);
5929
5930                 // make sure we found a ship
5931                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5932
5933                 // set the ship to be the right class
5934                 change_ship_type(objp->instance,(int)sinfo_index);
5935
5936                 // set the ship's team select index
5937                 Ships[objp->instance].ts_index = (int)ts_index;         
5938         }
5939
5940         // process ship weapon state info
5941         for(idx=0; idx<ship_count; idx++){      
5942                 // get the object's net signature
5943                 GET_USHORT(net_sig);
5944
5945                 // attempt to get the object
5946                 objp = multi_get_network_object(net_sig);
5947
5948                 // make sure we found a ship
5949                 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5950
5951                 // get a pointer to the ship
5952                 shipp = &Ships[objp->instance];
5953
5954                 // get number of primary and secondary banks;
5955                 GET_DATA(b);
5956                 SDL_assert( b != -1 );
5957                 shipp->weapons.num_primary_banks = (int)b;
5958
5959                 GET_DATA(b);
5960                 SDL_assert( b != -1 );
5961                 shipp->weapons.num_secondary_banks = (int)b;
5962
5963                 // get bank selection info
5964                 GET_DATA(b);
5965                 if ( b == -1 ){
5966                         b = 0;
5967                 }
5968                 shipp->weapons.current_primary_bank = (int)b;
5969
5970                 GET_DATA(b);
5971                 if ( b == -1 ){
5972                         b = 0;
5973                 }
5974                 shipp->weapons.current_secondary_bank = (int)b;         
5975
5976                         // primary weapon info
5977                 GET_DATA(b);
5978                 shipp->weapons.primary_bank_weapons[0] = (int)b;
5979
5980                 GET_DATA(b);
5981                 shipp->weapons.primary_bank_weapons[1] = (int)b;
5982
5983                 // secondary weapon info
5984                 GET_DATA(b);
5985                 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5986                 GET_SHORT(val_short);
5987                 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5988
5989                 GET_DATA(b);
5990                 shipp->weapons.secondary_bank_weapons[1] = (int)b;
5991                 GET_SHORT(val_short);
5992                 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
5993
5994                 GET_DATA(b);
5995                 shipp->weapons.secondary_bank_weapons[2] = (int)b;
5996                 GET_SHORT(val_short);
5997                 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
5998
5999                 // other flags
6000                 val = 0x0;
6001                 GET_DATA(val);
6002
6003                 if(val & (1<<0)){
6004                         shipp->flags |= SF_PRIMARY_LINKED;                              
6005                 }                               
6006                 if(val & (1<<1)){               
6007                         shipp->flags |= SF_SECONDARY_DUAL_FIRE;                 
6008                 }
6009                 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6010                 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6011                 if(val & (1<<2)){
6012                         Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6013                 } else {
6014                         obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6015                 }
6016
6017                 // get ship ets
6018                 GET_USHORT(ship_ets);
6019                 // shield ets
6020                 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6021                 // weapon ets
6022                 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6023                 // engine ets
6024                 shipp->engine_recharge_index = (ship_ets & 0x000f);     
6025         }
6026         PACKET_SET_SIZE();
6027
6028         // ack the server
6029         Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6030         send_netplayer_update_packet();
6031
6032         // the standalone server will receive this packet from the host of the game, to be applied locally and
6033         // also to be rebroadcast. 
6034         if(Game_mode & GM_STANDALONE_SERVER){
6035                 // update player ets settings
6036                 for(idx=0;idx<MAX_PLAYERS;idx++){
6037                         if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6038                                 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6039                         }
6040                 }                       
6041                 
6042                 send_post_sync_data_packet(NULL,0);
6043         }
6044 }
6045
6046 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6047 {
6048         ubyte data[MAX_PACKET_SIZE],val;
6049         short val_short;
6050         int idx,i;
6051         int packet_size = 0;
6052
6053         // build the header
6054         BUILD_HEADER(WSS_SLOTS_DATA);
6055
6056         // some header information for standalone packet routing purposes
6057         val = (ubyte)std_request;
6058         ADD_DATA(val);
6059
6060         // add the team #
6061         val = (ubyte)team_num;
6062         ADD_DATA(val);
6063         
6064         // add whether this is the final packet or not
6065         val = (ubyte)final;
6066         ADD_DATA(val);
6067
6068         // the standalone has two situations
6069         // 1.) sending a request to the host to distribute this block of data
6070         // 2.) having recevied this block of data from the host, it redistributes it
6071         if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6072                 // case 1, send the request                                     
6073                 multi_io_send_reliable(Netgame.host, data, packet_size);
6074                 return;
6075         }
6076         // case 2 for the standalone is below (as normal)
6077
6078         // add all the slots
6079         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6080                 // add the ship class
6081                 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6082                 ADD_DATA(val);
6083
6084                 // add the weapons
6085                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6086                         val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6087                         ADD_DATA(val);
6088                 }
6089
6090                 // add the weapon counts
6091                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6092                         val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6093                         ADD_SHORT(val_short);
6094                 }
6095         }
6096
6097                 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6098         // or if I'm the server as well as the host, I should be sending this to all players
6099         if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6100                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6101                         // broadcast
6102                         if(p == NULL){                          
6103                                 multi_io_send_to_all_reliable(data, packet_size);
6104                         }
6105                         // send to a specific player
6106                         else {
6107                                 multi_io_send_reliable(p, data, packet_size);
6108                         }
6109                 } else {
6110                         multi_io_send_reliable(Net_player, data, packet_size);
6111                 }
6112         }
6113         // standalone mode
6114         else {
6115                 // broadcast
6116                 if(p == NULL){
6117                         multi_io_send_to_all_reliable(data, packet_size);                       
6118                 }
6119                 // send to a specific player
6120                 else {
6121                         multi_io_send_reliable(p, data, packet_size);
6122                 }
6123         }       
6124 }
6125
6126 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6127 {
6128         ubyte val,team_num,final;
6129         int idx,i;
6130         int offset = HEADER_LENGTH;
6131         short val_short;
6132
6133         // packet routing information
6134         GET_DATA(val);
6135
6136         // get team data
6137         GET_DATA(team_num);
6138
6139         // get whether this is the final packet or not
6140         GET_DATA(final);
6141
6142         // 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
6143         if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6144                 PACKET_SET_SIZE();
6145
6146                 // send to the standalone through my socket
6147                 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6148                 return;
6149         }       
6150
6151         // read in all the slot data
6152         for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6153                 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6154
6155                 // get the ship class
6156                 GET_DATA(val);
6157                 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6158
6159                 // get the weapons
6160                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6161                         GET_DATA(val);
6162                         Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6163
6164                         // check for signed/unsigned problems
6165                         if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6166                                 Wss_slots_teams[team_num][idx].wep[i] = -1;
6167                         }
6168                 } 
6169
6170                 // get the weapon counts
6171                 for(i = 0;i<MAX_WL_WEAPONS;i++){
6172                         GET_SHORT(val_short);
6173                         Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6174                 }
6175         }
6176         PACKET_SET_SIZE();
6177
6178         // update my netplayer state if this is the final packet
6179         if(final){
6180                 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6181                 send_netplayer_update_packet();
6182         }
6183
6184         // the standalone server will receive this packet from the host of the game, to be applied locally and
6185         // also to be rebroadcast. 
6186         if(Game_mode & GM_STANDALONE_SERVER){
6187                 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6188         } else {
6189                 // add some mission sync text
6190                 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6191         }
6192 }
6193
6194 #define OBJ_VISIBILITY_DOT                                      0.6f    
6195
6196 // send and receive packets for shield explosion information
6197 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6198 {
6199         int packet_size, i;
6200         ubyte data[MAX_PACKET_SIZE], utri_num;
6201
6202         Int3();
6203         // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6204
6205         SDL_assert( tri_num < UCHAR_MAX );
6206         utri_num = (ubyte)tri_num;
6207
6208         // for each player, determine if this object is behind the player -- if so, don't
6209         // send the packet.
6210         for ( i = 0; i < MAX_PLAYERS; i++ ) {
6211                 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6212                         float           dot;
6213                         vector  eye_to_obj_vec, diff, eye_pos;
6214                         matrix  eye_orient;
6215
6216                         eye_pos = Net_players[i].s_info.eye_pos;
6217                         eye_orient = Net_players[i].s_info.eye_orient;
6218
6219                         // check for same vectors
6220                         vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6221                         if ( vm_vec_mag_quick(&diff) < 0.01 ){
6222                                 continue;
6223                         }
6224
6225                         vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6226                         dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6227
6228                         if ( dot < OBJ_VISIBILITY_DOT ){
6229                                 continue;
6230                         }
6231
6232                         BUILD_HEADER(SHIELD_EXPLOSION);
6233
6234                         ADD_USHORT( Objects[objnum].net_signature );
6235                         ADD_DATA(utri_num);                     
6236                         
6237                         multi_io_send(&Net_players[i], data, packet_size);
6238                 }
6239         }
6240 }
6241
6242 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6243
6244 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6245 {
6246         int offset;
6247         ushort signature;
6248         ubyte utri_num;
6249         object *objp;
6250
6251         // get the shield hit data
6252         offset = HEADER_LENGTH;
6253         GET_USHORT(signature);
6254         GET_DATA(utri_num);
6255         //GET_DATA(hit_pos);
6256         PACKET_SET_SIZE();
6257
6258         // find the object with this signature.  If found, then do a shield explosion
6259         objp = multi_get_network_object( signature );
6260         if ( objp ) {
6261                 polymodel *pm;
6262                 shield_info *shieldp;
6263                 shield_tri stri;
6264                 vector hit_pos;
6265                 int i;
6266
6267                 // given the tri num, find the local position which is the average of the
6268                 // three vertices of the triangle affected.  Use this average point as the hit
6269                 // point
6270                 // SDL_assert( objp->type == OBJ_SHIP );
6271                 if(objp->type != OBJ_SHIP){
6272                         return;
6273                 }
6274
6275                 pm = model_get(Ships[objp->instance].modelnum);
6276                 shieldp = &pm->shield;
6277                 SDL_assert( utri_num < shieldp->ntris );
6278                 stri = shieldp->tris[utri_num];
6279                 vm_vec_zero(&hit_pos);
6280                 for ( i = 0; i < 3; i++ ) {
6281                         vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6282                 }
6283                 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6284                 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6285         }
6286 }
6287
6288 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6289 {
6290         scoring_struct *sc;
6291         ubyte data[MAX_PACKET_SIZE], val;
6292         int idx;                
6293         int packet_size = 0;
6294
6295         ushort u_tmp;
6296         int i_tmp;
6297
6298         sc = &pl->player->stats;
6299
6300         // build the header
6301         BUILD_HEADER(PLAYER_STATS);     
6302
6303         // add the player id
6304         ADD_SHORT(pl->player_id);
6305
6306         // add the byte indicating whether these stats are all-time or not
6307         val = (ubyte)stats_code;
6308         ADD_DATA(val);  
6309         
6310         // kill information - alltime
6311         switch(stats_code){
6312         case STATS_ALLTIME:     
6313                 // alltime kills
6314                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6315                         u_tmp = sc->kills[idx];
6316                         ADD_USHORT(u_tmp);
6317                 }
6318                 // medal information
6319                 for(idx=0;idx<NUM_MEDALS;idx++){
6320                         i_tmp = sc->medals[idx];
6321                         ADD_INT(i_tmp);
6322                 }
6323
6324                 ADD_INT(sc->score);
6325                 ADD_INT(sc->rank);
6326                 ADD_INT(sc->assists);
6327                 ADD_INT(sc->kill_count);
6328                 ADD_INT(sc->kill_count_ok);
6329                 ADD_UINT(sc->p_shots_fired);
6330                 ADD_UINT(sc->s_shots_fired);
6331                 ADD_UINT(sc->p_shots_hit);
6332                 ADD_UINT(sc->s_shots_hit);
6333                 ADD_UINT(sc->p_bonehead_hits);
6334                 ADD_UINT(sc->s_bonehead_hits);
6335                 ADD_INT(sc->bonehead_kills);
6336
6337                 ADD_UINT(sc->missions_flown);
6338                 ADD_UINT(sc->flight_time);
6339                 ADD_INT(sc->last_flown);
6340                 ADD_INT(sc->last_backup);
6341                 break;
6342
6343         case STATS_MISSION:     
6344                 // mission OKkills              
6345                 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6346                         u_tmp = sc->m_okKills[idx];
6347                         ADD_USHORT(u_tmp);                      
6348                 }
6349         
6350                 ADD_INT(sc->m_score);
6351                 ADD_INT(sc->m_assists);
6352                 ADD_INT(sc->m_kill_count);
6353                 ADD_INT(sc->m_kill_count_ok);
6354                 ADD_UINT(sc->mp_shots_fired);
6355                 ADD_UINT(sc->ms_shots_fired);
6356                 ADD_UINT(sc->mp_shots_hit);
6357                 ADD_UINT(sc->ms_shots_hit);
6358                 ADD_UINT(sc->mp_bonehead_hits);
6359                 ADD_UINT(sc->ms_bonehead_hits);
6360                 ADD_INT(sc->m_bonehead_kills);
6361                 ADD_INT(sc->m_player_deaths);
6362                 ADD_INT(sc->m_medal_earned);
6363                 break;
6364
6365         case STATS_MISSION_KILLS:               
6366                 ADD_INT(sc->m_kill_count);
6367                 ADD_INT(sc->m_kill_count_ok);
6368                 ADD_INT(sc->m_assists);
6369                 break;          
6370
6371         case STATS_DOGFIGHT_KILLS:
6372                 for(idx=0; idx<MAX_PLAYERS; idx++){
6373 #ifndef MAKE_FS1
6374                         u_tmp = sc->m_dogfight_kills[idx];
6375 #else
6376                         u_tmp = 0;
6377 #endif
6378                         ADD_USHORT(u_tmp);
6379                 }
6380                 ADD_INT(sc->m_kill_count);
6381                 ADD_INT(sc->m_kill_count_ok);
6382                 ADD_INT(sc->m_assists);
6383                 break;          
6384         }
6385
6386         SDL_assert(packet_size < MAX_PACKET_SIZE);
6387
6388         // if we're a client, always send the data to the server
6389         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6390                 multi_io_send_reliable(Net_player, data, packet_size);          
6391         }
6392         // otherwise do server specific stuff
6393         else {
6394                 // send to a specific target
6395                 if(target != NULL){
6396                         multi_io_send_reliable(target, data, packet_size);                      
6397                 }
6398                 // otherwise, send to everyone
6399                 else {                  
6400                         multi_io_send_to_all_reliable(data, packet_size);
6401                 }
6402         }
6403 }
6404
6405 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6406 {
6407         ubyte val;
6408         int player_num,idx;
6409         scoring_struct *sc,bogus;
6410         short player_id;
6411         int offset = HEADER_LENGTH;
6412         ushort u_tmp;
6413         int i_tmp;
6414
6415         // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6416
6417         // get the player who these stats are for
6418         GET_SHORT(player_id);   
6419         player_num = find_player_id(player_id);
6420         if (player_num == -1) {
6421                 nprintf(("Network", "Couldn't find player for stats update!\n"));
6422                 ml_string("Couldn't find player for stats update!\n");
6423
6424                 sc = &bogus;
6425                 Int3();
6426         } else {
6427                 sc = &Net_players[player_num].player->stats;
6428         }
6429
6430         // get the stats code
6431         GET_DATA(val);  
6432         switch(val){
6433         case STATS_ALLTIME:
6434                 ml_string("Received STATS_ALLTIME\n");
6435
6436                 // kills - alltime
6437                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6438                         GET_USHORT(u_tmp);
6439                         sc->kills[idx] = u_tmp;
6440                 }
6441
6442                 // read in the stats
6443                 for (idx=0; idx<NUM_MEDALS; idx++) {
6444                         GET_INT(i_tmp);
6445                         sc->medals[idx] = i_tmp;
6446                 }
6447
6448                 GET_INT(sc->score);
6449                 GET_INT(sc->rank);
6450                 GET_INT(sc->assists);
6451                 GET_INT(sc->kill_count);
6452                 GET_INT(sc->kill_count_ok);
6453                 GET_UINT(sc->p_shots_fired);
6454                 GET_UINT(sc->s_shots_fired);
6455                 GET_UINT(sc->p_shots_hit);
6456                 GET_UINT(sc->s_shots_hit);
6457                 GET_UINT(sc->p_bonehead_hits);
6458                 GET_UINT(sc->s_bonehead_hits);
6459                 GET_INT(sc->bonehead_kills);
6460
6461                 GET_UINT(sc->missions_flown);
6462                 GET_UINT(sc->flight_time);
6463                 GET_INT(sc->last_flown);
6464                 GET_INT(sc->last_backup);
6465                 break;
6466
6467         case STATS_MISSION:
6468                 ml_string("Received STATS_MISSION\n");
6469
6470                 // kills - mission OK                   
6471                 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6472                         GET_USHORT(u_tmp);
6473                         sc->m_okKills[idx] = u_tmp;                     
6474                 }
6475                 
6476                 GET_INT(sc->m_score);
6477                 GET_INT(sc->m_assists);
6478                 GET_INT(sc->m_kill_count);
6479                 GET_INT(sc->m_kill_count_ok);
6480                 GET_UINT(sc->mp_shots_fired);
6481                 GET_UINT(sc->ms_shots_fired);
6482                 GET_UINT(sc->mp_shots_hit);
6483                 GET_UINT(sc->ms_shots_hit);
6484                 GET_UINT(sc->mp_bonehead_hits);
6485                 GET_UINT(sc->ms_bonehead_hits);
6486                 GET_INT(sc->m_bonehead_kills);
6487                 GET_INT(sc->m_player_deaths);
6488                 GET_INT(sc->m_medal_earned);
6489                 break;
6490
6491         case STATS_MISSION_KILLS:               
6492                 ml_string("Received STATS_MISSION_KILLS\n");
6493
6494                 GET_INT(sc->m_kill_count);
6495                 GET_INT(sc->m_kill_count_ok);
6496                 GET_INT(sc->m_assists);
6497                 break;          
6498
6499         case STATS_DOGFIGHT_KILLS:
6500                 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6501                 if(player_num >= 0){
6502                         ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6503                 }
6504                 for(idx=0; idx<MAX_PLAYERS; idx++){
6505                         GET_USHORT(u_tmp);
6506 #ifndef MAKE_FS1
6507                         sc->m_dogfight_kills[idx] = u_tmp;
6508                         if(player_num >= 0){                            
6509                                 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6510                         }
6511 #endif
6512                 }
6513                 GET_INT(sc->m_kill_count);
6514                 GET_INT(sc->m_kill_count_ok);
6515                 GET_INT(sc->m_assists);         
6516                 break;          
6517         }
6518         PACKET_SET_SIZE();
6519
6520         // if I'm the server of the game, I should always rebroadcast these stats
6521         if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6522                 // make sure these are alltime stats
6523                 SDL_assert(val == STATS_ALLTIME);
6524
6525                 multi_broadcast_stats(STATS_ALLTIME);
6526         }
6527 }
6528
6529 // called to create asteroid stuff
6530 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6531 {
6532         int packet_size;
6533         ubyte data[MAX_PACKET_SIZE];
6534         ubyte packet_type, atype;
6535         vector vec;
6536
6537         vm_vec_zero(&vec);
6538         if (relvec != NULL )
6539                 vec = *relvec;
6540
6541         BUILD_HEADER( ASTEROID_INFO );
6542         packet_type = ASTEROID_CREATE;
6543
6544         SDL_assert( asteroid_type < UCHAR_MAX );
6545         atype = (ubyte)asteroid_type;
6546
6547         ADD_DATA( packet_type );
6548         ADD_USHORT( parent_objp->net_signature );
6549         ADD_USHORT( new_objp->net_signature );
6550         ADD_DATA( atype );
6551         //ADD_DATA( vec );
6552         add_vector_data( data, &packet_size, vec );
6553
6554         multi_io_send_to_all(data, packet_size);
6555 }
6556
6557 void send_asteroid_throw( object *objp )
6558 {
6559         int packet_size;
6560         ubyte data[MAX_PACKET_SIZE], packet_type;
6561
6562         BUILD_HEADER( ASTEROID_INFO );
6563
6564         // this packet type is an asteroid throw
6565         packet_type = ASTEROID_THROW;
6566         ADD_DATA( packet_type );
6567         ADD_USHORT( objp->net_signature );
6568         //ADD_DATA( objp->pos );
6569         add_vector_data( data, &packet_size, objp->pos );
6570         //ADD_DATA( objp->phys_info.vel );
6571         add_vector_data( data, &packet_size, objp->phys_info.vel );
6572         
6573         multi_io_send_to_all(data, packet_size);
6574 }
6575
6576 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6577 {
6578         int packet_size;
6579         ubyte data[MAX_PACKET_SIZE], packet_type;
6580         vector vec;
6581
6582         vm_vec_zero(&vec);
6583         if ( hitpos != NULL )
6584                 vec = *hitpos;
6585
6586         // build up an asteroid hit packet
6587         BUILD_HEADER( ASTEROID_INFO );
6588         packet_type = ASTEROID_HIT;
6589         ADD_DATA( packet_type );
6590         ADD_USHORT( objp->net_signature );
6591
6592         if(other_objp == NULL){
6593                 ushort invalid_sig = 0xffff;
6594                 ADD_USHORT(invalid_sig);
6595         } else {
6596                 ADD_USHORT( other_objp->net_signature );
6597         }
6598         //ADD_DATA( vec );
6599         add_vector_data( data, &packet_size, vec );
6600         ADD_FLOAT( damage );
6601         
6602         multi_io_send_to_all(data, packet_size);
6603 }
6604
6605 void process_asteroid_info( ubyte *data, header *hinfo )
6606 {
6607         int offset;
6608         ubyte packet_type;
6609
6610         offset = HEADER_LENGTH;
6611         GET_DATA( packet_type );
6612
6613         // based on the packet type, do something interesting with an asteroid!
6614         switch( packet_type ) {
6615
6616         case ASTEROID_CREATE: {
6617                 ushort psignature, signature;
6618                 ubyte atype;
6619                 vector relvec = ZERO_VECTOR;
6620                 object *parent_objp;
6621
6622                 GET_USHORT( psignature );
6623                 GET_USHORT( signature );
6624                 GET_DATA( atype );
6625                 //GET_DATA( relvec );
6626                 get_vector_data( data, &offset, relvec );
6627
6628                 // after getting the values, set the next network signature, and call the create sub function
6629                 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6630                 parent_objp = multi_get_network_object( psignature );
6631                 if ( parent_objp ) {
6632                         asteroid_sub_create( parent_objp, atype, &relvec );
6633                 } else {
6634                         nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6635                 }
6636
6637
6638                 break;
6639         }
6640
6641                 // asteroid throw packet -- asteroid has wrapped bounds
6642         case ASTEROID_THROW: {
6643                 ushort signature;
6644                 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6645                 object *objp;
6646
6647                 GET_USHORT( signature );
6648                 //GET_DATA( pos );
6649                 get_vector_data( data, &offset, pos );
6650                 //GET_DATA( vel );
6651                 get_vector_data( data, &offset, vel );
6652                 objp = multi_get_network_object( signature );
6653                 if ( !objp ) {
6654                         nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6655                         break;
6656                 }
6657                 objp->pos = pos;
6658                 objp->phys_info.vel = vel;
6659                 objp->phys_info.desired_vel = vel;
6660                 break;
6661         }
6662
6663         case ASTEROID_HIT: {
6664                 ushort signature, osignature;
6665                 object *objp, *other_objp;
6666                 vector hitpos = ZERO_VECTOR;
6667                 float damage;
6668
6669                 GET_USHORT( signature );
6670                 GET_USHORT( osignature );
6671                 //GET_DATA( hitpos );
6672                 get_vector_data( data, &offset, hitpos );
6673                 GET_FLOAT( damage );
6674
6675                 objp = multi_get_network_object( signature );
6676                 if(osignature == 0xffff){
6677                         other_objp = NULL; 
6678                 } else {
6679                         other_objp = multi_get_network_object( osignature );
6680                 }
6681                 if ( !objp ) {
6682                         nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6683                         break;
6684                 }
6685
6686                 if ( IS_VEC_NULL(&hitpos) ){
6687                         asteroid_hit( objp, other_objp, NULL, damage );
6688                 } else {
6689                         asteroid_hit( objp, other_objp, &hitpos, damage );
6690                 }
6691                 
6692                 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6693                 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6694                         weapon_hit( other_objp, objp, &hitpos );
6695                 }
6696                 break;
6697         }
6698
6699         default:
6700                 Int3();
6701                 break;
6702         }
6703
6704         PACKET_SET_SIZE();
6705 }
6706
6707 void send_host_restr_packet(const char *callsign, int code, int mode)
6708 {
6709         ubyte data[MAX_PACKET_SIZE],val;
6710         int packet_size = 0;
6711
6712         // build the header and add the opcode
6713         BUILD_HEADER(HOST_RESTR_QUERY);
6714         val = (ubyte)code;
6715         ADD_DATA(val);
6716         val = (ubyte)mode;
6717         ADD_DATA(val);
6718
6719         // add the callsign
6720         ADD_STRING(callsign);
6721
6722         // if I'm the standalone server, I should be sending this to the game host
6723         if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){               
6724                 multi_io_send_reliable(Netgame.host, data, packet_size);
6725         } 
6726         // otherwise if I'm the host, I should be sending a reply back to the standalone server
6727         else {
6728                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);         
6729                 multi_io_send_reliable(Net_player, data, packet_size);
6730         }
6731 }       
6732
6733 void process_host_restr_packet(ubyte *data, header *hinfo)
6734 {
6735         char callsign[255];
6736         ubyte code,mode;
6737         int offset = HEADER_LENGTH;
6738
6739         // get the opcode and the callsign
6740         GET_DATA(code);
6741         GET_DATA(mode);
6742         GET_STRING(callsign);
6743         PACKET_SET_SIZE();
6744
6745         // do code specific operations
6746         switch(code){
6747         // query to the host from standalone
6748         case 0:         
6749                 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6750
6751                 // set the join mode
6752                 Multi_join_restr_mode = mode;
6753
6754                 // set the timestamp
6755                 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6756
6757                 // notify the host of the event
6758                 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6759                 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6760                 break;
6761                 
6762         // affirmative reply from the host to the standalone
6763         case 1:
6764                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);           
6765
6766                 // let the player join if the timestamp has not already elapsed on the server
6767                 if(Multi_restr_query_timestamp != -1){
6768                         multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6769                 }
6770                 break;  
6771
6772         // negative reply
6773         case 2 :
6774                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6775                 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6776                 Multi_restr_query_timestamp = -1;
6777                 break;
6778         }
6779 }
6780
6781 void send_netgame_end_error_packet(int notify_code,int err_code)
6782 {
6783         ubyte data[10];
6784         char code;
6785         int packet_size = 0;
6786
6787         // only the server should ever be here - although this might change if for some reason the host wants to end the game
6788         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6789         
6790         // build the header and add the notification and error codes
6791         BUILD_HEADER(NETGAME_END_ERROR);
6792         code = (char)notify_code;
6793         ADD_DATA(code);
6794         code = (char)err_code;
6795         ADD_DATA(code);
6796
6797         // send the packet      
6798         multi_io_send_to_all_reliable(data, packet_size);
6799 }
6800
6801 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6802 {
6803         int offset = HEADER_LENGTH;
6804         char notify_code,error_code;
6805
6806         // get the error and notification codes
6807         GET_DATA(notify_code);
6808         GET_DATA(error_code);
6809         PACKET_SET_SIZE();
6810
6811         // quit the game
6812         multi_quit_game(PROMPT_NONE,notify_code,error_code);    
6813 }
6814
6815 // sends info that a countermeasure succeeded.
6816 void send_countermeasure_success_packet( int objnum )
6817 {
6818         int pnum, packet_size;
6819         ubyte data[MAX_PACKET_SIZE];
6820
6821         pnum = multi_find_player_by_object( &Objects[objnum] );
6822         if ( pnum == -1 ) {
6823                 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6824                 return;
6825         }
6826
6827         BUILD_HEADER(COUNTERMEASURE_SUCCESS);   
6828         multi_io_send(&Net_players[pnum], data, packet_size);
6829 }
6830
6831 // start the flashing of my hud gauge
6832 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6833 {
6834         int offset;
6835
6836         offset = HEADER_LENGTH;
6837         PACKET_SET_SIZE();
6838
6839         hud_start_text_flash(XSTR("Evaded", 1430), 800);
6840         snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6841 }
6842
6843 #define UPDATE_IS_PAUSED                (1<<0)
6844 #define UPDATE_HULL_INFO                (1<<1)
6845
6846 void send_client_update_packet(net_player *pl)
6847 {
6848         ubyte data[MAX_PACKET_SIZE],val;
6849         int packet_size = 0;
6850
6851         // build the header
6852         BUILD_HEADER(CLIENT_UPDATE);
6853
6854         val = 0;        
6855
6856         // add the pause status
6857         if ( Multi_pause_status ) {
6858                 val |= UPDATE_IS_PAUSED;
6859         } 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) ) {
6860                 val |= UPDATE_HULL_INFO;
6861                 SDL_assert( Player_ship );                      // I"d better have one of these!!!!
6862         }
6863
6864         ADD_DATA(val);
6865
6866         // if paused, add the net address of the guy who paused
6867         if(val & UPDATE_IS_PAUSED){
6868                 SDL_assert(Multi_pause_pauser != NULL);
6869                 ADD_SHORT(Multi_pause_pauser->player_id);
6870         }
6871
6872         // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6873         if ( val & UPDATE_HULL_INFO ) {
6874                 object *objp;
6875                 ubyte percent, ns, threats;
6876                 ship_info *sip;
6877                 ship *shipp;
6878                 ship_subsys *subsysp;
6879                 int i;
6880
6881                 // get the object for the player
6882                 SDL_assert( pl->player->objnum != -1 );
6883
6884                 objp = &Objects[pl->player->objnum];
6885
6886                 SDL_assert ( objp->type == OBJ_SHIP );
6887                 shipp = &Ships[objp->instance];
6888                 sip = &Ship_info[shipp->ship_info_index];
6889
6890                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
6891                 // percentage value since that should be close enough
6892                 float temp = (objp->hull_strength  / sip->initial_hull_strength * 100.0f);              
6893                 if(temp < 0.0f){
6894                         percent = 0;
6895                 } else {
6896                         percent = (ubyte)temp;
6897                 }
6898                 ADD_DATA( percent );
6899
6900                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6901                         percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6902                         ADD_DATA( percent );
6903                 }
6904
6905                 // add the data for the subsystem hits.  We can assume that the lists will be the same side of
6906                 // both machines. Added as percent since that number <= 100
6907
6908                 // also write out the number of subsystems.  We do this because the client might not know
6909                 // about the object he is getting data for.  (i.e. he killed the object already).
6910                 ns = (ubyte)sip->n_subsystems;
6911                 ADD_DATA( ns );
6912
6913                 // now the subsystems.
6914                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6915                         percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6916                         ADD_DATA( percent );
6917                 }
6918
6919                 // compute the threats for this player.  Only compute the threats if this player is actually
6920                 // playing (i.e. he has a ship)
6921                 hud_update_reticle( pl->player );
6922                 threats = (ubyte)pl->player->threat_flags;
6923                 ADD_DATA( threats );
6924
6925                 // add his energy level for guns
6926                 ADD_FLOAT(shipp->weapon_energy);
6927
6928                 // add his secondary bank ammo
6929                 ADD_INT(shipp->weapons.num_secondary_banks);
6930                 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6931                         ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6932                 }
6933         }
6934
6935         // add pl
6936         ADD_INT(pl->sv_last_pl);
6937
6938         // send the packet reliably to the player       
6939         multi_io_send(pl, data, packet_size);
6940 }
6941
6942 void process_client_update_packet(ubyte *data, header *hinfo)
6943 {
6944         ubyte val;
6945         short pauser;
6946         int player_index;
6947         int is_paused, have_hull_info;
6948         int ammo_count;
6949         int ammo[10];
6950         float weapon_energy;
6951         int offset = HEADER_LENGTH;
6952
6953         // get the header byte containing useful information
6954         GET_DATA(val);
6955
6956         is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6957         have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6958
6959         // if we are paused, get who paused
6960         if(is_paused){          
6961                 GET_SHORT(pauser);
6962                 player_index = find_player_id(pauser);
6963                 if(player_index != -1){
6964                         Multi_pause_pauser = &Net_players[player_index];
6965                 } else {
6966                         Multi_pause_pauser = NULL;
6967                 }       
6968         }
6969
6970         // if we have hull information, then read it in.
6971         if ( have_hull_info ) {
6972                 float val;
6973                 ship_info *sip;
6974                 ship *shipp;
6975                 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6976                 ubyte ub_tmp;
6977                 ship_subsys *subsysp;
6978                 object *objp;
6979                 int i;
6980
6981                 // hull strength and sheild mesh information are floats (as a percentage).  Pass the integer
6982                 // percentage value since that should be close enough
6983                 GET_DATA( hull_percent );
6984
6985                 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6986                         GET_DATA(ub_tmp);
6987                         shield_percent[i] = ub_tmp;
6988                 }
6989
6990                 // get the data for the subsystems
6991                 GET_DATA( n_subsystems );
6992                 for ( i = 0; i < n_subsystems; i++ ){
6993                         GET_DATA(ub_tmp);
6994                         subsystem_percent[i] = ub_tmp;
6995                 }
6996
6997                 GET_DATA( threats );
6998
6999                 // add his energy level for guns
7000                 GET_FLOAT(weapon_energy);
7001                 
7002                 // add his secondary bank ammo
7003                 GET_INT(ammo_count);
7004                 for(i=0; i<ammo_count; i++){
7005                         GET_INT(ammo[i]);
7006                 }
7007
7008                 // assign the above information to my ship, assuming that I can find it!  Ingame joiners might get this
7009                 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7010                 // UDP client update packets.  Only read this info if I have a ship.
7011                 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {                        
7012                         shipp = Player_ship;
7013                         objp = Player_obj;
7014                         sip = &Ship_info[shipp->ship_info_index];
7015
7016                         val = hull_percent * sip->initial_hull_strength / 100.0f;
7017                         objp->hull_strength = val;
7018
7019                         for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7020                                 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7021                                 objp->shields[i] = val;
7022                         }
7023
7024                         // for sanity, be sure that the number of susbystems that I read in matches the player.  If not,
7025                         // then don't read these in.
7026                         if ( n_subsystems == sip->n_subsystems ) {
7027
7028                                 n_subsystems = 0;               // reuse this variable
7029                                 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7030                                         int subsys_type;
7031
7032                                         val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7033                                         subsysp->current_hits = val;
7034
7035                                         // add the value just generated (it was zero'ed above) into the array of generic system types
7036                                         subsys_type = subsysp->system_info->type;                                       // this is the generic type of subsystem
7037                                         SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7038                                         shipp->subsys_info[subsys_type].current_hits += val;
7039                                         n_subsystems++;
7040                                 }
7041                         }
7042                         ship_recalc_subsys_strength( shipp );
7043
7044                         shipp->weapon_energy = weapon_energy;
7045                         for(i=0; i<ammo_count; i++){
7046                                 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7047                         }
7048
7049                         // update my threat flags.
7050                         // temporarily commented out until tested.
7051                         Net_player->player->threat_flags = threats;
7052                 }
7053         }
7054
7055         // get pl
7056         int pl;
7057         GET_INT(pl);
7058         if(Net_player != NULL){
7059                 Net_player->cl_last_pl = pl;
7060         }
7061
7062         PACKET_SET_SIZE();
7063         // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7064         if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7065                 if( is_paused ) {
7066                         multi_pause_pause();
7067                 } else {
7068                         multi_pause_unpause();
7069                 }
7070         }
7071 }
7072
7073 void send_countdown_packet(int time)
7074 {
7075         ubyte data[20];
7076         char val;
7077         int packet_size = 0;
7078
7079         // build the header and add the time
7080         BUILD_HEADER(COUNTDOWN);
7081         val = (char)time;
7082         ADD_DATA(val);
7083
7084         // if we're the server, we should broadcast to everyone
7085         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
7086                 multi_io_send_to_all_reliable(data, packet_size);
7087         }
7088         // otherwise we'de better be a host sending to the standalone
7089         else {
7090                 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7091                 multi_io_send_reliable(Net_player, data, packet_size);
7092         }
7093 }
7094
7095 void process_countdown_packet(ubyte *data, header *hinfo)
7096 {
7097         int offset = HEADER_LENGTH;
7098         char time;
7099
7100         // get the time
7101         GET_DATA(time);
7102         PACKET_SET_SIZE();
7103
7104         // if we're not in the post sync data screen, ignore it
7105         if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7106                 return;
7107         }
7108
7109         // if we're the standalone, this should be a -1 telling us to start the countdown
7110         if(Game_mode & GM_STANDALONE_SERVER){
7111                 SDL_assert((int)time == -1);
7112
7113                 // start the countdown
7114                 multi_sync_start_countdown();
7115         }
7116         // otherwise if we're clients, just bash the countdown
7117         else {          
7118                 Multi_sync_countdown = (int)time;
7119         }
7120 }
7121
7122 // packets for debriefing information
7123 void send_debrief_info( int stage_count[], int *stages[] )
7124 {
7125         ubyte data[MAX_PACKET_SIZE];
7126         int packet_size, i, j;
7127         int i_tmp;
7128
7129         BUILD_HEADER(DEBRIEF_INFO);
7130
7131         // add the data for the teams
7132         for ( i = 0; i < Num_teams; i++ ) {
7133                 int count;
7134
7135                 count = stage_count[i];
7136                 ADD_INT( count );
7137                 for ( j = 0; j < count; j++ ) {
7138                         i_tmp = stages[i][j];
7139                         ADD_INT( i_tmp );
7140                 }
7141         }
7142         
7143         multi_io_send_to_all_reliable(data, packet_size);
7144 }
7145
7146 // process a debrief info packet from the server
7147 void process_debrief_info( ubyte *data, header *hinfo )
7148 {
7149         int offset, i, j;
7150         int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7151         int i_tmp;
7152
7153         offset = HEADER_LENGTH;
7154         for ( i = 0; i < Num_teams; i++ ) {
7155                 int count;
7156
7157                 GET_INT( count );
7158                 stage_counts[i] = count;
7159                 stages[i] = active_stages[i];
7160                 for ( j = 0; j < count; j++ ) {
7161                         GET_INT(i_tmp);
7162                         active_stages[i][j] = i_tmp;
7163                 }
7164         }
7165         PACKET_SET_SIZE();
7166
7167         // now that we have the stage data for the debriefing stages, call debrief function with the
7168         // data so that clients can now see the debriefing stuff.  Do it only for my team.
7169         SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7170         debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7171 }
7172
7173 // sends homing information to all clients.  We only need signature and num_missiles (because of hornets).
7174 // sends homing_object and homing_subsystem to all clients.
7175 void send_homing_weapon_info( int weapon_num )
7176 {
7177         ubyte data[MAX_PACKET_SIZE];
7178         char t_subsys;
7179         int packet_size;
7180         object *homing_object;
7181         ushort homing_signature;
7182         weapon *wp;
7183
7184         wp = &Weapons[weapon_num];
7185
7186         // be sure that this weapon object is a homing object.
7187         if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7188                 return;
7189
7190         // get the homing signature.  If this weapon isn't homing on anything, then sent 0 as the
7191         // homing signature.
7192         homing_signature = 0;
7193         homing_object = wp->homing_object;
7194         if ( homing_object != NULL ) {
7195                 homing_signature = homing_object->net_signature;
7196
7197                 // get the subsystem index.
7198                 t_subsys = -1;
7199                 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7200                         int s_index;
7201
7202                         s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7203                         SDL_assert( s_index < CHAR_MAX );                       // better be less than this!!!!
7204                         t_subsys = (char)s_index;
7205                 }
7206         }
7207
7208         BUILD_HEADER(HOMING_WEAPON_UPDATE);
7209         ADD_USHORT( Objects[wp->objnum].net_signature );
7210         ADD_USHORT( homing_signature );
7211         ADD_DATA( t_subsys );
7212         
7213         multi_io_send_to_all(data, packet_size);
7214 }
7215
7216 // process a homing weapon info change packet.  multiple_missiles parameter specifies is this
7217 // packet contains information for multiple weapons (like hornets).
7218 void process_homing_weapon_info( ubyte *data, header *hinfo )
7219 {
7220         int offset;
7221         ushort weapon_signature, homing_signature;
7222         char h_subsys;
7223         object *homing_object, *weapon_objp;
7224         weapon *wp;
7225
7226         offset = HEADER_LENGTH;
7227
7228         // get the data for the packet
7229         GET_USHORT( weapon_signature );
7230         GET_USHORT( homing_signature );
7231         GET_DATA( h_subsys );
7232         PACKET_SET_SIZE();
7233
7234         // deal with changing this weapons homing information
7235         weapon_objp = multi_get_network_object( weapon_signature );
7236         if ( weapon_objp == NULL ) {
7237                 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7238                 return;
7239         }
7240         SDL_assert( weapon_objp->type == OBJ_WEAPON );
7241         wp = &Weapons[weapon_objp->instance];
7242
7243         // be sure that we can find these weapons and 
7244         homing_object = multi_get_network_object( homing_signature );
7245         if ( homing_object == NULL ) {
7246                 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7247                 return;
7248         }
7249
7250         if ( homing_object->type == OBJ_WEAPON ) {
7251                 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7252         }
7253
7254         wp->homing_object = homing_object;
7255         wp->homing_subsys = NULL;
7256         wp->target_num = OBJ_INDEX(homing_object);
7257         wp->target_sig = homing_object->signature;
7258         if ( h_subsys != -1 ) {
7259                 SDL_assert( homing_object->type == OBJ_SHIP );
7260                 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7261         }
7262
7263         if ( homing_object->type == OBJ_SHIP ) {
7264                 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7265         }
7266 }
7267
7268 void send_emp_effect(ushort net_sig, float intensity, float time)
7269 {
7270         ubyte data[25];
7271         int packet_size;
7272
7273         SDL_assert(MULTIPLAYER_MASTER);
7274
7275         // build the packet and add the opcode
7276         BUILD_HEADER(EMP_EFFECT);
7277         ADD_USHORT(net_sig);
7278         ADD_FLOAT(intensity);
7279         ADD_FLOAT(time);
7280
7281         // send it to the player                
7282         multi_io_send_to_all(data, packet_size);
7283 }
7284
7285 void process_emp_effect(ubyte *data, header *hinfo)
7286 {
7287         float intensity, time;
7288         ushort net_sig;
7289         object *objp;
7290         int offset = HEADER_LENGTH;
7291
7292         // read in the EMP effect data
7293         GET_USHORT(net_sig);
7294         GET_FLOAT(intensity);
7295         GET_FLOAT(time);
7296         PACKET_SET_SIZE();
7297
7298         // try and find the object
7299         objp = multi_get_network_object(net_sig);
7300         if((objp != NULL) && (objp->type == OBJ_SHIP)){         
7301                 // if i'm not an observer and I have a valid ship, play the EMP effect
7302                 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7303                         emp_start_local(intensity, time);
7304                 }
7305
7306                 // start the effect for the ship itself
7307                 emp_start_ship(objp, intensity, time);
7308         }
7309 }
7310
7311 // tells whether or not reinforcements are available
7312 void send_reinforcement_avail( int rnum )
7313 {
7314         ubyte data[25];
7315         int packet_size;
7316
7317         BUILD_HEADER(REINFORCEMENT_AVAIL);
7318         ADD_INT( rnum );        
7319         multi_io_send_to_all_reliable(data, packet_size);
7320 }
7321
7322 void process_reinforcement_avail( ubyte *data, header *hinfo )
7323 {
7324         int offset;
7325         int rnum;
7326
7327         offset = HEADER_LENGTH;
7328         GET_INT( rnum );
7329         PACKET_SET_SIZE();
7330
7331         // sanity check for a valid reinforcement number
7332         if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7333                 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7334         }
7335 }
7336
7337 void send_change_iff_packet(ushort net_signature, int new_team)
7338 {
7339         ubyte data[MAX_PACKET_SIZE];
7340         int packet_size = 0;
7341
7342         if(Net_player == NULL){
7343                 return;
7344         }
7345         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7346                 return;
7347         }
7348
7349         // build the packet and add the data
7350         BUILD_HEADER(CHANGE_IFF);
7351         ADD_USHORT(net_signature);
7352         ADD_INT(new_team);
7353
7354         // send to all players  
7355         multi_io_send_to_all_reliable(data, packet_size);
7356 }
7357
7358 void process_change_iff_packet( ubyte *data, header *hinfo)
7359 {
7360         int offset = HEADER_LENGTH;
7361         ushort net_signature;
7362         int new_team;   
7363         object *objp;
7364
7365         // get the data
7366         GET_USHORT(net_signature);
7367         GET_INT(new_team);
7368         PACKET_SET_SIZE();
7369
7370         // lookup the object
7371         objp = multi_get_network_object(net_signature);
7372         if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7373                 Ships[objp->instance].team = new_team;
7374         }       
7375 }
7376
7377 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7378 {
7379         int packet_size, objnum;
7380         ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7381         object *objp;   
7382         int np_index;
7383         net_player *ignore = NULL;
7384
7385         // sanity checking for now
7386         SDL_assert ( banks_fired <= 3 );
7387
7388         // get an object pointer for this ship.
7389         objnum = shipp->objnum;
7390         objp = &Objects[objnum];
7391
7392         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7393         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7394                 return;
7395         }
7396
7397         // just in case nothing got fired
7398         if(banks_fired <= 0){
7399                 return;
7400         }
7401
7402         // ubanks_fired = (ubyte)banks_fired;
7403         // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7404         // SDL_assert( current_bank <= 3 );
7405
7406         // insert the current primary bank into this byte
7407         // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7408
7409         // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7410         // if ( shipp->flags & SF_PRIMARY_LINKED ){
7411                 // ubanks_fired |= (1<<7);
7412         // }    
7413
7414         // determine if its a player ship and don't send to him if we're in "client firing" mode
7415         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7416         if(MULTIPLAYER_MASTER){
7417                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7418                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7419                         ignore = &Net_players[np_index];
7420                 }
7421         }
7422
7423         // build up the standard weapon fired packet.  This packet will get sent to all players if an AI
7424         // ship fired the primary weapons.  If a player fired the weaspon, then this packet will get sent
7425         // to every player but the guy who actullly fired the weapon.  This method is used to help keep client
7426         // and server in sync w.r.t. weapon energy for player ship
7427         BUILD_HEADER( PRIMARY_FIRED_NEW );
7428         ADD_USHORT(objp->net_signature);
7429         // ADD_DATA(ubanks_fired);
7430
7431         // if I'm a server, broadcast to all players
7432         if(MULTIPLAYER_MASTER){         
7433                 multi_io_send_to_all(data, packet_size, ignore);
7434
7435                 // TEST CODE
7436                 multi_rate_add(1, "wfi", packet_size);
7437         }
7438         // otherwise just send to the server
7439         else {
7440                 multi_io_send(Net_player, data, packet_size);           
7441         }
7442 }
7443
7444 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7445 {
7446         int offset; // linked;  
7447         // ubyte banks_fired, current_bank;
7448         object* objp;   
7449 //      ship *shipp;
7450         ushort shooter_sig;     
7451
7452         // read all packet info
7453         offset = HEADER_LENGTH;
7454         GET_USHORT(shooter_sig);
7455         // GET_DATA(banks_fired);
7456         PACKET_SET_SIZE();
7457
7458         // find the object this fired packet is operating on
7459         objp = multi_get_network_object( shooter_sig );
7460         if ( objp == NULL ) {
7461                 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7462                 return;
7463         }
7464         // if this object is not actually a valid ship, don't do anything
7465         if(objp->type != OBJ_SHIP){
7466                 return;
7467         }
7468         if(objp->instance < 0){
7469                 return;
7470         }
7471 //      shipp = &Ships[objp->instance];
7472         
7473         // get the link status of the primary banks
7474         // linked = 0;
7475         // if ( banks_fired & (1<<7) ) {
7476                 // linked = 1;
7477                 // banks_fired ^= (1<<7);
7478         // }
7479
7480         // get the current primary bank
7481         // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7482         // current_bank &= 0x3;
7483         // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7484         // shipp->weapons.current_primary_bank = current_bank;
7485
7486         // strip off all remaining bits and just keep which banks were actually fired.
7487         // banks_fired &= 0x3;
7488         
7489         // set the link status of the ship if not the player.  If it is the player, we will do sanity checking
7490         // only (for now).      
7491         // if ( !linked ){
7492 //              shipp->flags &= ~SF_PRIMARY_LINKED;
7493         // } else {
7494                 // shipp->flags |= SF_PRIMARY_LINKED;
7495         // }
7496
7497         // if we're in client firing mode, ignore ones for myself       
7498         if((Player_obj != NULL) && (Player_obj == objp)){               
7499                 return;
7500         }
7501                 
7502         ship_fire_primary( objp, 0, 1 );
7503 }
7504
7505 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7506 {
7507         ubyte data[MAX_PACKET_SIZE];
7508         int packet_size;
7509         int np_index;   
7510         net_player *ignore = NULL;
7511
7512         // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7513         if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7514                 return;
7515         }
7516
7517         SDL_assert ( cmeasure_count < UCHAR_MAX );
7518         BUILD_HEADER(COUNTERMEASURE_NEW);
7519         ADD_USHORT( objp->net_signature );
7520         ADD_INT( rand_val );
7521
7522         nprintf(("Network","Sending NEW countermeasure packet!\n"));
7523
7524         // determine if its a player ship and don't send to him if we're in "client firing" mode
7525         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7526         if(MULTIPLAYER_MASTER){
7527                 np_index = multi_find_player_by_net_signature(objp->net_signature);
7528                 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7529                         ignore = &Net_players[np_index];
7530                 }
7531         }
7532         
7533         // if I'm the server, send to all players
7534         if(MULTIPLAYER_MASTER){                 
7535                 multi_io_send_to_all(data, packet_size, ignore);
7536         } 
7537         // otherwise send to the server
7538         else {
7539                 multi_io_send(Net_player, data, packet_size);
7540         }
7541 }
7542
7543 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7544 {
7545         int offset;
7546         ushort signature;
7547         int rand_val;
7548         object *objp;   
7549
7550         offset = HEADER_LENGTH;
7551         GET_USHORT( signature );
7552         GET_INT( rand_val );
7553         PACKET_SET_SIZE();
7554
7555         objp = multi_get_network_object( signature );
7556         if ( objp == NULL ) {
7557                 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7558                 return;
7559         }
7560         if(objp->type != OBJ_SHIP){
7561                 return;
7562         }       
7563
7564         // if we're in client firing mode, ignore ones for myself
7565         // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){         
7566         if((Player_obj != NULL) && (Player_obj == objp)){               
7567                 return;
7568         }
7569                 
7570         // make it so ship can fire right away!
7571         Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7572         if ( objp == Player_obj ){              
7573                 nprintf(("network", "firing countermeasure from my ship\n"));
7574         }
7575         ship_launch_countermeasure( objp, rand_val );                   
7576 }
7577
7578 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7579 {
7580         ubyte data[MAX_PACKET_SIZE];
7581         int packet_size = 0;    
7582         ubyte u_beam_info;
7583         char subsys_index;
7584         beam_info b_info;
7585
7586         // only the server should ever be doing this
7587         SDL_assert(MULTIPLAYER_MASTER);
7588
7589         // setup outgoing data
7590         SDL_assert(shooter != NULL);
7591         SDL_assert(turret != NULL);
7592         SDL_assert(target != NULL);
7593         SDL_assert(override != NULL);
7594         if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7595                 return;
7596         }
7597         u_beam_info = (ubyte)beam_info_index;
7598         subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7599         SDL_assert(subsys_index >= 0);
7600         if(subsys_index < 0){
7601                 return;
7602         }
7603
7604         // swap the beam_info override info into little endian byte order
7605         b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7606         b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7607         b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7608          
7609         b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7610         b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7611         b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7612          
7613         b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7614         b_info.shot_count = override->shot_count;
7615          
7616         for (int i = 0; i < b_info.shot_count; i++) {
7617                 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7618         }
7619
7620         // build the header
7621         BUILD_HEADER(BEAM_FIRED);
7622         ADD_USHORT(shooter->net_signature);
7623         ADD_DATA(subsys_index);
7624         ADD_USHORT(target->net_signature);
7625         ADD_DATA(u_beam_info);
7626         ADD_DATA(b_info);  // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7627
7628         // send to all clients  
7629         multi_io_send_to_all_reliable(data, packet_size);
7630 }
7631
7632 void process_beam_fired_packet(ubyte *data, header *hinfo)
7633 {
7634         int i,offset;
7635         ushort shooter_sig, target_sig;
7636         char subsys_index;
7637         ubyte u_beam_info;
7638         beam_info b_info;
7639         beam_fire_info fire_info;
7640
7641         // only clients should ever get this
7642         SDL_assert(MULTIPLAYER_CLIENT);
7643
7644         // read in packet data
7645         offset = HEADER_LENGTH;
7646         GET_USHORT(shooter_sig);
7647         GET_DATA(subsys_index);
7648         GET_USHORT(target_sig);
7649         GET_DATA(u_beam_info);
7650         GET_DATA(b_info);
7651
7652         PACKET_SET_SIZE();
7653
7654         // swap the beam_info override info into native byte order
7655         b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7656         b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7657         b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7658         b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7659         b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7660         b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7661         b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7662
7663         for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7664                 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7665         }
7666
7667         // lookup all relevant data
7668         fire_info.beam_info_index = (int)u_beam_info;
7669         fire_info.shooter = NULL;
7670         fire_info.target = NULL;
7671         fire_info.turret = NULL;
7672         fire_info.target_subsys = NULL;
7673         fire_info.beam_info_override = NULL;            
7674         fire_info.shooter = multi_get_network_object(shooter_sig);
7675         fire_info.target = multi_get_network_object(target_sig);
7676         fire_info.beam_info_override = &b_info;
7677         fire_info.accuracy = 1.0f;
7678         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)){
7679                 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7680                 return;
7681         }
7682         fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7683         if(fire_info.turret == NULL){
7684                 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7685                 return;
7686         }
7687
7688         // fire da beam
7689         beam_fire(&fire_info);
7690 }
7691
7692 void send_sw_query_packet(ubyte code, char *txt)
7693 {
7694         ubyte data[MAX_PACKET_SIZE];
7695         int packet_size = 0;
7696
7697         // build the packet and add the code
7698         BUILD_HEADER(SW_STD_QUERY);
7699         ADD_DATA(code);
7700         if((code == SW_STD_START) || (code == SW_STD_BAD)){             
7701                 ADD_STRING(txt);
7702         }
7703
7704         // if I'm the host, send to standalone
7705         if(MULTIPLAYER_HOST){
7706                 SDL_assert(!MULTIPLAYER_MASTER);
7707                 SDL_assert(code == SW_STD_START);               
7708                 multi_io_send_reliable(Net_player, data, packet_size);
7709         }
7710         // otherwise standalone sends back to host
7711         else {
7712                 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7713                 SDL_assert(code != SW_STD_START);
7714                 SDL_assert(Netgame.host != NULL);
7715                 if(Netgame.host != NULL){                       
7716                         multi_io_send_reliable(Netgame.host, data, packet_size);
7717                 }
7718         }
7719 }
7720
7721 void process_sw_query_packet(ubyte *data, header *hinfo)
7722 {       
7723 }
7724
7725 void send_event_update_packet(int event)
7726 {
7727         ubyte data[MAX_PACKET_SIZE];
7728         ushort u_event = (ushort)event;
7729         int packet_size = 0;
7730
7731         // build the header and add the event
7732         BUILD_HEADER(EVENT_UPDATE);
7733         ADD_USHORT(u_event);
7734         ADD_INT(Mission_events[event].flags);
7735         ADD_INT(Mission_events[event].formula);
7736         ADD_INT(Mission_events[event].result);
7737         ADD_INT(Mission_events[event].count);
7738
7739         // send to all players  
7740         multi_io_send_to_all_reliable(data, packet_size);
7741 }
7742
7743 void process_event_update_packet(ubyte *data, header *hinfo)
7744 {
7745         int offset = HEADER_LENGTH;
7746         int store_flags;
7747         ushort u_event;
7748         
7749         // get the data
7750         GET_USHORT(u_event);
7751         store_flags = Mission_events[u_event].flags;
7752         GET_INT(Mission_events[u_event].flags);
7753         GET_INT(Mission_events[u_event].formula);
7754         GET_INT(Mission_events[u_event].result);
7755         GET_INT(Mission_events[u_event].count);
7756         PACKET_SET_SIZE();
7757
7758         // went from non directive special to directive special
7759         if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7760                 mission_event_set_directive_special(u_event);
7761         }
7762         // if we went directive special to non directive special
7763         else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7764                 mission_event_unset_directive_special(u_event);
7765         }       
7766 }
7767
7768 // weapon detonate packet
7769 void send_weapon_detonate_packet(object *objp)
7770 {
7771         ubyte data[MAX_PACKET_SIZE];
7772         int packet_size = 0;
7773
7774         // sanity checks
7775         SDL_assert(MULTIPLAYER_MASTER);
7776         if(!MULTIPLAYER_MASTER){
7777                 return;
7778         }
7779         SDL_assert(objp != NULL);
7780         if(objp == NULL){
7781                 return;
7782         }
7783
7784         // build the header and add the data
7785         BUILD_HEADER(WEAPON_DET);
7786         ADD_USHORT(objp->net_signature);
7787
7788         // send to all players
7789         multi_io_send_to_all(data, packet_size);
7790 }
7791
7792 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7793 {
7794         ushort net_sig;
7795         int offset = HEADER_LENGTH;
7796         object *objp = NULL;
7797
7798         // get the weapon signature
7799         GET_USHORT(net_sig);
7800         PACKET_SET_SIZE();
7801
7802         // lookup the weapon
7803         objp = multi_get_network_object(net_sig);
7804         if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7805                 weapon_detonate(objp);
7806         }
7807 }       
7808
7809 // flak fired packet
7810 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7811 {
7812         int packet_size;
7813         ushort pnet_signature;
7814         ubyte data[MAX_PACKET_SIZE], cindex;
7815         object *objp;   
7816         ship_subsys *ssp;
7817         short val;
7818
7819         // sanity
7820         if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7821                 return;
7822         }
7823
7824         // local setup -- be sure we are actually passing a weapon!!!!
7825         objp = &Objects[weapon_objnum];
7826         SDL_assert ( objp->type == OBJ_WEAPON );        
7827         pnet_signature = Objects[ship_objnum].net_signature;
7828
7829         SDL_assert( subsys_index < UCHAR_MAX );
7830         cindex = (ubyte)subsys_index;
7831
7832         ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7833         if(ssp == NULL){
7834                 return;
7835         }
7836
7837         // build the fire turret packet.  
7838         BUILD_HEADER(FLAK_FIRED);       
7839         packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7840         ADD_USHORT( pnet_signature );           
7841         ADD_DATA( cindex );
7842         val = (short)ssp->submodel_info_1.angs.h;
7843         ADD_SHORT( val );
7844         val = (short)ssp->submodel_info_2.angs.p;
7845         ADD_SHORT( val );       
7846         ADD_FLOAT( flak_range );
7847         
7848         multi_io_send_to_all(data, packet_size);
7849
7850         multi_rate_add(1, "flk", packet_size);
7851 }
7852
7853 void process_flak_fired_packet(ubyte *data, header *hinfo)
7854 {
7855         int offset, weapon_objnum, wid;
7856         ushort pnet_signature;
7857         vector pos, dir;
7858         matrix orient;
7859         vector o_fvec;
7860         ubyte turret_index;
7861         object *objp;
7862         ship_subsys *ssp;       
7863         ship *shipp;
7864         short pitch, heading;
7865         float flak_range;
7866
7867         // get the data for the turret fired packet
7868         offset = HEADER_LENGTH;         
7869         offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7870         GET_USHORT( pnet_signature );
7871         GET_DATA( turret_index );
7872         GET_SHORT( heading );
7873         GET_SHORT( pitch );     
7874         GET_FLOAT( flak_range );
7875         PACKET_SET_SIZE();                              // move our counter forward the number of bytes we have read
7876
7877         // find the object
7878         objp = multi_get_network_object( pnet_signature );
7879         if ( objp == NULL ) {
7880                 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7881                 return;
7882         }
7883
7884         // if this isn't a ship, do nothing
7885         if ( objp->type != OBJ_SHIP ){
7886                 return;
7887         }
7888
7889         // make an orientation matrix from the o_fvec
7890         vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7891
7892         // find this turret, and set the position of the turret that just fired to be where it fired.  Quite a
7893         // hack, but should be suitable.
7894         shipp = &Ships[objp->instance];
7895         ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7896         if(ssp == NULL){
7897                 return;
7898         }
7899         wid = ssp->system_info->turret_weapon_type;
7900         if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7901                 return;
7902         }
7903
7904         // bash the position and orientation of the turret
7905         ssp->submodel_info_1.angs.h = (float)heading;
7906         ssp->submodel_info_2.angs.p = (float)pitch;
7907
7908         // get the world position of the weapon
7909         ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7910
7911         // create the weapon object     
7912         weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7913         if (weapon_objnum != -1) {
7914                 if ( Weapon_info[wid].launch_snd != -1 ) {
7915                         snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7916                 }
7917
7918                 // create a muzzle flash from a flak gun based upon firing position and weapon type
7919                 flak_muzzle_flash(&pos, &dir, wid);
7920
7921                 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7922                 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7923         }
7924 }
7925
7926 #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);
7927 #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);
7928
7929 // player pain packet
7930 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7931 {
7932         ubyte data[MAX_PACKET_SIZE];
7933         ubyte windex;
7934         ushort udamage;
7935         int packet_size = 0;
7936
7937         SDL_assert(MULTIPLAYER_MASTER);
7938         if(!MULTIPLAYER_MASTER){
7939                 return;
7940         }
7941         SDL_assert(pl != NULL);
7942         if(pl == NULL){
7943                 return;
7944         }
7945
7946         // build the packet and add the code
7947         BUILD_HEADER(NETPLAYER_PAIN);
7948         windex = (ubyte)weapon_info_index;
7949         ADD_DATA(windex);
7950         udamage = (ushort)damage;
7951         ADD_USHORT(udamage);
7952         //ADD_DATA((*force));
7953         add_vector_data( data, &packet_size, *force );
7954         //ADD_DATA((*hitpos));
7955         add_vector_data( data, &packet_size, *hitpos );
7956
7957         // send to the player
7958         multi_io_send(pl, data, packet_size);
7959
7960         multi_rate_add(1, "pai", packet_size);
7961 }       
7962
7963 void process_player_pain_packet(ubyte *data, header *hinfo)
7964 {
7965         int offset;
7966         ubyte windex;
7967         ushort udamage;
7968         vector force = ZERO_VECTOR;
7969         vector local_hit_pos = ZERO_VECTOR;
7970         weapon_info *wip;
7971
7972         // get the data for the pain packet
7973         offset = HEADER_LENGTH;         
7974         GET_DATA(windex);
7975         GET_USHORT(udamage);
7976         //GET_DATA(force);
7977         get_vector_data( data, &offset, force );
7978         //GET_DATA(local_hit_pos);
7979         get_vector_data( data, &offset, local_hit_pos );
7980         PACKET_SET_SIZE();
7981
7982         mprintf(("PAIN!\n"));
7983
7984         // get weapon info pointer
7985         //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER));        // always true
7986         if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7987                 return;
7988         }
7989         wip = &Weapon_info[windex];
7990
7991         // play the weapon hit sound
7992         SDL_assert(Player_obj != NULL);
7993         if(Player_obj == NULL){
7994                 return;
7995         }
7996         weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
7997
7998         // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
7999         ship_hit_pain((float)udamage);
8000
8001         // apply the whack      
8002         ship_apply_whack(&force, &local_hit_pos, Player_obj);   
8003 }
8004
8005 // lightning packet
8006 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8007 {
8008         ubyte data[MAX_PACKET_SIZE];
8009         char val;
8010         int packet_size = 0;
8011
8012         // build the header and add the data
8013         BUILD_HEADER(LIGHTNING_PACKET);
8014         val = (char)bolt_type;
8015         ADD_DATA(val);
8016         //ADD_DATA((*start));
8017         add_vector_data( data, &packet_size, *start );
8018         //ADD_DATA((*strike));
8019         add_vector_data( data, &packet_size, *strike );
8020
8021         // send to everyone unreliable for now
8022         multi_io_send_to_all(data, packet_size);
8023 }
8024
8025 void process_lightning_packet(ubyte *data, header *hinfo)
8026 {
8027         int offset;
8028         char bolt_type;
8029         vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8030
8031         // read the data
8032         offset = HEADER_LENGTH;
8033         GET_DATA(bolt_type);
8034 //      GET_DATA(start);
8035         get_vector_data(data, &offset, start);
8036 //      GET_DATA(strike);
8037         get_vector_data(data, &offset, strike);
8038         PACKET_SET_SIZE();
8039
8040         // invalid bolt?
8041         if(bolt_type < 0){
8042                 return;
8043         }
8044
8045         // fire it up
8046         nebl_bolt(bolt_type, &start, &strike);
8047 }
8048
8049 void send_bytes_recvd_packet(net_player *pl)
8050 {
8051         // only clients should ever be doing this
8052         if(pl == NULL){
8053                 return;
8054         }       
8055
8056         ubyte data[MAX_PACKET_SIZE];
8057         int packet_size = 0;
8058         BUILD_HEADER(BYTES_SENT);
8059         ADD_INT(pl->cl_bytes_recvd);
8060
8061         // send to the server
8062         multi_io_send_reliable(pl, data, packet_size);
8063 }
8064
8065 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8066 {
8067         int bytes;
8068         int pid;
8069         net_player *pl = NULL;
8070         int offset = HEADER_LENGTH;
8071         
8072         GET_INT(bytes);
8073         PACKET_SET_SIZE();
8074
8075         // not server?
8076         if(Net_player == NULL){
8077                 return;
8078         }
8079         if(!MULTIPLAYER_MASTER){
8080                 return;
8081         }
8082
8083         // make sure we know what player sent this
8084         pid = find_player_id(hinfo->id);
8085         if((pid < 0) || (pid >= MAX_PLAYERS)){
8086                 return;
8087         }
8088         pl = &Net_players[pid];
8089
8090         // compute his pl
8091         pl->cl_bytes_recvd = bytes;
8092         if(bytes < 0){
8093                 return;
8094         }
8095         pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8096
8097         // reset bytes sent
8098         pl->sv_bytes_sent = 0;
8099 }
8100
8101 // host transfer
8102 void send_host_captain_change_packet(short player_id, int captain_change)
8103 {
8104         ubyte data[MAX_PACKET_SIZE];
8105         int packet_size = 0;
8106
8107         // build the packet
8108         BUILD_HEADER(TRANSFER_HOST);
8109         ADD_SHORT(player_id);
8110         ADD_INT(captain_change);
8111
8112         // send to all
8113         multi_io_send_to_all_reliable(data, packet_size);
8114 }
8115
8116 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8117 {
8118         int offset = HEADER_LENGTH;
8119         int idx, found_player, captain_change;
8120         short player_id;
8121
8122         // get the player id
8123         GET_SHORT(player_id);
8124         GET_INT(captain_change);
8125         PACKET_SET_SIZE();
8126
8127         // captain change
8128         if(captain_change){
8129                 // flag the new guy             
8130                 for(idx=0; idx<MAX_PLAYERS; idx++){
8131                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8132                                 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8133                                 break;
8134                         }
8135                 }
8136         } else {
8137                 // unflag all old players
8138                 for(idx=0; idx<MAX_PLAYERS; idx++){
8139                         Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8140                 }
8141
8142                 // flag the new guy
8143                 found_player = 0;
8144                 for(idx=0; idx<MAX_PLAYERS; idx++){
8145                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8146                                 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8147
8148                                 // spew to the HUD config
8149                                 if(Net_players[idx].player != NULL){
8150                                         HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8151                                 }
8152
8153                                 found_player = 1;
8154                                 break;
8155                         }
8156                 }
8157
8158                 // doh
8159                 if(!found_player){
8160                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8161                 }
8162         }       
8163 }
8164
8165 void send_self_destruct_packet()
8166 {
8167         ubyte data[MAX_PACKET_SIZE];
8168         int packet_size = 0;
8169
8170         // bogus
8171         if(Net_player == NULL){
8172                 return;
8173         }
8174
8175         // if i'm the server, I shouldn't be here
8176         SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8177         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8178                 return;
8179         }
8180         
8181         // only if this is valid
8182         if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8183                 return;
8184         }
8185
8186         // bogus object?
8187         if((Player_ship == NULL) || (Player_obj == NULL)){
8188                 return;
8189         }
8190
8191         // self destruct
8192         BUILD_HEADER(SELF_DESTRUCT);
8193         ADD_USHORT(Player_obj->net_signature);
8194
8195         // send to the server
8196         multi_io_send_reliable(Net_player, data, packet_size);
8197 }
8198
8199 void process_self_destruct_packet(ubyte *data, header *hinfo)
8200 {
8201         int offset = HEADER_LENGTH;
8202         ushort net_sig;
8203         int np_index;
8204
8205         // get the net signature
8206         GET_USHORT(net_sig);
8207         PACKET_SET_SIZE();
8208
8209         // get the player
8210         np_index = find_player_id(hinfo->id);
8211         if(np_index < 0){
8212                 return;
8213         }
8214         if(MULTI_OBSERVER(Net_players[np_index])){
8215                 return;
8216         }
8217         if(Net_players[np_index].player == NULL){
8218                 return;
8219         }
8220         if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8221                 return;
8222         }
8223         if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8224                 return;
8225         }
8226         if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8227                 return;
8228         }
8229         if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8230                 return;
8231         }
8232
8233         // do eet
8234         ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);
8235 }