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