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