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