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