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