2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Network/MultiMsgs.cpp $
15 * C file that holds functions for the building and processing of multiplayer packets
18 * Revision 1.7 2004/06/11 01:49:45 tigital
19 * byte-swapping changes for bigendian systems
21 * Revision 1.6 2003/08/03 16:10:29 taylor
22 * cleanup; compile warning fixes
24 * Revision 1.5 2002/06/17 06:33:10 relnev
25 * ryan's struct patch for gcc 2.95
27 * Revision 1.4 2002/06/09 04:41:24 relnev
28 * added copyright header
30 * Revision 1.3 2002/05/26 20:49:54 theoddone33
33 * Revision 1.2 2002/05/07 03:16:47 theoddone33
34 * The Great Newline Fix
36 * Revision 1.1.1.1 2002/05/03 03:28:10 root
40 * 83 9/14/99 2:21p Dave
41 * Fixed observer mode joining and ingame stuff.
43 * 82 9/14/99 3:26a Dave
44 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
45 * respawn-too-early problem. Made a few crash points safe.
47 * 81 9/13/99 4:52p Dave
50 * 80 9/08/99 10:01p Dave
51 * Make sure game won't run in a drive's root directory. Make sure
52 * standalone routes suqad war messages properly to the host.
54 * 79 8/28/99 4:54p Dave
55 * Fixed directives display for multiplayer clients for wings with
56 * multiple waves. Fixed hud threat indicator rendering color.
58 * 78 8/27/99 12:32a Dave
59 * Allow the user to specify a local port through the launcher.
61 * 77 8/26/99 8:51p Dave
62 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
64 * 76 8/25/99 4:38p Dave
65 * Updated PXO stuff. Make squad war report stuff much more nicely.
67 * 75 8/24/99 1:50a Dave
68 * Fixed client-side afterburner stuttering. Added checkbox for no version
69 * checking on PXO join. Made button info passing more friendly between
72 * 74 8/22/99 5:53p Dave
73 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
74 * instead of ship designations for multiplayer players.
76 * 73 8/22/99 1:55p Dave
77 * Cleaned up host/team-captain leaving code.
79 * 72 8/22/99 1:19p Dave
80 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
81 * which d3d cards are detected.
83 * 71 8/19/99 10:59a Dave
84 * Packet loss detection.
86 * 70 8/17/99 1:12p Dave
87 * Send TvT update when a client has finished joining so he stays nice and
90 * 69 8/16/99 4:05p Dave
91 * Big honking checkin.
93 * 68 8/11/99 5:54p Dave
94 * Fixed collision problem. Fixed standalone ghost problem.
96 * 67 8/06/99 9:46p Dave
97 * Hopefully final changes for the demo.
99 * 66 8/05/99 2:06a Dave
102 * 65 7/30/99 7:01p Dave
103 * Dogfight escort gauge. Fixed up laser rendering in Glide.
105 * 64 7/29/99 5:41p Jefff
106 * Sound hooks for cmeasure success
108 * 63 7/28/99 5:34p Dave
109 * Nailed the missing stats bug to the wall. Problem was optimized build
110 * and using GET_DATA() with array elements. BLECH.
112 * 62 7/26/99 5:50p Dave
113 * Revised ingame join. Better? We'll see....
115 * 61 7/24/99 1:54p Dave
116 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
119 * 60 7/22/99 7:17p Dave
120 * Fixed excessive whacks in multiplayer.
122 * 59 7/08/99 10:53a Dave
123 * New multiplayer interpolation scheme. Not 100% done yet, but still
124 * better than the old way.
126 * 58 7/03/99 5:50p Dave
127 * Make rotated bitmaps draw properly in padlock views.
129 * 57 7/03/99 4:08p Dave
130 * Fixed wss_slots size issues. Fixed potentially nasty bug in low level
133 * 56 6/21/99 7:24p Dave
134 * netplayer pain packet. Added type E unmoving beams.
136 * 55 6/18/99 5:16p Dave
137 * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
138 * dialog to PXO screen.
140 * 54 6/16/99 4:06p Dave
141 * New pilot info popup. Added new draw-bitmap-as-poly function.
143 * 53 6/16/99 10:20a Dave
144 * Added send-message-list sexpression.
146 * 52 6/04/99 3:52p Anoop
147 * Removed bogus assert.
149 * 51 6/01/99 8:35p Dave
150 * Finished lockarm weapons. Added proper supercap weapons/damage. Added
151 * awacs-set-radius sexpression.
153 * 50 5/21/99 5:03p Andsager
154 * Add code to display engine wash death. Modify ship_kill_packet
156 * 49 5/18/99 1:30p Dave
157 * Added muzzle flash table stuff.
159 * 48 5/14/99 1:59p Andsager
160 * Multiplayer message for subsystem cargo revealed.
162 * 47 5/14/99 12:15p Andsager
163 * Add vaporized to kill packet
165 * 46 5/03/99 8:32p Dave
166 * New version of multi host options screen.
168 * 45 4/30/99 12:18p Dave
169 * Several minor bug fixes.
171 * 44 4/29/99 2:29p Dave
172 * Made flak work much better in multiplayer.
174 * 43 4/28/99 11:13p Dave
175 * Temporary checkin of artillery code.
177 * 42 4/16/99 5:54p Dave
178 * Support for on/off style "stream" weapons. Real early support for
179 * target-painting lasers.
181 * 41 4/12/99 2:22p Dave
182 * More checks for dogfight stats.
184 * 40 4/09/99 2:21p Dave
185 * Multiplayer beta stuff. CD checking.
187 * 39 4/02/99 9:55a Dave
188 * Added a few more options in the weapons.tbl for beam weapons. Attempt
189 * at putting "pain" packets into multiplayer.
191 * 38 4/01/99 3:41p Anoop
192 * Removed bogus Int3().
194 * 37 3/19/99 9:51a Dave
195 * Checkin to repair massive source safe crash. Also added support for
196 * pof-style nebulae, and some new weapons code.
198 * 38 3/12/99 2:32p Anoop
199 * Removed bogus asserts.
201 * 37 3/11/99 11:41a Neilk
202 * Don't do multi_io_* operations in single-player
204 * 36 3/10/99 6:50p Dave
205 * Changed the way we buffer packets for all clients. Optimized turret
206 * fired packets. Did some weapon firing optimizations.
208 * 35 3/09/99 6:24p Dave
209 * More work on object update revamping. Identified several sources of
210 * unnecessary bandwidth.
212 * 34 3/08/99 7:03p Dave
213 * First run of new object update system. Looks very promising.
215 * 33 3/04/99 6:09p Dave
216 * Added in sexpressions for firing beams and checking for if a ship is
219 * 32 3/01/99 10:00a Dave
220 * Fxied several dogfight related stats bugs.
222 * 31 2/24/99 2:25p Dave
223 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
224 * bug for dogfight more.
226 * 30 2/23/99 2:29p Dave
227 * First run of oldschool dogfight mode.
229 * 29 2/21/99 6:01p Dave
230 * Fixed standalone WSS packets.
232 * 28 2/21/99 1:48p Dave
233 * Some code for monitoring datarate for multiplayer in detail.
235 * 27 2/17/99 2:11p Dave
236 * First full run of squad war. All freespace and tracker side stuff
239 * 26 2/12/99 6:16p Dave
240 * Pre-mission Squad War code is 95% done.
242 * 25 2/11/99 3:08p Dave
243 * PXO refresh button. Very preliminary squad war support.
245 * 24 1/29/99 5:07p Dave
246 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
249 * 23 1/27/99 9:56a Dave
250 * Temporary checkin of beam weapons for Dan to make cool sounds.
252 * 22 1/26/99 6:33p Anoop
253 * Fixed multiplayer slot switching problem (be sure to remember that
254 * hinfo->id is player id# _not_ player index #)
256 * 21 1/24/99 11:37p Dave
257 * First full rev of beam weapons. Very customizable. Removed some bogus
258 * Int3()'s in low level net code.
260 * 20 1/15/99 4:37p Dave
261 * Potential fix for weapon pair problem.
263 * 19 1/14/99 6:06p Dave
264 * 100% full squad logo support for single player and multiplayer.
266 * 18 1/14/99 12:48a Dave
267 * Todo list bug fixes. Made a pass at putting briefing icons back into
268 * FRED. Sort of works :(
270 * 17 1/12/99 5:45p Dave
271 * Moved weapon pipeline in multiplayer to almost exclusively client side.
272 * Very good results. Bandwidth goes down, playability goes up for crappy
273 * connections. Fixed object update problem for ship subsystems.
275 * 16 1/08/99 4:56p Anoop
276 * Fixed a problem with wss request packets.
278 * 15 12/18/98 12:24p Markm
279 * Fixed a dumb bug where player image_filenames were not being passed
280 * properly in new players packet.
282 * 14 12/14/98 12:13p Dave
283 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
286 * 13 11/30/98 1:07p Dave
287 * 16 bit conversion, first run.
289 * 12 11/20/98 4:08p Dave
290 * Fixed flak effect in multiplayer.
292 * 11 11/19/98 4:19p Dave
293 * Put IPX sockets back in psnet. Consolidated all multiplayer config
296 * 10 11/19/98 8:04a Dave
297 * Full support for D3-style reliable sockets. Revamped packet lag/loss
298 * system, made it receiver side and at the lowest possible level.
300 * 9 11/17/98 11:12a Dave
301 * Removed player identification by address. Now assign explicit id #'s.
303 * 8 11/12/98 11:50a Dave
304 * Multiplayer clients set flak range to be very long.
306 * 7 11/12/98 12:13a Dave
307 * Tidied code up for multiplayer test. Put in network support for flak
310 * 6 11/05/98 5:55p Dave
311 * Big pass at reducing #includes
313 * 5 10/20/98 1:39p Andsager
314 * Make so sparks follow animated ship submodels. Modify
315 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
316 * submodel_num. Add submodel_num to multiplayer hit packet.
318 * 4 10/13/98 9:29a Dave
319 * Started neatening up freespace.h. Many variables renamed and
320 * reorganized. Added AlphaColors.[h,cpp]
322 * 3 10/07/98 6:27p Dave
323 * Globalized mission and campaign file extensions. Removed Silent Threat
324 * special code. Moved \cache \players and \multidata into the \data
327 * 2 10/07/98 10:53a Dave
330 * 1 10/07/98 10:50a Dave
332 * 506 10/02/98 3:22p Allender
333 * fix up the -connect option and fix the -port option
335 * 505 10/02/98 11:45a Dave
336 * Fixed stupid chat message bug.
338 * 504 9/29/98 1:33p Dave
339 * Remove standalone only conditional compiles for pre 1.04 stuff.
341 * 503 9/28/98 1:54p Dave
342 * Make sure French and German don't xfer builtin files they don't have
345 * 502 9/20/98 7:19p Dave
346 * Added CHANGE_IFF packet.
348 * 501 9/17/98 3:08p Dave
349 * PXO to non-pxo game warning popup. Player icon stuff in create and join
350 * game screens. Upped server count refresh time in PXO to 35 secs (from
359 #include <io.h> // for findfirst/findnext, etc
362 #include "multimsgs.h"
363 #include "multiutil.h"
366 #include "multiteamselect.h"
367 #include "linklist.h"
368 #include "gamesequence.h"
369 #include "hudmessage.h"
370 #include "hudsquadmsg.h"
371 #include "freespace.h"
375 #include "missiongoals.h"
376 #include "missionparse.h"
377 #include "missionlog.h"
378 #include "missionmessage.h"
379 #include "missionbrief.h"
381 #include "cmeasure.h"
382 #include "model.h" // for some limits
383 #include "afterburner.h"
384 #include "stand_gui.h"
385 #include "multi_xfer.h"
391 #include "managepilot.h"
392 #include "hudsquadmsg.h"
394 #include "missionweaponchoice.h"
395 #include "missionshipchoice.h"
396 #include "fireballs.h"
399 #include "multi_ingame.h"
400 #include "multiteamselect.h"
402 #include "multi_campaign.h"
403 #include "multi_team.h"
404 #include "multi_respawn.h"
405 #include "multi_observer.h"
406 #include "multi_voice.h"
407 #include "asteroid.h"
408 #include "multi_pmsg.h"
409 #include "multi_data.h"
410 #include "multi_options.h"
411 #include "objcollide.h"
412 #include "hudreticle.h"
413 #include "multi_pause.h"
414 #include "multi_endgame.h"
415 #include "missiondebrief.h"
416 #include "multi_obj.h"
417 #include "multi_log.h"
419 #include "multi_kick.h"
423 #include "multi_rate.h"
424 #include "neblightning.h"
425 #include "hudescort.h"
427 // #define _MULTI_SUPER_WACKY_COMPRESSION
429 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
431 #define MAX_CODE ( ( 1 << BITS ) - 1 )
432 #define TABLE_SIZE 35023L
433 #define END_OF_STREAM 256
434 #define BUMP_CODE 257
435 #define FLUSH_CODE 258
436 #define FIRST_CODE 259
445 static DICTIONARY dict[TABLE_SIZE];
446 static char decode_stack[TABLE_SIZE];
447 static uint next_code;
448 static int current_code_bits;
449 static uint next_bump_code;
451 typedef struct BitBuf {
457 void output_bits( BitBuf *bitbuf, uint code, int count )
461 mask = 1L << ( count - 1 );
464 bitbuf->rack |= bitbuf->mask;
466 if ( bitbuf->mask == 0 ) {
467 *bitbuf->data++=(ubyte)bitbuf->rack;
475 uint input_bits( BitBuf *bitbuf, int bit_count )
480 mask = 1L << ( bit_count - 1 );
483 if ( bitbuf->mask == 0x80 ) {
484 bitbuf->rack = *bitbuf->data++;
485 if ( bitbuf->rack == EOF )
486 return END_OF_STREAM;
488 if ( bitbuf->rack & bitbuf->mask )
489 return_value |= mask;
492 if ( bitbuf->mask == 0 )
495 return( return_value );
499 static void InitializeDictionary()
503 for ( i = 0 ; i < TABLE_SIZE ; i++ )
504 dict[i].code_value = UNUSED;
506 next_code = FIRST_CODE;
507 current_code_bits = 9;
508 next_bump_code = 511;
512 static uint find_child_node( int parent_code, int child_character )
517 index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
521 offset = TABLE_SIZE - index;
523 if ( dict[ index ].code_value == UNUSED )
524 return( (uint) index );
525 if ( dict[ index ].parent_code == parent_code &&
526 dict[ index ].character == (char) child_character )
528 if ( (int) index >= offset )
531 index += TABLE_SIZE - offset;
536 static uint decode_string( uint count, uint code )
538 while ( code > 255 ) {
539 decode_stack[ count++ ] = dict[ code ].character;
540 code = dict[ code ].parent_code;
542 decode_stack[ count++ ] = (char) code;
546 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size )
554 // Init output bit buffer
557 output.data = outputbuf;
559 InitializeDictionary();
561 string_code = *inputbuf++;
563 for ( i=1 ; i<input_size ; i++ ) {
564 character = *inputbuf++;
565 index = find_child_node( string_code, character );
566 if ( dict[ index ].code_value != - 1 )
567 string_code = dict[ index ].code_value;
569 dict[ index ].code_value = next_code++;
570 dict[ index ].parent_code = string_code;
571 dict[ index ].character = (char) character;
572 output_bits( &output, (unsigned long) string_code, current_code_bits );
573 string_code = character;
574 if ( next_code > MAX_CODE ) {
575 output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
576 InitializeDictionary();
577 } else if ( next_code > next_bump_code ) {
578 output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
580 next_bump_code <<= 1;
585 output_bits( &output, (unsigned long) string_code, current_code_bits );
586 output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
588 if ( output.mask != 0x80 )
589 *output.data++ = (ubyte)output.rack;
591 return output.data-outputbuf;
595 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf )
606 input.data = inputbuf;
610 InitializeDictionary();
611 old_code = (uint) input_bits( &input, current_code_bits );
612 if ( old_code == END_OF_STREAM )
614 character = old_code;
615 outputbuf[counter++] = ( ubyte )old_code;
617 new_code = (uint) input_bits( &input, current_code_bits );
618 if ( new_code == END_OF_STREAM )
620 if ( new_code == FLUSH_CODE )
622 if ( new_code == BUMP_CODE ) {
626 if ( new_code >= next_code ) {
627 decode_stack[ 0 ] = (char) character;
628 count = decode_string( 1, old_code );
630 count = decode_string( 0, new_code );
632 character = decode_stack[ count - 1 ];
634 outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
635 dict[ next_code ].parent_code = old_code;
636 dict[ next_code ].character = (char) character;
644 // process a join request packet add
645 void add_join_request(ubyte *data, int *size, join_request *jr)
647 int packet_size = *size;
648 join_request *jr_tmp = jr;
650 jr_tmp->tracker_id = INTEL_INT(jr->tracker_id);
651 jr_tmp->player_options.flags = INTEL_INT(jr->player_options.flags);
652 jr_tmp->player_options.obj_update_level = INTEL_INT(jr->player_options.obj_update_level);
659 // process a join request packet get
660 void get_join_request(ubyte *data, int *size, join_request jr)
666 jr.tracker_id = INTEL_INT(jr.tracker_id);
667 jr.player_options.flags = INTEL_INT(jr.player_options.flags);
668 jr.player_options.obj_update_level = INTEL_INT(jr.player_options.obj_update_level);
673 void add_net_addr(ubyte *data, int *size, net_addr addr)
675 int packet_size = *size;
676 net_addr addr_tmp = addr;
678 addr_tmp.type = INTEL_INT(addr.type);
679 addr_tmp.port = INTEL_SHORT(addr.port);
686 void get_net_addr(ubyte *data, int *size, net_addr addr)
692 addr.type = INTEL_INT(addr.type);
693 addr.port = INTEL_SHORT(addr.port);
698 void add_vector_data(ubyte *data, int *size, vector vec)
700 int packet_size = *size;
702 ADD_DATA_FL(vec.xyz.x);
703 ADD_DATA_FL(vec.xyz.y);
704 ADD_DATA_FL(vec.xyz.z);
709 void get_vector_data(ubyte *data, int *size, vector vec)
713 GET_DATA_FL(vec.xyz.x);
714 GET_DATA_FL(vec.xyz.y);
715 GET_DATA_FL(vec.xyz.z);
720 // send the specified data packet to all players
721 void multi_io_send(net_player *pl, ubyte *data, int len)
724 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
728 // don't do it for single player
729 if(!(Game_mode & GM_MULTIPLAYER)){
734 if(MULTIPLAYER_CLIENT){
735 // Assert(pl == Net_player);
736 if(pl != Net_player){
740 // Assert(pl != Net_player);
741 if(pl == Net_player){
746 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
747 if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
748 multi_io_send_force(pl);
749 pl->s_info.unreliable_buffer_size = 0;
752 Assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
754 memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
755 pl->s_info.unreliable_buffer_size += len;
758 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
761 Assert(MULTIPLAYER_MASTER);
763 // need to check for i > 1, hmmm... and connected. I don't know.
764 for (i = 0; i < MAX_PLAYERS; i++ ) {
765 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
769 // maybe ignore a player
770 if((ignore != NULL) && (&Net_players[i] == ignore)){
774 // ingame joiners not waiting to select a ship doesn't get any packets
775 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
780 multi_io_send(&Net_players[i], data, length);
784 void multi_io_send_force(net_player *pl)
787 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
791 // don't do it for single player
792 if(!(Game_mode & GM_MULTIPLAYER)){
796 // send everything in
797 if (MULTIPLAYER_MASTER) {
798 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
800 // add the bytes sent to this player
801 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
803 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
805 pl->s_info.unreliable_buffer_size = 0;
808 // send the data packet to all players via their reliable sockets
809 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
812 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
816 // don't do it for single player
817 if(!(Game_mode & GM_MULTIPLAYER)){
822 if(MULTIPLAYER_CLIENT){
823 // Assert(pl == Net_player);
824 if(pl != Net_player){
828 // Assert(pl != Net_player);
829 if(pl == Net_player){
834 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
835 if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
836 multi_io_send_reliable_force(pl);
837 pl->s_info.reliable_buffer_size = 0;
840 Assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
842 memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
843 pl->s_info.reliable_buffer_size += len;
846 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
849 Assert(MULTIPLAYER_MASTER);
851 // need to check for i > 1, hmmm... and connected. I don't know.
852 for (i = 0; i < MAX_PLAYERS; i++ ) {
853 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
857 // maybe ignore a player
858 if((ignore != NULL) && (&Net_players[i] == ignore)){
862 // ingame joiners not waiting to select a ship doesn't get any packets
863 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
868 multi_io_send_reliable(&Net_players[i], data, length);
872 void multi_io_send_reliable_force(net_player *pl)
875 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
879 // don't do it for single player
880 if(!(Game_mode & GM_MULTIPLAYER)){
884 // send everything in
885 if(MULTIPLAYER_MASTER) {
886 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
887 } else if(Net_player != NULL){
888 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
890 pl->s_info.reliable_buffer_size = 0;
893 // send all buffered packets
894 void multi_io_send_buffered_packets()
898 // don't do it for single player
899 if(!(Game_mode & GM_MULTIPLAYER)){
904 if(MULTIPLAYER_MASTER){
905 for(idx=0; idx<MAX_PLAYERS; idx++){
906 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
907 // force unreliable data
908 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
909 multi_io_send_force(&Net_players[idx]);
910 Net_players[idx].s_info.unreliable_buffer_size = 0;
913 // force reliable data
914 if(Net_players[idx].s_info.reliable_buffer_size > 0){
915 multi_io_send_reliable_force(&Net_players[idx]);
916 Net_players[idx].s_info.reliable_buffer_size = 0;
922 else if(Net_player != NULL){
923 // force unreliable data
924 if(Net_player->s_info.unreliable_buffer_size > 0){
925 multi_io_send_force(Net_player);
926 Net_player->s_info.unreliable_buffer_size = 0;
929 // force reliable data
930 if(Net_player->s_info.reliable_buffer_size > 0){
931 multi_io_send_reliable_force(Net_player);
932 Net_player->s_info.reliable_buffer_size = 0;
937 // 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)
938 void send_game_chat_packet(net_player *from, char *msg, int msg_mode, net_player *to, char *expr, int server_msg)
940 ubyte data[MAX_PACKET_SIZE],mode;
943 BUILD_HEADER(GAME_CHAT);
946 ADD_DATA_S16(from->player_id);
948 // add the message mode and if in MSG_TARGET mode, add who the target is
949 ADD_DATA_S32(server_msg);
950 mode = (ubyte)msg_mode;
953 case MULTI_MSG_TARGET:
955 ADD_DATA_S16(to->player_id);
958 Assert(expr != NULL);
962 // add the message itself
965 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
967 // message all players
969 for(idx=0;idx<MAX_PLAYERS;idx++){
970 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
971 multi_io_send_reliable(&Net_players[idx], data, packet_size);
976 // message only friendly players
977 case MULTI_MSG_FRIENDLY:
978 for(idx=0;idx<MAX_PLAYERS;idx++){
979 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)){
980 multi_io_send_reliable(&Net_players[idx], data, packet_size);
985 // message only hostile players
986 case MULTI_MSG_HOSTILE:
987 for(idx=0;idx<MAX_PLAYERS;idx++){
988 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)){
989 multi_io_send_reliable(&Net_players[idx], data, packet_size);
994 // message the player's target
995 case MULTI_MSG_TARGET:
997 if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
998 multi_io_send_reliable(to, data, packet_size);
1002 // message all players who match the expression string
1003 case MULTI_MSG_EXPR:
1004 Assert(expr != NULL);
1005 for(idx=0;idx<MAX_PLAYERS;idx++){
1006 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
1007 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1013 // send to the server, who will take care of routing it
1015 multi_io_send_reliable(Net_player, data, packet_size);
1019 // process a general game chat packet, if we're the standalone we should rebroadcast
1020 void process_game_chat_packet( ubyte *data, header *hinfo )
1024 int color_index,player_index,to_player_index,should_display,server_msg;
1025 char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
1029 offset = HEADER_LENGTH;
1031 // get the id of the sender
1034 // determine if this is a server message
1035 GET_DATA_S32(server_msg);
1040 // if targeting a specific player, get the address
1043 case MULTI_MSG_TARGET:
1046 case MULTI_MSG_EXPR:
1050 // get the message itself
1054 // get the index of the sending player
1055 color_index = find_player_id(from);
1056 player_index = color_index;
1058 // if we couldn't find the player - bail
1059 if(player_index == -1){
1060 nprintf(("Network","Could not find player for processing game chat packet!\n"));
1066 // if we're the server, determine what to do with the packet here
1067 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1068 // if he's targeting a specific player, find out who it is
1069 if(mode == MULTI_MSG_TARGET){
1070 to_player_index = find_player_id(to);
1072 to_player_index = -1;
1075 // if we couldn't find who sent the message or who should be getting the message, the bail
1076 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
1080 // determine if _I_ should be seeing the text
1081 if(Game_mode & GM_STANDALONE_SERVER){
1084 // check against myself for several specific cases
1086 if((mode == MULTI_MSG_ALL) ||
1087 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
1088 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
1089 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
1090 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
1095 // if we're the server of a game, we need to rebroadcast to all other players
1097 // individual target mission
1098 case MULTI_MSG_TARGET:
1099 // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
1100 if(to_player_index != MY_NET_PLAYER_NUM){
1101 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1105 case MULTI_MSG_EXPR:
1106 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1110 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1114 // if a client receives this packet, its always ok for him to display it
1119 // if we're not on a standalone
1121 if(server_msg == 2){
1124 multi_display_chat_msg(msg, player_index, !server_msg);
1129 // broadcast a hud message to all players
1130 void send_hud_msg_to_all( char* msg )
1132 ubyte data[MAX_PACKET_SIZE];
1135 // only the server should be sending this packet
1136 BUILD_HEADER(HUD_MSG);
1140 multi_io_send_to_all( data, packet_size );
1143 // process an incoming hud message packet
1144 void process_hud_message(ubyte* data, header* hinfo)
1147 char msg_buffer[255];
1149 offset = HEADER_LENGTH;
1151 GET_STRING(msg_buffer);
1154 // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1155 if(Game_mode & GM_IN_MISSION){
1156 HUD_printf(msg_buffer);
1160 // send a join packet request to the specified address (should be a server)
1161 void send_join_packet(net_addr* addr,join_request *jr)
1163 ubyte data[MAX_PACKET_SIZE];
1166 // build the header and add the request
1169 add_join_request(data, &packet_size, jr);
1171 psnet_send(addr, data, packet_size);
1174 // process an incoming join request packet
1175 void process_join_packet(ubyte* data, header* hinfo)
1180 int host_restr_mode;
1181 // int team0_avail,team1_avail;
1182 char join_string[255];
1185 // only the server of the game should ever receive this packet
1186 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1189 offset = HEADER_LENGTH;
1191 // read in the request info
1192 memset(&jr,0,sizeof(join_request));
1195 jr.tracker_id = INTEL_INT(jr.tracker_id);
1199 // fill in the address information of where this came from
1200 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
1202 // determine if we should accept this guy, or return a reason we should reject him
1203 // see the DENY_* codes in multi.h
1204 ret_code = multi_eval_join_request(&jr,&addr);
1206 // evaluate the return code
1208 // he should be accepted
1212 // we have to query the host because this is a restricted game
1213 case JOIN_QUERY_RESTRICTED :
1214 if(!(Game_mode & GM_STANDALONE_SERVER)){
1215 // notify the host of the event
1216 snd_play(&Snds[SND_CUE_VOICE]);
1219 // set the query timestamp
1220 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1221 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1223 // determine what mode we're in
1224 host_restr_mode = -1;
1225 memset(join_string,0,255);
1226 // if(Netgame.type == NG_TYPE_TEAM){
1227 // multi_player_ships_available(&team0_avail,&team1_avail);
1229 // if(team0_avail && team1_avail){
1230 // host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1231 // sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1232 // } else if(team0_avail && !team1_avail){
1233 // host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1234 // sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1235 // } else if(!team0_avail && team1_avail){
1236 // host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1237 // sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1239 // } else if(Netgame.mode == NG_MODE_RESTRICTED){
1240 host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1241 sprintf(join_string,XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1243 Assert(host_restr_mode != -1);
1245 // store the request info
1246 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1247 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1248 Multi_join_restr_mode = host_restr_mode;
1250 // if i'm the standalone server, I need to send a query to the host
1251 if(Game_mode & GM_STANDALONE_SERVER){
1252 send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1254 HUD_printf(join_string);
1258 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1262 // he'e being denied for some reason
1264 // send him the reason he is being denied
1265 send_deny_packet(&addr,ret_code);
1269 // process the rest of the request
1270 multi_process_valid_join_request(&jr,&addr);
1273 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1274 void send_new_player_packet(int new_player_num,net_player *target)
1276 ubyte data[MAX_PACKET_SIZE], val;
1277 int packet_size = 0;
1279 BUILD_HEADER( NOTIFY_NEW_PLAYER );
1281 // add the new player's info
1282 ADD_DATA_S32(new_player_num);
1283 // ADD_DATA(Net_players[new_player_num].p_info.addr);
1285 add_net_addr(data, &packet_size, Net_players[new_player_num].p_info.addr);
1287 ADD_DATA_S16(Net_players[new_player_num].player_id);
1288 ADD_DATA_S32(Net_players[new_player_num].flags);
1289 ADD_STRING(Net_players[new_player_num].player->callsign);
1290 ADD_STRING(Net_players[new_player_num].player->image_filename);
1291 ADD_STRING(Net_players[new_player_num].player->squad_filename);
1292 ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1294 val = (ubyte)Net_players[new_player_num].p_info.team;
1297 // broadcast the data
1299 multi_io_send_reliable(target, data, packet_size);
1301 multi_io_send_to_all_reliable(data, packet_size);
1305 // process a notification for a new player who has joined the game
1306 void process_new_player_packet(ubyte* data, header* hinfo)
1308 int already_in_game = 0;
1309 int offset, new_player_num,player_num,new_flags;
1311 char new_player_name[CALLSIGN_LEN+2] = "";
1312 char new_player_image[MAX_FILENAME_LEN+1] = "";
1313 char new_player_squad[MAX_FILENAME_LEN+1] = "";
1314 char new_player_pxo_squad[LOGIN_LEN+1] = "";
1315 char notify_string[256];
1319 offset = HEADER_LENGTH;
1321 // get the new players information
1322 GET_DATA_S32(new_player_num);
1323 get_net_addr(data, &offset, new_addr);
1325 GET_DATA_S16(new_id);
1326 GET_DATA_S32(new_flags);
1327 GET_STRING(new_player_name);
1328 GET_STRING(new_player_image);
1329 GET_STRING(new_player_squad);
1330 GET_STRING(new_player_pxo_squad);
1334 player_num = multi_find_open_player_slot();
1335 Assert(player_num != -1);
1337 // note that this new code does not check for duplicate IPs. It merely checks to see if
1338 // the slot referenced by new_player_num is already occupied by a connected player
1339 if(MULTI_CONNECTED(Net_players[new_player_num])){
1343 // if he's not alreayd in the game for one reason or another
1344 if ( !already_in_game ) {
1345 if ( Game_mode & GM_IN_MISSION ){
1346 HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1349 // create the player
1350 memcpy(new_addr.net_id, Psnet_my_addr.net_id, 4);
1352 if(new_flags & NETINFO_FLAG_OBSERVER){
1353 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1354 Net_players[new_player_num].flags |= new_flags;
1356 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1357 Net_players[new_player_num].flags |= new_flags;
1360 // copy in the filename
1361 if(strlen(new_player_image) > 0){
1362 strcpy(Net_players[new_player_num].player->image_filename, new_player_image);
1364 strcpy(Net_players[new_player_num].player->image_filename, "");
1366 // copy his pilot squad filename
1367 Net_players[new_player_num].player->insignia_texture = -1;
1368 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1370 // copy in his pxo squad name
1371 strcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad);
1373 // since we just created the player, set the last_heard_time here.
1374 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1376 Net_players[new_player_num].p_info.team = team;
1378 Net_players[new_player_num].player_id = new_id;
1380 // zero out this players ping
1381 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1383 // add a chat message
1384 if(Net_players[new_player_num].player->callsign != NULL){
1385 sprintf(notify_string,XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1386 multi_display_chat_msg(notify_string,0,0);
1391 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1393 // let the current ui screen know someone joined
1394 switch(gameseq_get_state()){
1395 case GS_STATE_MULTI_HOST_SETUP :
1396 multi_create_handle_join(&Net_players[new_player_num]);
1398 case GS_STATE_MULTI_CLIENT_SETUP :
1399 multi_jw_handle_join(&Net_players[new_player_num]);
1404 #define PLAYER_DATA_SLOP 100
1406 void send_accept_player_data( net_player *npp, int is_ingame )
1410 ubyte data[MAX_PACKET_SIZE], stop;
1412 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1414 // add in the netplayer data for all players
1416 for (i=0; i<MAX_PLAYERS; i++) {
1417 // skip non connected players
1418 if ( !MULTI_CONNECTED(Net_players[i]) ){
1422 // skip this new player's entry
1423 if ( npp->player_id == Net_players[i].player_id ){
1427 // add the stop byte
1430 // add the player's number
1433 // add the player's address
1434 // ADD_DATA(Net_players[i].p_info.addr);
1435 add_net_addr(data, &packet_size, Net_players[i].p_info.addr);
1438 ADD_DATA_S16(Net_players[i].player_id);
1441 ADD_STRING(Net_players[i].player->callsign);
1443 // add his image filename
1444 ADD_STRING(Net_players[i].player->image_filename);
1446 // add his squad filename
1447 ADD_STRING(Net_players[i].player->squad_filename);
1449 // add his PXO squad name
1450 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1453 ADD_DATA_S32(Net_players[i].flags);
1455 // add his object's net sig
1457 ADD_DATA_U16( Objects[Net_players[i].player->objnum].net_signature );
1460 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1461 stop = APD_END_PACKET;
1463 multi_io_send_reliable( npp, data, packet_size );
1464 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1470 // add the stop byte
1471 stop = APD_END_DATA;
1473 multi_io_send_reliable(npp, data, packet_size);
1476 // send an accept packet to a client in response to a request to join the game
1477 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1480 ubyte data[MAX_PACKET_SIZE],val;
1481 char notify_string[256];
1484 Assert(new_player_num >= 0);
1486 // setup his "reliable" socket
1487 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1489 // build the packet header
1491 BUILD_HEADER(ACCEPT);
1493 // add the accept code
1496 // add code specific accept data
1497 if (code & ACCEPT_INGAME) {
1498 // the game filename
1499 ADD_STRING(Game_current_mission_filename);
1501 // if he is joining on a specific team, mark it here
1502 if(ingame_join_team != -1){
1505 val = (ubyte)ingame_join_team;
1513 if (code & ACCEPT_OBSERVER) {
1514 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1517 if (code & ACCEPT_HOST) {
1518 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1521 if (code & ACCEPT_CLIENT) {
1522 Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1525 // add the current skill level setting on the host
1526 ADD_DATA_S32(Game_skill_level);
1528 // add this guys player num
1529 ADD_DATA_S32(new_player_num);
1531 // add his player id
1532 ADD_DATA_S16(Net_players[new_player_num].player_id);
1534 // add netgame type flags
1535 ADD_DATA_S32(Netgame.type_flags);
1538 // char buffer[100];
1539 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1542 // actually send the packet
1543 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1545 // if he's not an observer, inform all the other players in the game about him
1546 // inform the other players in the game about this new player
1547 for (i=0; i<MAX_PLAYERS; i++) {
1548 // skip unconnected players as well as this new guy himself
1549 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])) {
1553 // send the new packet
1554 send_new_player_packet(new_player_num,&Net_players[i]);
1557 // add a chat message
1558 if(Net_players[new_player_num].player->callsign != NULL){
1559 sprintf(notify_string,XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1560 multi_display_chat_msg(notify_string, 0, 0);
1563 // handle any team vs. team details
1564 if (!(code & ACCEPT_OBSERVER)) {
1565 multi_team_handle_join(&Net_players[new_player_num]);
1569 if(Net_players[new_player_num].tracker_player_id >= 0){
1570 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);
1572 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1577 // process the player data from the server
1578 void process_accept_player_data( ubyte *data, header *hinfo )
1580 int offset, player_num, player_slot_num, new_flags;
1581 char name[CALLSIGN_LEN + 1] = "";
1582 char image_name[MAX_FILENAME_LEN + 1] = "";
1583 char squad_name[MAX_FILENAME_LEN + 1] = "";
1584 char pxo_squad_name[LOGIN_LEN+1] = "";
1588 ushort ig_signature;
1590 offset = HEADER_LENGTH;
1593 while ( stop == APD_NEXT ) {
1594 player_slot_num = multi_find_open_player_slot();
1595 Assert(player_slot_num != -1);
1597 // get the player's number
1598 GET_DATA_S32(player_num);
1600 // add the player's address
1601 get_net_addr(data, &offset, addr);
1603 // get the player's id#
1604 GET_DATA_S16(player_id);
1609 // add his image filename
1610 GET_STRING(image_name);
1612 // get his squad logo filename
1613 GET_STRING(squad_name);
1615 // get his PXO squad name
1616 GET_STRING(pxo_squad_name);
1619 GET_DATA_S32(new_flags);
1621 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1622 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1627 // the error handling here is less than stellar. We should probably put up a popup and go
1628 // back to the main menu. But then again, this should never ever happen!
1629 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1634 // copy his image filename
1635 strcpy(Net_players[player_num].player->image_filename, image_name);
1637 // copy his pilot squad filename
1638 Net_players[player_num].player->insignia_texture = -1;
1639 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1641 // copy his pxo squad name
1642 strcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name);
1644 // set his player id#
1645 Net_players[player_num].player_id = player_id;
1647 // mark him as being connected
1648 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1649 Net_players[player_num].flags |= new_flags;
1651 // set the server pointer
1652 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1653 Netgame.server = &Net_players[player_num];
1654 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1656 // also - always set the server address to be where this data came from, NOT from
1657 // the data in the packet
1658 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->net_id, hinfo->port);
1661 // set the host pointer
1662 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1663 Netgame.host = &Net_players[player_num];
1666 // read in the player's object net signature and store as his objnum for now
1667 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1668 GET_DATA_U16( ig_signature );
1669 Net_players[player_num].player->objnum = ig_signature;
1672 // get the stop byte
1677 if ( stop == APD_END_DATA ) {
1678 // if joining a game automatically, set the connect address to NULl so we don't try and
1679 // do this next time we enter a game
1680 if (Cmdline_connect_addr != NULL) {
1681 Cmdline_connect_addr = NULL;
1684 // send my stats to the server if I'm not in observer mode
1685 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1686 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1689 // if i'm being accepted as a host, then move into the host setup state
1690 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1691 // set my permission bits
1692 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1693 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1695 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1698 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1699 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1701 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1702 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1703 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1707 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1708 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1711 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1712 // flag myself as being an ingame joiner
1713 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1715 // move myself into the ingame join mission sync state
1716 Multi_sync_mode = MULTI_SYNC_INGAME;
1717 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1720 // update my options on the server
1721 multi_options_update_local();
1723 // if we're in PXO mode, mark it down in our player struct
1724 if(MULTI_IS_TRACKER_GAME){
1725 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1726 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1731 // process an accept packet from the server
1732 extern int Select_default_ship;
1734 void process_accept_packet(ubyte* data, header* hinfo)
1736 int code, my_player_num, offset;
1740 // get the accept code
1741 offset = HEADER_LENGTH;
1745 // read in the accept code specific data
1747 if (code & ACCEPT_INGAME) {
1748 // the game filename
1749 GET_STRING(Game_current_mission_filename);
1750 Select_default_ship = 0;
1752 // determine if I'm being placed on a team
1759 if (code & ACCEPT_OBSERVER) {
1760 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1763 if (code & ACCEPT_HOST) {
1764 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1767 if (code & ACCEPT_CLIENT) {
1768 Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1771 // fill in the netgame server address
1772 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->net_id, hinfo->port );
1774 // get the skill level setting
1775 GET_DATA_S32(Game_skill_level);
1777 // get my netplayer number
1778 GET_DATA_S32(my_player_num);
1781 GET_DATA_S16(player_id);
1783 // get netgame type flags
1784 GET_DATA_S32(Netgame.type_flags);
1786 // setup the Net_players structure for myself first
1787 Net_player = &Net_players[my_player_num];
1788 Net_player->flags = 0;
1789 Net_player->tracker_player_id = Multi_tracker_id;
1790 Net_player->player_id = player_id;
1791 Net_player->s_info.xfer_handle = -1;
1792 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1793 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1794 multi_options_local_load(&Net_player->p_info.options, Net_player);
1796 Net_player->p_info.team = team;
1799 // determine if I have a CD
1801 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1804 // set accept code in netplayer for this guy
1805 if ( code & ACCEPT_INGAME ){
1806 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1808 if ( code & ACCEPT_OBSERVER ){
1809 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1811 if ( code & ACCEPT_HOST ){
1812 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1814 if ( code & ACCEPT_CLIENT ){
1815 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1818 // if I have hacked data
1819 if(game_hacked_data()){
1820 Net_player->flags |= NETINFO_FLAG_HAXOR;
1823 // if we're supposed to flush our local data cache, do so now
1824 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1825 multi_flush_multidata_cache();
1828 Net_player->sv_bytes_sent = 0;
1829 Net_player->sv_last_pl = -1;
1830 Net_player->cl_bytes_recvd = 0;
1831 Net_player->cl_last_pl = -1;
1833 // intiialize endgame stuff
1834 multi_endgame_init();
1838 // make a call to psnet to initialize and try to connect with the server.
1839 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1840 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1841 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1845 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1846 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1848 ubyte data[MAX_PACKET_SIZE];
1850 int packet_size = 0;
1852 BUILD_HEADER(LEAVE_GAME);
1854 // add a flag indicating whether he was kicked or not
1855 val = (char)kicked_reason;
1858 if (player_id < 0) {
1859 ADD_DATA_S16(Net_player->player_id);
1861 // inform the host that we are leaving the game
1862 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1863 multi_io_send_to_all_reliable(data, packet_size);
1865 multi_io_send_reliable(Net_player, data, packet_size);
1868 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1869 // so he has to tell everyone that this guy left
1871 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1873 // a couple of important checks
1874 Assert(player_id != Net_player->player_id);
1875 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1877 // add the id of the guy to be kicked
1878 ADD_DATA_S16(player_id);
1880 // broadcast to everyone
1881 if (target == NULL) {
1882 multi_io_send_to_all_reliable(data, packet_size);
1884 multi_io_send_reliable(target, data, packet_size);
1889 // process a notification the a player has left the game
1890 void process_leave_game_packet(ubyte* data, header* hinfo)
1898 offset = HEADER_LENGTH;
1900 // get whether he was kicked
1901 GET_DATA(kicked_reason);
1903 // get the address of the guy who is to leave
1904 GET_DATA_S16(deader_id);
1907 // determine who is dropping and printf out a notification
1908 player_num = find_player_id(deader_id);
1909 if (player_num == -1) {
1910 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1914 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1917 // a hook to display that a player was kicked
1918 if (kicked_reason >= 0){
1919 // if it was me that was kicked, leave the game
1920 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1923 switch(kicked_reason){
1924 case KICK_REASON_BAD_XFER:
1925 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1927 case KICK_REASON_CANT_XFER:
1928 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1930 case KICK_REASON_INGAME_ENDED:
1931 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1934 notify_code = MULTI_END_NOTIFY_KICKED;
1938 multi_quit_game(PROMPT_NONE, notify_code);
1941 // otherwise indicate someone was kicked
1943 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1945 // display the result
1946 memset(str, 0, 512);
1947 multi_kick_get_text(&Net_players[player_num], kicked_reason, str);
1948 multi_display_chat_msg(str, player_num, 0);
1952 // first of all, if we're the master, we should be rebroadcasting this packet
1953 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1956 sprintf(msg, XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1958 if (!(Game_mode & GM_STANDALONE_SERVER)){
1959 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1962 send_hud_msg_to_all(msg);
1963 multi_io_send_to_all_reliable(data, offset);
1966 // leave the game if the host and/or master has dropped
1968 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1969 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1972 ml_string(NOX("Host and/or server has left the game"));
1974 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1975 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1976 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1979 delete_player(player_num);
1982 delete_player(player_num);
1984 // OSAPI GUI stuff (if standalone)
1985 if (Game_mode & GM_STANDALONE_SERVER) {
1986 // returns true if we should reset the standalone
1987 if (std_remove_player(&Net_players[player_num])) {
1988 nprintf(("Network", "Should reset!!\n"));
1992 // update these gui vals
1993 std_connect_set_host_connect_status();
1994 std_connect_set_connect_count();
1998 // send information about this currently active game to the specified address
1999 void send_game_active_packet(net_addr* addr)
2003 ubyte data[MAX_PACKET_SIZE],val;
2005 // build the header and add the data
2006 BUILD_HEADER(GAME_ACTIVE);
2008 // add the server version and compatible version #
2009 val = MULTI_FS_SERVER_VERSION;
2011 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2014 ADD_STRING(Netgame.name);
2015 ADD_STRING(Netgame.mission_name);
2016 ADD_STRING(Netgame.title);
2017 val = (ubyte)multi_num_players();
2020 // add the proper flags
2022 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2023 flags |= AG_FLAG_PASSWD;
2026 // proper netgame type flags
2027 if(Netgame.type_flags & NG_TYPE_TEAM){
2028 flags |= AG_FLAG_TEAMS;
2029 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2030 flags |= AG_FLAG_DOGFIGHT;
2032 flags |= AG_FLAG_COOP;
2035 // proper netgame state flags
2036 switch(Netgame.game_state){
2037 case NETGAME_STATE_FORMING:
2038 flags |= AG_FLAG_FORMING;
2041 case NETGAME_STATE_BRIEFING:
2042 case NETGAME_STATE_MISSION_SYNC:
2043 case NETGAME_STATE_HOST_SETUP:
2044 flags |= AG_FLAG_BRIEFING;
2047 case NETGAME_STATE_IN_MISSION:
2048 flags |= AG_FLAG_IN_MISSION;
2051 case NETGAME_STATE_PAUSED:
2052 flags |= AG_FLAG_PAUSE;
2055 case NETGAME_STATE_ENDGAME:
2056 case NETGAME_STATE_DEBRIEF:
2057 flags |= AG_FLAG_DEBRIEF;
2061 // if this is a standalone
2062 if(Game_mode & GM_STANDALONE_SERVER){
2063 flags |= AG_FLAG_STANDALONE;
2066 // if we're in campaign mode
2067 if(Netgame.campaign_mode == MP_CAMPAIGN){
2068 flags |= AG_FLAG_CAMPAIGN;
2071 // add the data about the connection speed of the host machine
2072 Assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2073 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2075 ADD_DATA_U16(flags);
2078 psnet_send(addr, data, packet_size);
2081 // process information about an active game
2082 void process_game_active_packet(ubyte* data, header* hinfo)
2087 int modes_compatible;
2089 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->net_id, hinfo->port);
2091 // read this game into a temporary structure
2092 offset = HEADER_LENGTH;
2094 // get the server version and compatible version
2095 GET_DATA(ag.version);
2096 GET_DATA(ag.comp_version);
2098 GET_STRING(ag.name);
2099 GET_STRING(ag.mission_name);
2100 GET_STRING(ag.title);
2102 ag.num_players = val;
2103 GET_DATA_U16(ag.flags);
2107 modes_compatible = 1;
2109 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2110 modes_compatible = 0;
2112 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2113 modes_compatible = 0;
2117 // if this is a compatible version, and our modes are compatible, register it
2118 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2119 multi_update_active_games(&ag);
2123 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2124 // is used to change the current mission, current state, etc.
2125 void send_netgame_update_packet(net_player *pl)
2129 ubyte data[MAX_PACKET_SIZE];
2132 BUILD_HEADER(GAME_UPDATE);
2134 // with new mission description field, this becomes way to large
2135 // so we must add every element piece by piece except the
2136 ADD_STRING(Netgame.name);
2137 ADD_STRING(Netgame.mission_name);
2138 ADD_STRING(Netgame.title);
2139 ADD_STRING(Netgame.campaign_name);
2140 ADD_DATA_S32(Netgame.campaign_mode);
2141 ADD_DATA_S32(Netgame.max_players);
2142 ADD_DATA_S32(Netgame.security);
2143 ADD_DATA_U32(Netgame.respawn);
2144 ADD_DATA_S32(Netgame.flags);
2145 ADD_DATA_S32(Netgame.type_flags);
2146 ADD_DATA_S32(Netgame.version_info);
2147 ADD_DATA(Netgame.debug_flags);
2149 // only the server should ever send the netgame state (standalone situation)
2150 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2151 ADD_DATA_S32(Netgame.game_state);
2154 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2155 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2157 multi_io_send_to_all_reliable(data, packet_size);
2159 for(idx=0; idx<MAX_PLAYERS; idx++){
2160 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2161 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2165 multi_io_send_reliable(pl, data, packet_size);
2166 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2169 Assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2170 multi_io_send_reliable(Net_player, data, packet_size);
2173 // host should always send a netgame options update as well
2174 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2175 multi_options_update_netgame();
2179 // process information about the netgame sent from the server/host
2180 void process_netgame_update_packet( ubyte *data, header *hinfo )
2182 int offset,old_flags;
2185 Assert(!(Game_mode & GM_STANDALONE_SERVER));
2186 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2188 // read in the netgame information
2189 offset = HEADER_LENGTH;
2190 GET_STRING(Netgame.name);
2191 GET_STRING(Netgame.mission_name);
2192 GET_STRING(Netgame.title);
2193 GET_STRING(Netgame.campaign_name);
2194 GET_DATA_S32(Netgame.campaign_mode);
2195 GET_DATA_S32(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2196 GET_DATA_S32(Netgame.security);
2197 GET_DATA_U32(Netgame.respawn);
2199 // be sure not to blast the quitting flag because of the "one frame extra" problem
2200 old_flags = Netgame.flags;
2201 GET_DATA_S32(Netgame.flags);
2202 GET_DATA_S32(Netgame.type_flags);
2203 GET_DATA_S32(Netgame.version_info);
2204 GET_DATA(Netgame.debug_flags);
2207 GET_DATA_S32(ng_state);
2211 // now compare the passed in game state to our current known state. If it has changed, then maybe
2212 // do something interesting.
2213 // move from the forming or debriefing state to the mission sync state
2214 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2215 // if coming from the forming state
2216 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2217 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2218 // do any special processing for forced state transitions
2219 multi_handle_state_special();
2221 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2222 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2223 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2225 // if coming from the debriefing state
2226 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2227 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2229 // do any special processing for forced state transitions
2230 multi_handle_state_special();
2232 multi_flush_mission_stuff();
2234 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2235 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2236 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2239 // move from mission sync to team select
2240 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2241 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2242 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2244 // do any special processing for forced state transitions
2245 multi_handle_state_special();
2247 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2248 gameseq_post_event(GS_EVENT_START_BRIEFING);
2251 // move from the debriefing to the create game screen
2252 else if ( ng_state == NETGAME_STATE_FORMING ){
2253 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2254 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2255 // do any special processing for forced state transitions
2256 multi_handle_state_special();
2258 multi_flush_mission_stuff();
2260 // move to the proper screen
2261 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2262 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2264 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2269 Netgame.game_state = ng_state;
2272 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2273 void send_netgame_descript_packet(net_addr *addr, int code)
2275 ubyte data[MAX_PACKET_SIZE],val;
2277 int packet_size = 0;
2280 BUILD_HEADER(UPDATE_DESCRIPT);
2286 // add as much of the description as we dare
2287 len = strlen(The_mission.mission_desc);
2288 if(len > MAX_PACKET_SIZE - 10){
2289 len = MAX_PACKET_SIZE - 10;
2291 memcpy(data+packet_size,The_mission.mission_desc,len);
2294 ADD_STRING(The_mission.mission_desc);
2298 Assert(addr != NULL);
2300 psnet_send(addr, data, packet_size);
2304 // process an incoming netgame description packet
2305 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2309 char mission_desc[MISSION_DESC_LENGTH+2];
2312 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2314 // read this game into a temporary structure
2315 offset = HEADER_LENGTH;
2318 // if this is a request for mission description
2320 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2325 // send an update to this guy
2326 send_netgame_descript_packet(&addr, 1);
2328 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2329 GET_STRING(mission_desc);
2331 // only display if we're in the proper state
2332 state = gameseq_get_state();
2334 case GS_STATE_MULTI_JOIN_GAME:
2335 case GS_STATE_MULTI_CLIENT_SETUP:
2336 case GS_STATE_MULTI_HOST_SETUP:
2337 multi_common_set_text(mission_desc);
2345 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2346 void broadcast_game_query()
2350 server_item *s_moveup;
2351 ubyte data[MAX_PACKET_SIZE];
2353 BUILD_HEADER(GAME_QUERY);
2355 // go through the server list and query each of those as well
2356 s_moveup = Game_server_head;
2357 if(s_moveup != NULL){
2359 send_server_query(&s_moveup->server_addr);
2360 s_moveup = s_moveup->next;
2361 } while(s_moveup != Game_server_head);
2364 fill_net_addr(&addr, Psnet_my_addr.addr, Psnet_my_addr.net_id, DEFAULT_GAME_PORT);
2366 // send out a broadcast if our options allow us
2367 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2368 psnet_broadcast( &addr, data, packet_size);
2372 // send an individual query to an address to see if there is an active game
2373 void send_server_query(net_addr *addr)
2376 ubyte data[MAX_PACKET_SIZE];
2378 // build the header and send the data
2379 BUILD_HEADER(GAME_QUERY);
2380 psnet_send(addr, data, packet_size);
2383 // process a query from a client looking for active freespace games
2384 void process_game_query(ubyte* data, header* hinfo)
2389 offset = HEADER_LENGTH;
2393 // check to be sure that we don't capture our own broadcast message
2394 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2395 if ( psnet_same( &addr, &Psnet_my_addr) ){
2399 // if I am not a server of a game, don't send a reply!!!
2400 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2404 // if the game options are being selected, then ignore the request
2405 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2406 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2410 // send information about this active game
2411 send_game_active_packet(&addr);
2414 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2415 void send_netplayer_update_packet( net_player *pl )
2417 int packet_size,idx;
2418 ubyte data[MAX_PACKET_SIZE],val;
2420 BUILD_HEADER(NETPLAYER_UPDATE);
2422 // if I'm the server of the game, I should send an update for _all_players in the game
2423 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2424 for(idx=0;idx<MAX_PLAYERS;idx++){
2425 // only send info for connected players
2426 if(MULTI_CONNECTED(Net_players[idx])){
2431 // add the net player's information
2432 ADD_DATA_S16(Net_players[idx].player_id);
2433 ADD_DATA_S32(Net_players[idx].state);
2434 ADD_DATA_S32(Net_players[idx].p_info.ship_class);
2435 ADD_DATA_S32(Net_players[idx].tracker_player_id);
2437 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2445 // add the final stop byte
2449 // broadcast the packet
2450 if(!(Game_mode & GM_IN_MISSION)){
2452 multi_io_send_to_all_reliable(data, packet_size);
2454 multi_io_send_reliable(pl, data, packet_size);
2458 multi_io_send_to_all(data, packet_size);
2460 multi_io_send(pl, data, packet_size);
2468 // add my current state in the netgame to this packet
2469 ADD_DATA_S16(Net_player->player_id);
2470 ADD_DATA_S32(Net_player->state);
2471 ADD_DATA_S32(Net_player->p_info.ship_class);
2472 ADD_DATA_S32(Multi_tracker_id);
2474 // add if I have a CD or not
2482 // add a final stop byte
2486 // send the packet to the server
2487 Assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2488 if(!(Game_mode & GM_IN_MISSION)){
2489 multi_io_send_reliable(Net_player, data, packet_size);
2491 multi_io_send(Net_player, data, packet_size);
2496 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2497 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2499 int offset, player_num;
2505 offset = HEADER_LENGTH;
2507 // get the first stop byte
2510 while(stop != 0xff){
2511 // look the player up
2512 GET_DATA_S16(player_id);
2513 player_num = find_player_id(player_id);
2514 // if we couldn't find him, read in the bogus data
2515 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2516 GET_DATA_S32(bogus.state);
2517 GET_DATA_S32(bogus.p_info.ship_class);
2518 GET_DATA_S32(bogus.tracker_player_id);
2522 // otherwise read in the data correctly
2524 GET_DATA_S32(new_state);
2525 GET_DATA_S32(Net_players[player_num].p_info.ship_class);
2526 GET_DATA_S32(Net_players[player_num].tracker_player_id);
2529 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2531 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2534 // if he's changing state to joined, send a team update
2535 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2536 multi_team_send_update();
2540 Net_players[player_num].state = new_state;
2543 // get the next stop byte
2549 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2550 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2551 send_netplayer_update_packet(NULL);
2554 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2555 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2556 switch(Net_players[player_num].state){
2557 case NETPLAYER_STATE_STD_HOST_SETUP:
2558 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2561 case NETPLAYER_STATE_HOST_SETUP:
2562 // check for race conditions
2563 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2564 Netgame.game_state = NETGAME_STATE_FORMING;
2571 #define EXTRA_DEATH_VAPORIZED (1<<0)
2572 #define EXTRA_DEATH_WASHED (1<<1)
2573 // send a packet indicating a ship has been killed
2574 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2576 int packet_size, model;
2577 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2578 ushort debris_signature;
2582 // only sendable from the master
2583 Assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2586 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2588 extra_death_info = 0;
2590 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2593 if ( Ships[objp->instance].wash_killed ) {
2594 extra_death_info |= EXTRA_DEATH_WASHED;
2597 // find out the next network signature that will be used for the debris pieces.
2598 model = Ships[objp->instance].modelnum;
2599 pm = model_get(model);
2600 debris_signature = 0;
2601 if ( pm && !vaporized ) {
2602 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2603 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2604 Ships[objp->instance].arrival_distance = debris_signature;
2607 BUILD_HEADER(SHIP_KILL);
2608 ADD_DATA_U16(objp->net_signature);
2610 // ships which are initially killed get the rest of the data sent. self destructed ships and
2611 if ( other_objp == NULL ) {
2616 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2618 ADD_DATA_U16( other_objp->net_signature );
2621 ADD_DATA_U16( debris_signature );
2622 ADD_DATA_FL( percent_killed );
2623 sd = (ubyte)self_destruct;
2625 ADD_DATA( extra_death_info );
2627 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2629 if ( objp->flags & OF_PLAYER_SHIP ) {
2633 pnum = multi_find_player_by_object( objp );
2636 ADD_DATA( was_player );
2638 Assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2639 temp = (char)Net_players[pnum].player->killer_objtype;
2642 Assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2643 temp = (char)Net_players[pnum].player->killer_species;
2646 Assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2647 temp = (char)Net_players[pnum].player->killer_weapon_index;
2650 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2652 ADD_DATA( was_player );
2655 ADD_DATA( was_player );
2658 // send the packet reliably!!!
2659 multi_io_send_to_all_reliable(data, packet_size);
2662 // process a packet indicating that a ship has been killed
2663 void process_ship_kill_packet( ubyte *data, header *hinfo )
2666 ushort ship_sig, other_sig, debris_sig;
2667 object *sobjp, *oobjp;
2668 float percent_killed;
2669 ubyte was_player, extra_death_info, sd;
2670 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2672 offset = HEADER_LENGTH;
2673 GET_DATA_U16(ship_sig);
2675 GET_DATA_U16( other_sig );
2676 GET_DATA_U16( debris_sig );
2677 GET_DATA_FL( percent_killed );
2679 GET_DATA( extra_death_info );
2680 GET_DATA( was_player );
2683 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2684 if ( was_player != 0 ) {
2685 GET_DATA( killer_objtype );
2686 GET_DATA( killer_species );
2687 GET_DATA( killer_weapon_index );
2688 GET_STRING( killer_name );
2693 sobjp = multi_get_network_object( ship_sig );
2695 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2696 // another message from the server that this happened!
2697 if ( sobjp == NULL ) {
2698 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2702 // set this ship's hull value to 0
2703 sobjp->hull_strength = 0.0f;
2705 // maybe set vaporized
2706 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2707 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2710 // maybe set wash_killed
2711 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2712 Ships[sobjp->instance].wash_killed = 1;
2715 oobjp = multi_get_network_object( other_sig );
2717 if ( was_player != 0 ) {
2720 pnum = multi_find_player_by_object( sobjp );
2722 Net_players[pnum].player->killer_objtype = killer_objtype;
2723 Net_players[pnum].player->killer_species = killer_species;
2724 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2725 strcpy( Net_players[pnum].player->killer_parent_name, killer_name );
2729 // check to see if I need to respawn myself
2730 multi_respawn_check(sobjp);
2732 // store the debris signature in the arrival distance which will never get used for player ships
2733 Ships[sobjp->instance].arrival_distance = debris_sig;
2735 // set this bit so that we don't accidentally start switching targets when we die
2736 if(sobjp == Player_obj){
2737 Game_mode |= GM_DEAD_DIED;
2740 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2742 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2743 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2744 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2746 extern void ship_destroyed( int shipnum );
2747 ship_destroyed( sobjp->instance );
2748 sobjp->flags |= OF_SHOULD_BE_DEAD;
2749 obj_delete( OBJ_INDEX(sobjp) );
2753 // send a packet indicating a ship should be created
2754 void send_ship_create_packet( object *objp, int is_support )
2757 ubyte data[MAX_PACKET_SIZE];
2759 // We will pass the ship to create by name.
2760 BUILD_HEADER(SHIP_CREATE);
2761 ADD_DATA_U16(objp->net_signature);
2762 ADD_DATA_S32( is_support );
2764 add_vector_data(data, &packet_size, objp->pos);
2767 // broadcast the packet
2768 multi_io_send_to_all_reliable(data, packet_size);
2771 // process a packet indicating a ship should be created
2772 void process_ship_create_packet( ubyte *data, header *hinfo )
2774 int offset, objnum, is_support;
2777 vector pos = ZERO_VECTOR;
2779 Assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2780 offset = HEADER_LENGTH;
2781 GET_DATA_U16(signature);
2782 GET_DATA_S32( is_support );
2784 get_vector_data(data, &offset, pos);
2789 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2790 if ( !is_support ) {
2791 objp = mission_parse_get_arrival_ship( signature );
2792 if ( objp != NULL ) {
2793 objnum = parse_create_object(objp);
2795 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2798 Assert( Arriving_support_ship );
2799 if(Arriving_support_ship == NULL){
2802 Arriving_support_ship->pos = pos;
2803 Arriving_support_ship->net_signature = signature;
2804 objnum = parse_create_object( Arriving_support_ship );
2805 Assert( objnum != -1 );
2807 mission_parse_support_arrived( objnum );
2812 // send a packet indicating a wing of ships should be created
2813 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2815 int packet_size, index, ship_instance;
2816 ubyte data[MAX_PACKET_SIZE];
2820 // for creating wing -- we just send the index into the wing array of this wing.
2821 // all players load the same mission, and so their array's should all match. We also
2822 // need to send the signature of the first ship that was created. We can find this by
2823 // looking num_to_create places back in the ship_index field in the wing structure.
2825 index = WING_INDEX(wingp);
2826 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2827 signature = Objects[Ships[ship_instance].objnum].net_signature;
2829 BUILD_HEADER( WING_CREATE );
2830 ADD_DATA_S32(index);
2831 ADD_DATA_S32(num_to_create);
2832 ADD_DATA_U16(signature);
2833 ADD_DATA_S32(pre_create_count);
2834 val = wingp->current_wave - 1;
2837 multi_io_send_to_all_reliable(data, packet_size);
2840 // process a packet saying that a wing should be created
2841 void process_wing_create_packet( ubyte *data, header *hinfo )
2843 int offset, index, num_to_create;
2845 int total_arrived_count, current_wave;
2847 offset = HEADER_LENGTH;
2848 GET_DATA_S32(index);
2849 GET_DATA_S32(num_to_create);
2850 GET_DATA_U16(signature);
2851 GET_DATA_S32(total_arrived_count);
2852 GET_DATA_S32(current_wave);
2856 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2857 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2858 nprintf(("Network", "invalid index %d for wing create packet\n"));
2861 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2862 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2867 Wings[index].current_count = 0;
2868 Wings[index].total_arrived_count = total_arrived_count;
2869 Wings[index].current_wave = current_wave;
2871 // set the network signature that was passed. The client should create ships in the same order
2872 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2873 // need to set some timestamps and cues correctly to be sure that these things get created on
2874 // the clients correctly
2875 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2876 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2879 // packet indicating a ship is departing
2880 void send_ship_depart_packet( object *objp )
2882 ubyte data[MAX_PACKET_SIZE];
2886 signature = objp->net_signature;
2888 BUILD_HEADER(SHIP_DEPART);
2889 ADD_DATA_U16( signature );
2891 multi_io_send_to_all_reliable(data, packet_size);
2894 // process a packet indicating a ship is departing
2895 void process_ship_depart_packet( ubyte *data, header *hinfo )
2901 offset = HEADER_LENGTH;
2902 GET_DATA_U16( signature );
2905 // find the object which is departing
2906 objp = multi_get_network_object( signature );
2907 if ( objp == NULL ) {
2908 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2912 // start warping him out
2913 shipfx_warpout_start( objp );
2916 // packet to tell clients cargo of a ship was revealed to all
2917 void send_cargo_revealed_packet( ship *shipp )
2919 ubyte data[MAX_PACKET_SIZE];
2922 // build the header and add the data
2923 BUILD_HEADER(CARGO_REVEALED);
2924 ADD_DATA_U16( Objects[shipp->objnum].net_signature );
2926 // server sends to all players
2927 if(MULTIPLAYER_MASTER){
2928 multi_io_send_to_all_reliable(data, packet_size);
2930 // clients just send to the server
2932 multi_io_send_reliable(Net_player, data, packet_size);
2936 // process a cargo revealed packet
2937 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2943 offset = HEADER_LENGTH;
2944 GET_DATA_U16(signature);
2947 // get a ship pointer and call the ship function to reveal the cargo
2948 objp = multi_get_network_object( signature );
2949 if ( objp == NULL ) {
2950 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2954 // Assert( objp->type == OBJ_SHIP );
2955 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2959 // this will take care of re-routing to all other clients
2960 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2962 // server should rebroadcast
2963 if(MULTIPLAYER_MASTER){
2964 send_cargo_revealed_packet(&Ships[objp->instance]);
2968 // defines used for secondary fire packet
2969 #define SFPF_ALLOW_SWARM (1<<7)
2970 #define SFPF_DUAL_FIRE (1<<6)
2971 #define SFPF_TARGET_LOCKED (1<<5)
2973 // send a packet indicating a secondary weapon was fired
2974 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2976 int packet_size, net_player_num;
2977 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2979 ushort target_signature;
2983 // Assert ( starting_count < UCHAR_MAX );
2985 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
2986 // we might send the info to the other player different than the one who fired
2987 objp = &Objects[shipp->objnum];
2988 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2989 if ( num_fired == 0 ) {
2994 aip = &Ai_info[shipp->ai_index];
2996 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
2997 Assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );
2999 // build up the header portion
3000 BUILD_HEADER( SECONDARY_FIRED_AI );
3002 ADD_DATA_U16( Objects[shipp->objnum].net_signature );
3003 ADD_DATA_U16( starting_sig );
3005 // add a couple of bits for swarm missiles and dual fire secondary weaspons
3008 sinfo = current_bank;
3011 sinfo |= SFPF_ALLOW_SWARM;
3014 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3015 sinfo |= SFPF_DUAL_FIRE;
3018 if ( aip->current_target_is_locked ){
3019 sinfo |= SFPF_TARGET_LOCKED;
3024 // add the ship's target and any targeted subsystem
3025 target_signature = 0;
3027 if ( aip->target_objnum != -1) {
3028 target_signature = Objects[aip->target_objnum].net_signature;
3029 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3032 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3033 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
3034 t_subsys = (char)s_index;
3037 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3038 Assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3043 ADD_DATA_U16( target_signature );
3044 ADD_DATA( t_subsys );
3046 // just send this packet to everyone, then bail if an AI ship fired.
3047 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3048 multi_io_send_to_all(data, packet_size);
3052 net_player_num = multi_find_player_by_object( objp );
3054 // getting here means a player fired. Send the current packet to all players except the player
3055 // who fired. If nothing got fired, then don't send to the other players -- we will just send
3056 // a packet to the player who will find out that he didn't fire anything
3057 if ( num_fired > 0 ) {
3058 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3061 // if I (the master) fired, then return
3062 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3066 // now build up the packet to send to the player who actually fired.
3067 BUILD_HEADER( SECONDARY_FIRED_PLR );
3068 ADD_DATA_U16(starting_sig);
3071 // add the targeting information so that the player's weapons will always home on the correct
3073 ADD_DATA_U16( target_signature );
3074 ADD_DATA( t_subsys );
3076 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3079 /// process a packet indicating a secondary weapon was fired
3080 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3082 int offset, allow_swarm, target_objnum_save;
3083 ushort net_signature, starting_sig, target_signature;
3084 ubyte sinfo, current_bank;
3085 object* objp, *target_objp;
3089 ship_subsys *targeted_subsys_save;
3091 offset = HEADER_LENGTH; // size of the header
3093 // if from_player is false, it means that the secondary weapon info in this packet was
3094 // fired by an ai object (or another player). from_player == 1 means tha me (the person
3095 // receiving this packet) fired the secondary weapon
3096 if ( !from_player ) {
3097 GET_DATA_U16( net_signature );
3098 GET_DATA_U16( starting_sig );
3099 GET_DATA( sinfo ); // are we firing swarm missiles
3101 GET_DATA_U16( target_signature );
3102 GET_DATA( t_subsys );
3106 // find the object (based on network signatures) for the object that fired
3107 objp = multi_get_network_object( net_signature );
3108 if ( objp == NULL ) {
3109 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3113 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3114 // of the next fire time of this bank to 0 so we can fire right away
3115 shipp = &Ships[objp->instance];
3118 GET_DATA_U16( starting_sig );
3121 GET_DATA_U16( target_signature );
3122 GET_DATA( t_subsys );
3126 // get the object and ship
3128 shipp = Player_ship;
3131 // check the allow swarm bit
3133 if ( sinfo & SFPF_ALLOW_SWARM ){
3137 // set the dual fire properties of the ship
3138 if ( sinfo & SFPF_DUAL_FIRE ){
3139 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3141 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3144 // determine whether current target is locked
3145 Assert( shipp->ai_index != -1 );
3146 aip = &Ai_info[shipp->ai_index];
3147 if ( sinfo & SFPF_TARGET_LOCKED ) {
3148 aip->current_target_is_locked = 1;
3150 aip->current_target_is_locked = 0;
3153 // find out the current bank
3154 current_bank = (ubyte)(sinfo & 0x3);
3155 Assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );
3156 shipp->weapons.current_secondary_bank = current_bank;
3158 // make it so we can fire this ship's secondary bank immediately!!!
3159 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3160 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3162 // set this ship's target and subsystem information. We will save and restore target and
3163 // targeted subsystem so that we do not accidentally change targets for this player or
3164 // any AI ships on his system.
3165 target_objnum_save = aip->target_objnum;
3166 targeted_subsys_save = aip->targeted_subsys;
3168 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3169 aip->target_objnum = -1;
3170 aip->targeted_subsys = NULL;
3172 target_objp = multi_get_network_object( target_signature );
3173 if ( target_objp != NULL ) {
3174 aip->target_objnum = OBJ_INDEX(target_objp);
3176 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3177 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3181 if ( starting_sig != 0 ){
3182 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3184 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3187 ship_fire_secondary( objp, allow_swarm );
3189 // restore targeted object and targeted subsystem
3190 aip->target_objnum = target_objnum_save;
3191 aip->targeted_subsys = targeted_subsys_save;
3194 // send a packet indicating a countermeasure was fired
3195 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3197 ubyte data[MAX_PACKET_SIZE];
3202 Assert ( cmeasure_count < UCHAR_MAX );
3203 BUILD_HEADER(COUNTERMEASURE_FIRED);
3204 ADD_DATA_U16( objp->net_signature );
3205 ADD_DATA_S32( rand_val );
3207 multi_io_send_to_all(data, packet_size);
3210 // process a packet indicating a countermeasure was fired
3211 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3213 int offset, rand_val;
3219 offset = HEADER_LENGTH;
3221 GET_DATA_U16( signature );
3222 GET_DATA_S32( rand_val );
3225 objp = multi_get_network_object( signature );
3226 if ( objp == NULL ) {
3227 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3230 if(objp->type != OBJ_SHIP){
3233 // Assert ( objp->type == OBJ_SHIP );
3235 // make it so ship can fire right away!
3236 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3237 if ( objp == Player_obj ){
3238 nprintf(("network", "firing countermeasure from my ship\n"));
3241 ship_launch_countermeasure( objp, rand_val );
3244 // send a packet indicating that a turret has been fired
3245 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3248 ushort pnet_signature;
3249 ubyte data[MAX_PACKET_SIZE], cindex;
3256 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3260 // local setup -- be sure we are actually passing a weapon!!!!
3261 objp = &Objects[weapon_objnum];
3262 Assert ( objp->type == OBJ_WEAPON );
3263 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3267 pnet_signature = Objects[ship_objnum].net_signature;
3269 Assert( subsys_index < UCHAR_MAX );
3270 cindex = (ubyte)subsys_index;
3272 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3277 // build the fire turret packet.
3278 BUILD_HEADER(FIRE_TURRET_WEAPON);
3279 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3280 ADD_DATA( has_sig );
3281 ADD_DATA_U16( pnet_signature );
3283 ADD_DATA_U16( objp->net_signature );
3286 val = (short)ssp->submodel_info_1.angs.h;
3287 ADD_DATA_S16( val );
3288 val = (short)ssp->submodel_info_2.angs.p;
3289 ADD_DATA_S16( val );
3291 multi_io_send_to_all(data, packet_size);
3293 multi_rate_add(1, "tur", packet_size);
3296 // process a packet indicating a turret has been fired
3297 void process_turret_fired_packet( ubyte *data, header *hinfo )
3299 int offset, weapon_objnum, wid;
3300 ushort pnet_signature, wnet_signature;
3309 short pitch, heading;
3311 // get the data for the turret fired packet
3312 offset = HEADER_LENGTH;
3313 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3314 GET_DATA( has_sig );
3315 GET_DATA_U16( pnet_signature );
3317 GET_DATA_U16( wnet_signature );
3321 GET_DATA( turret_index );
3322 GET_DATA_S16( heading );
3323 GET_DATA_S16( pitch );
3324 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3327 objp = multi_get_network_object( pnet_signature );
3328 if ( objp == NULL ) {
3329 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3333 // if this isn't a ship, do nothing
3334 if ( objp->type != OBJ_SHIP ){
3338 // make an orientation matrix from the o_fvec
3339 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3341 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3342 // hack, but should be suitable.
3343 shipp = &Ships[objp->instance];
3344 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3348 wid = ssp->system_info->turret_weapon_type;
3350 // bash the position and orientation of the turret
3351 ssp->submodel_info_1.angs.h = (float)heading;
3352 ssp->submodel_info_2.angs.p = (float)pitch;
3354 // get the world position of the weapon
3355 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3357 // create the weapon object
3358 if(wnet_signature != 0){
3359 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3361 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3362 if (weapon_objnum != -1) {
3363 if ( Weapon_info[wid].launch_snd != -1 ) {
3364 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3369 // send a mission log item packet
3370 void send_mission_log_packet( int num )
3373 ubyte data[MAX_PACKET_SIZE];
3378 Assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3380 // get the data from the log
3381 entry = &log_entries[num];
3382 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3383 sindex = (ushort)entry->index;
3385 BUILD_HEADER(MISSION_LOG_ENTRY);
3387 ADD_DATA_S32(entry->flags);
3388 ADD_DATA_U16(sindex);
3389 ADD_DATA(entry->timestamp);
3390 ADD_STRING(entry->pname);
3391 ADD_STRING(entry->sname);
3393 // broadcast the packet to all players
3394 multi_io_send_to_all_reliable(data, packet_size);
3397 // process a mission log item packet
3398 void process_mission_log_packet( ubyte *data, header *hinfo )
3403 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3406 Assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3408 offset = HEADER_LENGTH;
3410 GET_DATA_S32(flags);
3411 GET_DATA_U16(sindex);
3412 GET_DATA(timestamp);
3418 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3421 // send a mission message packet
3422 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)
3425 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3427 Assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3428 Assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3429 Assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3431 up = (ubyte) priority;
3432 us = (ubyte) source;
3433 utime = (ubyte)timing;
3435 BUILD_HEADER(MISSION_MESSAGE);
3437 ADD_STRING(who_from);
3441 ADD_DATA_S32(builtin_type);
3442 ADD_DATA_S32(multi_team_filter);
3444 if (multi_target == -1){
3445 multi_io_send_to_all_reliable(data, packet_size);
3447 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3451 // process a mission message packet
3452 void process_mission_message_packet( ubyte *data, header *hinfo )
3454 int offset, id, builtin_type;
3455 ubyte priority, source, utiming;
3456 char who_from[NAME_LENGTH];
3457 int multi_team_filter;
3459 Assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3461 offset = HEADER_LENGTH;
3463 GET_STRING(who_from);
3467 GET_DATA_S32(builtin_type);
3468 GET_DATA_S32(multi_team_filter);
3472 // filter out builtin ones in TvT
3473 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3477 // maybe filter this out
3478 if(!message_filter_multi(id)){
3479 // send the message as if it came from an sexpression
3480 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3484 // just send them a pong back as fast as possible
3485 void process_ping_packet(ubyte *data, header *hinfo)
3490 offset = HEADER_LENGTH;
3493 // get the address to return the pong to
3494 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3500 // right now it just routes the pong through to the standalone gui, which is the only
3501 // system which uses ping and pong right now.
3502 void process_pong_packet(ubyte *data, header *hinfo)
3508 offset = HEADER_LENGTH;
3510 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3514 // if we're connected , see who sent us this pong
3515 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3516 lookup = find_player_id(hinfo->id);
3521 p = &Net_players[lookup];
3523 // evaluate the ping
3524 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3526 // put in calls to any functions which may want to know about the ping times from
3528 if(Game_mode & GM_STANDALONE_SERVER){
3529 std_update_player_ping(p);
3532 // mark his socket as still alive (extra precaution)
3533 psnet_mark_received(Net_players[lookup].reliable_socket);
3535 // otherwise, do any special processing
3537 // if we're in the join game state, see if this pong came from a server on our
3539 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3540 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3545 // send a ping packet
3546 void send_ping(net_addr *addr)
3548 unsigned char data[8];
3551 // build the header and send the packet
3552 BUILD_HEADER( PING );
3553 psnet_send(addr, &data[0], packet_size);
3556 // send a pong packet
3557 void send_pong(net_addr *addr)
3559 unsigned char data[8];
3562 // build the header and send the packet
3564 psnet_send(addr, &data[0], packet_size);
3567 // sent from host to master. give me the list of missions you have.
3568 // this will be used only in a standalone mode
3569 void send_mission_list_request( int what )
3571 ubyte data[MAX_PACKET_SIZE];
3574 // build the header and ask for a list of missions or campaigns (depending
3575 // on the 'what' flag).
3576 BUILD_HEADER(MISSION_REQUEST);
3578 multi_io_send_reliable(Net_player, data, packet_size);
3581 // maximum number of bytes that we can send in a mission items packet.
3582 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3584 // defines used to tell what type of packets are being sent
3585 #define MISSION_LIST_ITEMS 1
3586 #define CAMPAIGN_LIST_ITEMS 2
3588 // send an individual mission file item
3589 void send_mission_items( net_player *pl )
3591 ubyte data[MAX_PACKET_SIZE];
3596 BUILD_HEADER(MISSION_ITEM);
3598 // send the list of missions and campaigns avilable on the server. Stop when
3599 // reaching a certain maximum
3600 type = MISSION_LIST_ITEMS;
3602 for (i = 0; i < Multi_create_mission_count; i++ ) {
3606 ADD_STRING( Multi_create_mission_list[i].filename );
3607 ADD_STRING( Multi_create_mission_list[i].name );
3608 ADD_DATA_S32( Multi_create_mission_list[i].flags );
3609 ADD_DATA( Multi_create_mission_list[i].max_players );
3610 ADD_DATA_U32( Multi_create_mission_list[i].respawn );
3613 ADD_DATA( Multi_create_mission_list[i].valid_status );
3615 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3618 multi_io_send_reliable(pl, data, packet_size);
3619 BUILD_HEADER( MISSION_ITEM );
3625 multi_io_send_reliable(pl, data, packet_size);
3627 // send the campaign information
3628 type = CAMPAIGN_LIST_ITEMS;
3629 BUILD_HEADER(MISSION_ITEM);
3631 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3635 ADD_STRING( Multi_create_campaign_list[i].filename );
3636 ADD_STRING( Multi_create_campaign_list[i].name );
3637 ADD_DATA_S32( Multi_create_campaign_list[i].flags );
3638 ADD_DATA( Multi_create_campaign_list[i].max_players );
3640 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3643 multi_io_send_reliable(pl, data, packet_size);
3644 BUILD_HEADER( MISSION_ITEM );
3650 multi_io_send_reliable(pl, data, packet_size);
3653 // process a request for a list of missions
3654 void process_mission_request_packet(ubyte *data, header *hinfo)
3656 int player_num,offset;
3658 offset = HEADER_LENGTH;
3661 // fill in the address information of where this came from
3662 player_num = find_player_id(hinfo->id);
3663 if(player_num == -1){
3664 nprintf(("Network","Could not find player to send mission list items to!\n"));
3668 send_mission_items( &Net_players[player_num] );
3671 // process an individual mission file item
3672 void process_mission_item_packet(ubyte *data,header *hinfo)
3675 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3676 ubyte stop, type,max_players;
3679 Assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3680 offset = HEADER_LENGTH;
3685 GET_STRING( filename );
3687 GET_DATA_S32( flags );
3688 GET_DATA( max_players );
3690 // missions also have respawns and a crc32 associated with them
3691 if(type == MISSION_LIST_ITEMS){
3692 GET_DATA_U32(respawn);
3695 GET_DATA(valid_status);
3697 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3698 strcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename );
3699 strcpy(Multi_create_mission_list[Multi_create_mission_count].name, name );
3700 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3701 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3702 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3705 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3707 Multi_create_mission_count++;
3709 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3710 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3711 strcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename );
3712 strcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name );
3713 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3714 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3715 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3716 Multi_create_campaign_count++;
3725 // this will cause whatever list to get resorted (although they should be appearing in order)
3726 multi_create_setup_list_data(-1);
3729 // send a request to the server to pause or unpause the game
3730 void send_multi_pause_packet(int pause)
3732 ubyte data[MAX_PACKET_SIZE];
3734 int packet_size = 0;
3736 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3739 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3740 val = (ubyte) pause;
3742 // add the pause info
3745 // send the request to the server
3746 multi_io_send_reliable(Net_player, data, packet_size);
3749 // process a pause update packet (pause, unpause, etc)
3750 void process_multi_pause_packet(ubyte *data, header *hinfo)
3756 offset = HEADER_LENGTH;
3762 // get who sent the packet
3763 player_index = find_player_id(hinfo->id);
3764 // if we don't know who sent the packet, don't do anything
3765 if(player_index == -1){
3769 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3770 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3773 // send a game information update
3774 void send_game_info_packet()
3777 ubyte data[MAX_PACKET_SIZE], paused;
3779 // set the paused variable
3780 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3782 BUILD_HEADER(GAME_INFO);
3783 ADD_DATA_S32( Missiontime );
3786 multi_io_send_to_all(data, packet_size);
3789 // process a game information update
3790 void process_game_info_packet( ubyte *data, header *hinfo )
3796 offset = HEADER_LENGTH;
3798 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3799 // time, set our time to server time (should take ping time into account!!!)
3800 GET_DATA( mission_time );
3805 // send an ingame nak packet
3806 void send_ingame_nak(int state, net_player *p)
3808 ubyte data[MAX_PACKET_SIZE];
3811 BUILD_HEADER(INGAME_NAK);
3813 ADD_DATA_S32(state);
3815 multi_io_send_reliable(p, data, packet_size);
3818 // process an ingame nak packet
3819 void process_ingame_nak(ubyte *data, header *hinfo)
3821 int offset,state,pid;
3824 offset = HEADER_LENGTH;
3825 GET_DATA_S32(state);
3828 pid = find_player_id(hinfo->id);
3832 pl = &Net_players[pid];
3835 case ACK_FILE_ACCEPTED :
3836 Assert(Net_player->flags & NETINFO_FLAG_INGAME_JOIN);
3837 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3838 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3843 // send a packet telling players to end the mission
3844 void send_endgame_packet(net_player *pl)
3846 ubyte data[MAX_PACKET_SIZE];
3850 BUILD_HEADER(MISSION_END);
3852 // sending to a specific player?
3854 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3855 multi_io_send_reliable(pl, data, packet_size);
3859 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3860 // send all player stats here
3861 multi_broadcast_stats(STATS_MISSION);
3863 // if in dogfight mode, send all dogfight stats as well
3864 ml_string("Before dogfight stats!");
3865 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3866 ml_string("Sending dogfight stats!");
3868 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3870 ml_string("After dogfight stats!");
3872 // tell everyone to leave the game
3873 multi_io_send_to_all_reliable(data, packet_size);
3875 multi_io_send_reliable(Net_player, data, packet_size);
3879 // process a packet indicating we should end the current mission
3880 void process_endgame_packet(ubyte *data, header *hinfo)
3885 offset = HEADER_LENGTH;
3889 ml_string("Receiving endgame packet");
3891 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3892 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3893 // determine who this came from and make sure he is allowed to end the game
3894 player_num = find_player_id(hinfo->id);
3895 Assert(player_num != -1);
3900 // if the player is allowed to end the mission
3901 if(!multi_can_end_mission(&Net_players[player_num])){
3905 // act as if we hit alt+j locally
3906 multi_handle_end_mission_request();
3908 // all clients process immediately
3910 // ingame joiners should quit when they receive an endgame packet since the game is over
3911 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3912 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3916 // do any special processing for being in a state other than the gameplay state
3917 multi_handle_state_special();
3919 // make sure we're not already in the debrief state
3920 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3921 multi_warpout_all_players();
3926 // send a position/orientation update for myself (if I'm an observer)
3927 void send_observer_update_packet()
3929 ubyte data[MAX_PACKET_SIZE];
3934 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3935 // to send any update packets to anyone.
3936 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3940 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3946 BUILD_HEADER(OBSERVER_UPDATE);
3948 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3950 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3953 // add targeting infomation
3954 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3955 target_sig = Objects[Player_ai->target_objnum].net_signature;
3959 ADD_DATA_U16(target_sig);
3961 multi_io_send(Net_player, data, packet_size);
3964 // process a position/orientation update from an observer
3965 void process_observer_update_packet(ubyte *data, header *hinfo)
3971 physics_info bogus_pi;
3974 offset = HEADER_LENGTH;
3976 obs_num = find_player_id(hinfo->id);
3978 memset(&bogus_pi,0,sizeof(physics_info));
3979 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3981 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3984 // targeting information
3985 GET_DATA_U16(target_sig);
3988 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
3992 // set targeting info
3993 if(target_sig == 0){
3994 Net_players[obs_num].s_info.target_objnum = -1;
3996 target_obj = multi_get_network_object(target_sig);
3997 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4000 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4001 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4002 Net_players[obs_num].s_info.eye_pos = g_vec;
4003 Net_players[obs_num].s_info.eye_orient = g_mat;
4006 void send_netplayer_slot_packet()
4008 ubyte data[MAX_PACKET_SIZE];
4009 int packet_size,idx;
4014 BUILD_HEADER(NETPLAYER_SLOTS_P);
4015 for(idx=0;idx<MAX_PLAYERS;idx++){
4016 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4018 ADD_DATA_S16(Net_players[idx].player_id);
4019 ADD_DATA_U16(Objects[Net_players[idx].player->objnum].net_signature);
4020 ADD_DATA_S32(Net_players[idx].p_info.ship_class);
4021 ADD_DATA_S32(Net_players[idx].p_info.ship_index);
4027 // standalone case or not
4028 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
4029 multi_io_send_to_all_reliable(data, packet_size);
4031 multi_io_send_reliable(Net_player, data, packet_size);
4035 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4038 int player_num,ship_class,ship_index;
4044 offset = HEADER_LENGTH;
4046 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4047 multi_untag_player_ships();
4051 GET_DATA_S16(player_id);
4052 GET_DATA_U16(net_sig);
4053 GET_DATA_S32(ship_class);
4054 GET_DATA_S32(ship_index);
4055 player_num = find_player_id(player_id);
4057 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4059 // call the function in multiutil.cpp to set up the player object stuff
4060 // being careful not to muck with the standalone object
4061 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4062 objp = multi_get_network_object(net_sig);
4063 Assert(objp != NULL);
4064 multi_assign_player_ship( player_num, objp, ship_class );
4065 Net_players[player_num].p_info.ship_index = ship_index;
4066 objp->flags &= ~(OF_COULD_BE_PLAYER);
4067 objp->flags |= OF_PLAYER_SHIP;
4074 // standalone should forward the packet and wait for a response
4075 if(Game_mode & GM_STANDALONE_SERVER){
4076 send_netplayer_slot_packet();
4079 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4080 send_netplayer_update_packet();
4083 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4084 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4085 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4086 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4088 ubyte data[MAX_PACKET_SIZE], utmp;
4091 BUILD_HEADER(SHIP_WSTATE_CHANGE);
4092 ADD_DATA_U16( Objects[shipp->objnum].net_signature );
4093 utmp = (ubyte)(what);
4095 utmp = (ubyte)(new_bank);
4097 utmp = (ubyte)(link_status);
4100 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4101 multi_io_send_to_all_reliable(data, packet_size);
4104 void process_ship_weapon_change( ubyte *data, header *hinfo )
4108 ubyte what, new_bank, link_status;
4112 offset = HEADER_LENGTH;
4113 GET_DATA_U16( signature );
4115 GET_DATA( new_bank );
4116 GET_DATA( link_status );
4119 objp = multi_get_network_object( signature );
4120 if ( objp == NULL ) {
4121 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4124 // Assert( objp->type == OBJ_SHIP );
4125 if(objp->type != OBJ_SHIP){
4129 // if this is my data, do nothing since I already have my own data
4130 if ( objp == Player_obj ){
4134 // now, get the ship and set the new bank and link modes based on the 'what' value
4135 shipp = &Ships[objp->instance];
4136 if ( what == MULTI_PRIMARY_CHANGED ) {
4137 shipp->weapons.current_primary_bank = new_bank;
4139 shipp->flags |= SF_PRIMARY_LINKED;
4141 shipp->flags &= ~SF_PRIMARY_LINKED;
4144 shipp->weapons.current_secondary_bank = new_bank;
4146 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4148 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4153 // ship status change procedure
4154 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4156 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4157 // for added redundancy.
4158 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4159 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4160 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4161 // back to the client. Also sends multiple times for redundancy
4162 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4163 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4164 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4166 #define SHIP_STATUS_REPEAT 2
4167 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4170 ubyte data[MAX_PACKET_SIZE];
4171 int packet_size = 0;
4177 BUILD_HEADER(SHIP_STATUS_CHANGE);
4179 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4180 temp = bi->status[idx];
4184 // server should send reliably (response packet)
4185 if(MULTIPLAYER_MASTER){
4186 multi_io_send_reliable(pl, data, packet_size);
4188 multi_io_send(pl, data, packet_size);
4192 void process_ship_status_packet(ubyte *data, header *hinfo)
4196 int player_num,unique_id;
4200 offset = HEADER_LENGTH;
4202 // zero out the button info structure for good measure
4203 memset(&bi,0,sizeof(button_info));
4205 // read the button-info
4206 GET_DATA_S32(unique_id);
4208 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4209 GET_DATA_S32(i_tmp);
4210 bi.status[idx] = i_tmp;
4215 // this will be handled differently client and server side. Duh.
4216 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4217 // find which net-player has sent us butotn information
4218 player_num = find_player_id(hinfo->id);
4219 Assert(player_num >= 0);
4224 // don't process critical button information for observers
4225 // its a new button_info for this guy. apply and ack
4226 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4227 // mark that he's pressed this button
4228 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4230 // send a return packet
4231 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4233 // apply the button presses to his ship as normal
4234 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4236 // else ignore it as a repeat from the same guy
4237 } else { // CLIENT SIDE
4238 // this is the return from the server, so we should now apply them locally
4239 // if(lookup_ship_status(Net_player,unique_id,1)){
4240 multi_apply_ship_status(Net_player, &bi, 1);
4245 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4246 // for clients. Left all details to this function instead of higher level messaging
4248 void send_player_order_packet(int type, int index, int cmd)
4250 ubyte data[MAX_PACKET_SIZE];
4252 ushort target_signature;
4254 int packet_size = 0;
4256 BUILD_HEADER(PLAYER_ORDER_PACKET);
4259 ADD_DATA(val); // ship order or wing order, or message all fighters
4261 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4262 if ( val != SQUAD_MSG_ALL ){
4263 ADD_DATA_S32(index); // net signature of target ship
4266 ADD_DATA_S32(cmd); // the command itself
4269 target_signature = 0;
4270 if ( Player_ai->target_objnum != -1 ){
4271 target_signature = Objects[Player_ai->target_objnum].net_signature;
4274 ADD_DATA_U16( target_signature );
4277 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4280 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4281 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
4282 t_subsys = (char)s_index;
4286 multi_io_send_reliable(Net_player, data, packet_size);
4289 // brief explanation :
4290 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4291 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4292 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4293 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4294 void process_player_order_packet(ubyte *data, header *hinfo)
4296 int offset, player_num, command, index = 0, tobjnum_save;
4297 ushort target_signature;
4298 char t_subsys, type;
4299 object *objp, *target_objp;
4302 ship_subsys *tsubsys_save, *targeted_subsys;
4304 Assert(MULTIPLAYER_MASTER);
4306 // packet values - its easier to read all of these in first
4308 offset = HEADER_LENGTH;
4311 if ( type != SQUAD_MSG_ALL ){
4312 GET_DATA_S32( index );
4315 GET_DATA_S32( command );
4316 GET_DATA_U16( target_signature );
4317 GET_DATA( t_subsys );
4321 player_num = find_player_id(hinfo->id);
4322 if(player_num == -1){
4323 nprintf(("Network","Received player order packet from unknown player\n"));
4327 objp = &Objects[Net_players[player_num].player->objnum];
4328 if ( objp->type != OBJ_SHIP ) {
4329 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4333 // HACK HACK HACK HACK HACK HACK
4334 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4335 // the data is BOGUS. All people should be able to to these things as well.
4336 if(command == REARM_REPAIR_ME_ITEM){
4337 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4339 } else if(command == ABORT_REARM_REPAIR_ITEM){
4340 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4344 // if this player is not allowed to do messaging, quit here
4345 if( !multi_can_message(&Net_players[player_num]) ){
4346 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4350 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4351 // then call them in.
4352 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4353 Assert( (index >= 0) && (index < Num_reinforcements) );
4354 hud_squadmsg_call_reinforcement(index, player_num);
4358 // set the player's ai information here
4359 shipp = &Ships[objp->instance];
4360 aip = &Ai_info[shipp->ai_index];
4362 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4363 target_objp = multi_get_network_object( target_signature );
4364 if ( target_objp == NULL ) {
4368 targeted_subsys = NULL;
4369 if ( t_subsys != -1 ) {
4370 Assert( target_objp != NULL );
4371 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4374 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4376 tobjnum_save = aip->target_objnum;
4377 tsubsys_save = aip->targeted_subsys;
4379 if ( target_objp ) {
4380 aip->target_objnum = OBJ_INDEX(target_objp);
4382 aip->target_objnum = -1;
4385 aip->targeted_subsys = targeted_subsys;
4387 if ( type == SQUAD_MSG_SHIP ) {
4388 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4389 } else if ( type == SQUAD_MSG_WING ) {
4390 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4391 } else if ( type == SQUAD_MSG_ALL ) {
4392 hud_squadmsg_send_to_all_fighters( command, player_num );
4395 Assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4396 aip->target_objnum = tobjnum_save;
4397 aip->targeted_subsys = tsubsys_save;
4400 // FILE SIGNATURE stuff :
4401 // there are 2 cases for file signature sending which are handled very differently
4402 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4403 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4404 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4405 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4406 // would have to keep track of up to potentially 14 other ack handles (ouch).
4407 void send_file_sig_packet(ushort sum_sig,int length_sig)
4409 ubyte data[MAX_PACKET_SIZE];
4410 int packet_size = 0;
4412 BUILD_HEADER(FILE_SIG_INFO);
4413 ADD_DATA_U16(sum_sig);
4414 ADD_DATA_S16(length_sig);
4416 multi_io_send_reliable(Net_player, data, packet_size);
4419 void process_file_sig_packet(ubyte *data, header *hinfo)
4424 offset = HEADER_LENGTH;
4426 // should only be received on the server-side
4427 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4429 GET_DATA_U16(sum_sig);
4430 GET_DATA_S32(length_sig);
4432 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4435 void send_file_sig_request(char *file_name)
4437 ubyte data[MAX_PACKET_SIZE];
4438 int packet_size = 0;
4440 BUILD_HEADER(FILE_SIG_REQUEST);
4441 ADD_STRING(file_name);
4443 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4445 multi_io_send_to_all_reliable(data, packet_size);
4448 void process_file_sig_request(ubyte *data, header *hinfo)
4450 int offset = HEADER_LENGTH;
4452 // get the mission name
4453 GET_STRING(Netgame.mission_name);
4456 // set the current mission filename
4457 strcpy(Game_current_mission_filename,Netgame.mission_name);
4460 multi_get_mission_checksum(Game_current_mission_filename);
4462 if(!multi_endgame_ending()){
4463 // reply to the server
4464 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4468 // functions to deal with subsystems getting whacked
4469 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4471 ubyte data[MAX_PACKET_SIZE];
4474 vector tmp, local_hitpos;
4477 Assert ( index < UCHAR_MAX );
4478 uindex = (ubyte)(index);
4480 objp = &Objects[shipp->objnum];
4482 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4483 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4485 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4486 ADD_DATA_U16( Objects[shipp->objnum].net_signature );
4488 // ADD_DATA( local_hitpos );
4489 add_vector_data(data, &packet_size, local_hitpos);
4491 multi_io_send_to_all_reliable(data, packet_size);
4494 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4500 vector local_hit_pos, world_hit_pos;
4502 offset = HEADER_LENGTH;
4504 GET_DATA_U16( signature );
4506 // GET_DATA( local_hit_pos );
4507 get_vector_data(data, &offset, local_hit_pos);
4509 // get the network object. process it if we find it.
4510 objp = multi_get_network_object( signature );
4511 if ( objp != NULL ) {
4513 ship_subsys *subsysp;
4515 // be sure we have a ship!!!
4516 // Assert ( objp->type == OBJ_SHIP );
4517 if(objp->type != OBJ_SHIP){
4522 shipp = &Ships[objp->instance];
4524 // call to get the pointer to the subsystem we should be working on
4525 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4526 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4527 vm_vec_add2( &world_hit_pos, &objp->pos );
4529 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4530 if ( objp == Player_obj ) {
4531 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4539 // packet to tell clients cargo of a ship was revealed to all
4540 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4542 ubyte data[MAX_PACKET_SIZE], uindex;
4545 Assert ( index < UCHAR_MAX );
4546 uindex = (ubyte)(index);
4548 // build the header and add the data
4549 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4550 ADD_DATA_U16( Objects[shipp->objnum].net_signature );
4553 // server sends to all players
4554 if(MULTIPLAYER_MASTER){
4555 multi_io_send_to_all_reliable(data, packet_size);
4557 // clients just send to the server
4559 multi_io_send_reliable(Net_player, data, packet_size);
4563 // process a subsystem cargo revealed packet
4564 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4571 ship_subsys *subsysp;
4573 offset = HEADER_LENGTH;
4574 GET_DATA_U16( signature );
4578 // get a ship pointer and call the ship function to reveal the cargo
4579 objp = multi_get_network_object( signature );
4580 if ( objp == NULL ) {
4581 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4585 // Assert( objp->type == OBJ_SHIP );
4586 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4590 shipp = &Ships[objp->instance];
4592 // call to get the pointer to the subsystem we should be working on
4593 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4594 if (subsysp == NULL) {
4595 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4599 // this will take care of re-routing to all other clients
4600 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4601 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4603 // server should rebroadcast
4604 if(MULTIPLAYER_MASTER){
4605 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4609 void send_netplayer_load_packet(net_player *pl)
4611 ubyte data[MAX_PACKET_SIZE];
4612 int packet_size = 0;
4614 BUILD_HEADER(LOAD_MISSION_NOW);
4615 ADD_STRING(Netgame.mission_name);
4618 multi_io_send_to_all_reliable(data, packet_size);
4620 multi_io_send_reliable(pl, data, packet_size);
4624 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4627 int offset = HEADER_LENGTH;
4632 strcpy(Netgame.mission_name,str);
4633 strcpy(Game_current_mission_filename,str);
4634 if(!Multi_mission_loaded){
4636 // MWA 2/3/98 -- ingame join changes!!!
4637 // everyone can go through the same mission loading path here!!!!
4638 nprintf(("Network","Loading mission..."));
4640 // notify everyone that I'm loading the mission
4641 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4642 send_netplayer_update_packet();
4644 // do the load itself
4645 game_start_mission();
4647 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4648 // code will remark the correct player ships
4649 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4650 multi_untag_player_ships();
4653 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4654 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4655 send_netplayer_update_packet();
4657 Multi_mission_loaded = 1;
4658 nprintf(("Network","Finished loading mission\n"));
4662 void send_jump_into_mission_packet(net_player *pl)
4664 ubyte data[MAX_PACKET_SIZE];
4665 int packet_size = 0;
4667 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4669 BUILD_HEADER(JUMP_INTO_GAME);
4671 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4672 // and possible other things.
4674 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4675 ADD_DATA_S32(Netgame.game_state);
4681 multi_io_send_to_all_reliable(data, packet_size);
4683 // send to a specific player
4685 multi_io_send_reliable(pl, data, packet_size);
4689 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4691 int offset = HEADER_LENGTH;
4696 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4697 // the game could be paused, so ingame joiner needs to deal with it.
4698 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4699 GET_DATA_S32( state );
4700 Netgame.game_state = state;
4705 // handle any special processing for being in a weird substate
4706 multi_handle_state_special();
4708 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4709 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4710 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4711 multi_ingame_observer_finish();
4713 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4714 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4715 send_netplayer_update_packet();
4718 // start the mission!!
4719 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4720 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4721 gameseq_post_event(GS_EVENT_ENTER_GAME);
4722 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4723 send_netplayer_update_packet();
4727 extern int Player_multi_died_check;
4728 Player_multi_died_check = -1;
4730 // recalc all object pairs now
4731 extern void obj_reset_all_collisions();
4732 obj_reset_all_collisions();
4734 // display some cool text
4735 multi_common_add_text(XSTR("Received mission start\n",720),1);
4738 ml_string(NOX("Client received mission start from server - entering mission"));
4743 char *repair_text[] = {
4745 "REPAIR_INFO_BEGIN",
4747 "REPAIR_INFO_UPDATE",
4748 "REPAIR_INFO_QUEUE",
4749 "REPAIR_INFO_ABORT",
4750 "REPAIR_INFO_BROKEN",
4751 "REPAIR_INFO_WARP_ADD",
4752 "REPAIR_INFO_WARP_REMOVE",
4753 "REPAIR_INFO_ONWAY",
4754 "REPAIR_INFO_KILLED",
4755 "REPAIR_INFO_COMPLETE",
4760 // the following two routines deal with updating and sending information regarding players
4761 // rearming and repairing during the game. The process function calls the routines to deal with
4762 // setting flags and other interesting things.
4763 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4765 int packet_size = 0;
4766 ushort repaired_signature, repair_signature;
4767 ubyte data[MAX_PACKET_SIZE];
4770 // use the network signature of the destination object if there is one, -1 otherwise.
4771 // client will piece it all together
4772 repaired_signature = repaired_objp->net_signature;
4774 // the repair ship may be NULL here since it might have been destroyed
4775 repair_signature = 0;
4777 repair_signature = repair_objp->net_signature;
4780 BUILD_HEADER(CLIENT_REPAIR_INFO);
4783 ADD_DATA_U16( repaired_signature );
4784 ADD_DATA_U16( repair_signature );
4786 multi_io_send_to_all_reliable(data, packet_size);
4788 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));
4791 void process_repair_info_packet(ubyte *data, header *hinfo)
4793 int offset = HEADER_LENGTH;
4794 ushort repaired_signature, repair_signature;
4795 object *repaired_objp, *repair_objp;
4799 GET_DATA_U16( repaired_signature );
4800 GET_DATA_U16( repair_signature );
4803 repaired_objp = multi_get_network_object( repaired_signature );
4804 repair_objp = multi_get_network_object( repair_signature );
4806 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));
4808 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4812 if ( repaired_objp == NULL ) {
4813 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4817 // the hope is to simply call the routine in the ai code to set/unset flags
4818 // based on the code value and everything else should happen..I hope....
4819 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4821 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4823 // set the dock flags when repair begins. Prevents problem in lagging docking
4824 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4826 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4827 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4828 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4831 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4833 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4834 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4837 if ( code == REPAIR_INFO_WARP_ADD ){
4838 mission_warp_in_support_ship( repaired_objp );
4840 mission_remove_scheduled_repair( repaired_objp );
4845 // sends information updating clients on certain AI information that clients will
4846 // need to know about to keep HUD information up to date. objp is the object that we
4847 // are updating, and what is the type of stuff that we are updating.
4848 void send_ai_info_update_packet( object *objp, char what )
4851 ushort other_signature;
4852 ubyte data[MAX_PACKET_SIZE];
4854 ubyte dock_index, dockee_index;
4856 // Assert( objp->type == OBJ_SHIP );
4857 if(objp->type != OBJ_SHIP){
4860 aip = &Ai_info[Ships[objp->instance].ai_index];
4863 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4866 BUILD_HEADER( AI_INFO_UPDATE );
4867 ADD_DATA_U16( objp->net_signature );
4870 // depending on the "what" value, we will send different information
4874 case AI_UPDATE_DOCK:
4875 // for docking ships, add the signature of the ship that we are docking with.
4876 Assert( aip->dock_objnum != -1 );
4877 other_signature = Objects[aip->dock_objnum].net_signature;
4878 dock_index = (ubyte)(aip->dock_index);
4879 dockee_index = (ubyte)(aip->dockee_index);
4880 ADD_DATA_U16( other_signature );
4881 ADD_DATA(dock_index);
4882 ADD_DATA(dockee_index);
4885 case AI_UPDATE_UNDOCK:
4886 // for undocking ships, check the dock_objnum since we might or might not have it
4887 // depending on whether or not a ship was destroyed while we were docked.
4888 other_signature = 0;
4889 if ( aip->dock_objnum != -1 )
4890 other_signature = Objects[aip->dock_objnum].net_signature;
4891 ADD_DATA_U16( other_signature );
4895 case AI_UPDATE_ORDERS: {
4898 // for orders, we only need to send a little bit of information here. Be sure that the
4899 // first order for this ship is active
4900 Assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4901 ADD_DATA_S32( aip->goals[0].ai_mode );
4902 ADD_DATA_S32( aip->goals[0].ai_submode );
4904 if ( aip->goals[0].ship_name != NULL )
4905 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4907 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4908 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4909 if ( shipnum != -1 ) {
4910 Assert( Ships[shipnum].objnum != -1 );
4911 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4913 other_signature = 0;
4915 ADD_DATA_U16( other_signature );
4917 // for docking, add the dock and dockee index
4918 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4919 Assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4920 Assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4921 dock_index = (ubyte)aip->goals[0].docker.index;
4922 dockee_index = (ubyte)aip->goals[0].dockee.index;
4923 ADD_DATA( dock_index );
4924 ADD_DATA( dockee_index );
4933 multi_rate_add(1, "aiu", packet_size);
4934 multi_io_send_to_all_reliable(data, packet_size);
4937 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4938 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4939 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4941 int offset = HEADER_LENGTH;
4943 ushort net_signature, other_net_signature;
4944 object *objp, *other_objp;
4947 ubyte dock_index = 0, dockee_index = 0;
4949 GET_DATA_U16( net_signature ); // signature of the object that we are dealing with.
4950 GET_DATA( code ); // code of what we are doing.
4951 objp = multi_get_network_object( net_signature );
4953 nprintf(("Network", "Couldn't find object for ai update\n"));
4956 case AI_UPDATE_DOCK:
4957 GET_DATA_U16( other_net_signature );
4958 GET_DATA( dock_index );
4959 GET_DATA( dockee_index );
4960 other_objp = multi_get_network_object( other_net_signature );
4962 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4964 // if we don't have an object to work with, break out of loop
4965 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4969 Assert( other_objp->type == OBJ_SHIP );
4970 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4971 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4973 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4974 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4976 ai_do_objects_docked_stuff( objp, other_objp );
4979 case AI_UPDATE_UNDOCK:
4980 GET_DATA_U16( other_net_signature );
4981 other_objp = multi_get_network_object( other_net_signature );
4983 // if we don't have an object to work with, break out of loop
4987 ai_do_objects_undocked_stuff( objp, other_objp );
4990 case AI_UPDATE_ORDERS:
4991 GET_DATA_S32( mode );
4992 GET_DATA_S32( submode );
4993 GET_DATA_U16( other_net_signature );
4994 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4995 GET_DATA(dock_index);
4996 GET_DATA(dockee_index);
4999 // be sure that we have a ship object!!!
5000 if ( !objp || (objp->type != OBJ_SHIP) )
5003 // set up the information in the first goal element of the object in question
5004 aip = &Ai_info[Ships[objp->instance].ai_index];
5005 aip->active_goal = 0;
5006 aip->goals[0].ai_mode = mode;
5007 aip->goals[0].ai_submode = submode;
5009 // for docking, add the dock and dockee index
5010 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5011 aip->dock_index = dock_index;
5012 aip->dockee_index = dockee_index;
5015 // get a shipname if we can.
5016 other_objp = multi_get_network_object( other_net_signature );
5017 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5018 // get a pointer to the shipname in question. Use the ship_name value in the
5019 // ship. We are only using this for HUD display, so I think that using this
5020 // method will be fine.
5021 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5023 // special case for destroy subsystem -- get the ai_info pointer to our target ship
5024 // so that we can properly set up what subsystem this ship is attacking.
5025 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5026 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5028 // if docking -- set the dock index and dockee index of this other ship
5029 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5030 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5031 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5038 Int3(); // this Int3() should be temporary
5039 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5045 // tell the standalone to move into the MISSION_SYNC_STATE
5046 void send_mission_sync_packet(int mode,int start_campaign)
5048 ubyte data[MAX_PACKET_SIZE],is_campaign;
5049 int packet_size = 0;
5051 Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5053 // build the header and add the sync mode (pre or post briefing)
5054 BUILD_HEADER(MISSION_SYNC_DATA);
5057 // if this is a campaign game
5058 if(mode == MULTI_SYNC_PRE_BRIEFING){
5059 if(Game_mode & GM_CAMPAIGN_MODE){
5060 // add a byte indicating campaign mode
5062 ADD_DATA(is_campaign);
5064 // add a byte indicating if we should be starting a campaign or continuing it
5065 is_campaign = (ubyte)start_campaign;
5066 ADD_DATA(is_campaign);
5068 // add the campaign filename
5069 ADD_STRING(Netgame.campaign_name);
5071 // otherwise if this is a single mission
5073 // add a byte indicating single mission mode
5075 ADD_DATA(is_campaign);
5077 // add the mission filename
5078 ADD_STRING(Game_current_mission_filename);
5081 multi_io_send_reliable(Net_player, data, packet_size);
5084 // move into the MISSION_SYNC state when this is received
5085 // this packet is sent only from a game host to a standalone
5086 void process_mission_sync_packet(ubyte *data, header *hinfo)
5089 ubyte campaign_flag;
5090 int offset = HEADER_LENGTH;
5092 Assert(Game_mode & GM_STANDALONE_SERVER);
5094 // if this is a team vs team situation, lock the players send a final team update
5095 if(Netgame.type_flags & NG_TYPE_TEAM){
5096 multi_team_host_lock_all();
5097 multi_team_send_update();
5100 // get the sync mode (pre or post briefing)
5103 if(mode == MULTI_SYNC_PRE_BRIEFING){
5104 // get the flag indicating if this is a single mission or a campaign mode
5105 GET_DATA(campaign_flag);
5107 // get the flag indicating whether we should be starting a new campaign
5108 GET_DATA(campaign_flag);
5110 // get the campaign filename
5111 GET_STRING(Netgame.campaign_name);
5113 // either start a new campaign or continue on to the next mission in the current campaign
5115 multi_campaign_start(Netgame.campaign_name);
5117 multi_campaign_next_mission();
5120 // make sure we remove the campaign mode flag
5121 Game_mode &= ~(GM_CAMPAIGN_MODE);
5123 // get the single mission filename
5124 GET_STRING(Game_current_mission_filename);
5125 strcpy(Netgame.mission_name,Game_current_mission_filename);
5130 // set the correct mode and m ove into the state
5131 Multi_sync_mode = mode;
5132 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5135 // tell a player to merge his mission stats into his alltime stats
5136 void send_store_stats_packet(int accept)
5139 int packet_size = 0;
5141 BUILD_HEADER(STORE_MISSION_STATS);
5143 // add whether we're accepting or tossing
5144 val = (ubyte)accept;
5147 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5148 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5149 multi_io_send_to_all_reliable(data, packet_size);
5151 multi_io_send_reliable(Net_player, data, packet_size);
5155 void process_store_stats_packet(ubyte *data, header *hinfo)
5157 int offset = HEADER_LENGTH;
5163 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5164 if(Game_mode & GM_STANDALONE_SERVER){
5165 // rebroadcast the packet to all others in the game
5166 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5167 multi_io_send_to_all_reliable(data, offset);
5170 // all players should mark the stats as being accepted in the debriefing
5171 multi_debrief_stats_accept();
5173 // all players should mark the stats as being "tossed" in the debriefing
5174 multi_debrief_stats_toss();
5179 void send_debris_update_packet(object *objp,int code)
5181 ubyte data[MAX_PACKET_SIZE];
5183 int packet_size = 0;
5185 BUILD_HEADER(DEBRIS_UPDATE);
5186 ADD_DATA_U16(objp->net_signature);
5190 // add any extra relevant data
5192 case DEBRIS_UPDATE_UPDATE:
5193 // ADD_DATA(objp->pos); // add position
5194 add_vector_data(data, &packet_size, objp->pos);
5195 ADD_ORIENT(objp->orient); // add orientation
5196 // ADD_DATA(objp->phys_info.vel); // add velocity
5197 add_vector_data(data, &packet_size, objp->phys_info.vel);
5198 // ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5199 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5202 multi_io_send_to_all(data, packet_size);
5205 void process_debris_update_packet(ubyte *data, header *hinfo)
5209 object bogus_object;
5211 int offset = HEADER_LENGTH;
5213 GET_DATA_U16(net_sig);
5217 objp = multi_get_network_object(net_sig);
5219 objp = &bogus_object;
5223 // update the object
5224 case DEBRIS_UPDATE_UPDATE:
5225 //GET_DATA(objp->pos);
5226 get_vector_data( data, &offset, objp->pos );
5228 GET_ORIENT(objp->orient);
5229 GET_DATA(objp->phys_info.vel);
5230 GET_DATA(objp->phys_info.rotvel);
5232 // simply remove it (no explosion)
5233 case DEBRIS_UPDATE_REMOVE:
5234 if(objp != &bogus_object){
5235 Assert(objp->type == OBJ_DEBRIS);
5236 obj_delete(OBJ_INDEX(objp));
5240 case DEBRIS_UPDATE_NUKE:
5241 if(objp != &bogus_object)
5242 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5250 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)
5252 ubyte data[MAX_PACKET_SIZE];
5254 int packet_size = 0;
5256 BUILD_HEADER(WSS_REQUEST_PACKET);
5258 // add the request information
5259 ADD_DATA_S16(player_id);
5260 ADD_DATA_S32(from_slot);
5261 ADD_DATA_S32(from_index);
5262 ADD_DATA_S32(to_slot);
5263 ADD_DATA_S32(to_index);
5264 ADD_DATA_S32(wl_ship_slot); // only used in weapons loadout
5265 ADD_DATA_S32(ship_class);
5268 // a standard request
5270 multi_io_send_reliable(Net_player, data, packet_size);
5272 // being routed through the standalone to the host of the game
5274 Assert(Game_mode & GM_STANDALONE_SERVER);
5275 multi_io_send_reliable(p, data, packet_size);
5279 void process_wss_request_packet(ubyte *data, header *hinfo)
5281 int offset = HEADER_LENGTH;
5282 int from_slot,from_index;
5283 int to_slot,to_index;
5285 int wl_ship_slot,ship_class;
5289 // determine who this request is from
5290 GET_DATA_S16(player_id);
5291 player_num = find_player_id(player_id);
5293 // read in the request data
5294 GET_DATA_S32(from_slot);
5295 GET_DATA_S32(from_index);
5296 GET_DATA_S32(to_slot);
5297 GET_DATA_S32(to_index);
5298 GET_DATA_S32(wl_ship_slot); // only used in weapons loadout
5299 GET_DATA_S32(ship_class); // only used in multi team select
5303 Assert(player_num != -1);
5304 if(player_num == -1){
5308 // if we're the standalone, we have to route this packet to the host of the game
5309 if(Game_mode & GM_STANDALONE_SERVER){
5310 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5312 // otherwise we're the host and should process the request
5315 case WSS_WEAPON_SELECT :
5316 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5318 case WSS_SHIP_SELECT :
5319 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5327 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5329 ubyte data[MAX_PACKET_SIZE],team;
5330 int packet_size = 0;
5332 Assert(size <= (MAX_PACKET_SIZE - 10));
5334 BUILD_HEADER(WSS_UPDATE_PACKET);
5336 // add the team/pool # this is for
5337 team = (ubyte)team_num;
5340 // add the data block size
5343 // add the data itself
5344 memcpy(data + packet_size,wss_data,size);
5345 packet_size += size;
5347 // if we're also the master of the game (not on a standalone)
5348 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5349 multi_io_send_to_all_reliable(data, packet_size);
5351 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5353 multi_io_send_reliable(Net_player, data, packet_size);
5357 void process_wss_update_packet(ubyte *data, header *hinfo)
5360 int size,player_index,idx;
5361 int offset = HEADER_LENGTH;
5363 // get the team/pool #
5366 // get the data size
5369 // if we're the standalone, then we should be routing this data to all the other clients
5370 if(Game_mode & GM_STANDALONE_SERVER){
5375 // determine where this came from
5376 player_index = find_player_id(hinfo->id);
5377 Assert(player_index != -1);
5378 if(player_index < 0){
5382 // route the packet (don't resend it to the host)
5383 for(idx=0;idx<MAX_PLAYERS;idx++){
5384 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5385 multi_io_send_reliable(&Net_players[idx], data, offset);
5389 // set the proper pool pointers
5390 ss_set_team_pointers((int)team);
5392 // read in the block of data, and apply it to the weapons/ship pools
5393 offset += restore_wss_data(data + offset);
5396 // set the pool pointers back to my own team
5397 ss_set_team_pointers(Net_player->p_info.team);
5399 // sync the interface if this was for my own team
5400 if((int)team == Net_player->p_info.team){
5401 multi_ts_sync_interface();
5408 // function to send firing information from the client to the server once they reach
5409 // the final sync screen.
5410 void send_firing_info_packet()
5412 ubyte data[MAX_PACKET_SIZE];
5414 ubyte plinked, sdual;
5416 Assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5418 BUILD_HEADER(FIRING_INFO);
5419 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5420 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5421 ADD_DATA( plinked );
5424 multi_io_send_reliable(Net_player, data, packet_size);
5427 void process_firing_info_packet( ubyte *data, header *hinfo )
5429 int offset, player_num;
5430 ubyte plinked, sdual;
5433 // only the master of the game should be dealing with these packets
5434 Assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5436 offset = HEADER_LENGTH;
5437 GET_DATA( plinked );
5441 player_num = find_player_id(hinfo->id);
5443 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5447 // get the ship pointer for this player and set the flags accordingly.
5448 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5450 shipp->flags |= SF_PRIMARY_LINKED;
5452 shipp->flags &= ~SF_PRIMARY_LINKED;
5455 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5457 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5460 // packet to deal with changing status of mission goals. used to be sent every so often from server
5461 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5462 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5463 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5464 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5466 ubyte data[MAX_PACKET_SIZE];
5469 BUILD_HEADER(MISSION_GOAL_INFO);
5471 ADD_DATA_S32(goal_num);
5472 ADD_DATA_S32(new_status);
5473 ADD_DATA_S32(valid);
5475 multi_io_send_to_all_reliable(data, packet_size);
5478 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5480 int offset, goal_num, new_status, valid;
5482 offset = HEADER_LENGTH;
5483 GET_DATA_S32(goal_num);
5484 GET_DATA_S32(new_status);
5485 GET_DATA_S32(valid);
5488 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5489 if ( new_status != -1 ){
5490 mission_goal_status_change( goal_num, new_status );
5492 mission_goal_validation_change( goal_num, valid );
5496 void send_player_settings_packet(net_player *p)
5498 ubyte data[MAX_PACKET_SIZE];
5501 int packet_size = 0;
5504 BUILD_HEADER(PLAYER_SETTINGS);
5506 // add all the data for all the players
5508 for(idx=0;idx<MAX_PLAYERS;idx++){
5509 if(MULTI_CONNECTED(Net_players[idx])){
5511 ADD_DATA_S16(Net_players[idx].player_id);
5513 // break the p_info structure by member, so we don't overwrite any absolute pointers
5514 // ADD_DATA(Net_players[idx].p_info);
5515 ADD_DATA_S32(Net_players[idx].p_info.team);
5516 ADD_DATA_S32(Net_players[idx].p_info.ship_index);
5517 ADD_DATA_S32(Net_players[idx].p_info.ship_class);
5520 // add the stop byte
5524 // either broadcast the data or send to a specific player
5526 multi_io_send_to_all_reliable(data, packet_size);
5528 multi_io_send_reliable(p, data, packet_size);
5532 void process_player_settings_packet(ubyte *data, header *hinfo)
5534 int offset,player_num;
5535 net_player_info bogus,*ptr;
5539 offset = HEADER_LENGTH;
5541 // read in the data for all the players
5543 while(stop != 0xff){
5544 // lookup the player
5545 GET_DATA_S16(player_id);
5546 player_num = find_player_id(player_id);
5548 // make sure this is a valid player
5549 if(player_num == -1){
5552 ptr = &Net_players[player_num].p_info;
5555 GET_DATA_S32(ptr->team);
5556 GET_DATA_S32(ptr->ship_index);
5557 GET_DATA_S32(ptr->ship_class);
5564 // update the server with my new state
5565 // MWA -- 3/31/98 -- check for in mission instead of state.
5566 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5567 if( !(Game_mode & GM_IN_MISSION) ) {
5568 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5569 send_netplayer_update_packet();
5573 // display some cool text
5574 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5577 void send_deny_packet(net_addr *addr, int code)
5580 int packet_size = 0;
5582 // build the header and add the rejection code
5588 psnet_send(addr, data, packet_size);
5591 void process_deny_packet(ubyte *data, header *hinfo)
5595 // get the denial code
5596 offset = HEADER_LENGTH;
5600 // if there is already a dialog active, do nothing - who cares at this point.
5605 // display the appropriate dialog
5607 case JOIN_DENY_JR_STATE :
5608 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));
5610 case JOIN_DENY_JR_TRACKER_INVAL :
5611 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));
5613 case JOIN_DENY_JR_PASSWD :
5614 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5616 case JOIN_DENY_JR_CLOSED :
5617 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));
5619 case JOIN_DENY_JR_TEMP_CLOSED :
5620 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));
5622 case JOIN_DENY_JR_RANK_HIGH :
5623 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));
5625 case JOIN_DENY_JR_RANK_LOW :
5626 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));
5628 case JOIN_DENY_JR_DUP :
5629 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5631 case JOIN_DENY_JR_FULL :
5632 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5634 case JOIN_DENY_JR_BANNED :
5635 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5637 case JOIN_DENY_JR_NOOBS :
5638 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5640 case JOIN_DENY_JR_INGAME_JOIN :
5641 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));
5643 case JOIN_DENY_JR_BAD_VERSION :
5644 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));
5646 case JOIN_DENY_JR_TYPE :
5647 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5651 // call this so that the join request timestamp automatically expires when we hear back from the server
5652 multi_join_reset_join_stamp();
5655 // this packet will consist of
5656 // 1.) netplayer ship classes (85 bytes max)
5657 // 2.) ship weapon state data (241 bytes max)
5658 // 3.) player settings et. al. (133 bytes max)
5659 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5660 void send_post_sync_data_packet(net_player *p, int std_request)
5662 ubyte data[MAX_PACKET_SIZE], val;
5667 ushort sval, ship_ets;
5668 int idx, player_index;
5669 int packet_size = 0;
5673 BUILD_HEADER(POST_SYNC_DATA);
5675 // some header information for standalone packet routing purposes
5676 val = (ubyte)std_request;
5679 // the standalone has two situations
5680 // 1.) sending a request to the host to distribute this block of data
5681 // 2.) having recevied this block of data from the host, it redistributes it
5682 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5683 // case 1, send the request
5684 multi_io_send_reliable(Netgame.host, data, packet_size);
5687 // case 2 for the standalone is below (as normal)
5689 // otherwise build the data now
5691 // add all deleted ships
5692 val = (ubyte)Multi_ts_num_deleted;
5694 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5695 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5701 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5702 shipp = &Ships[Objects[so->objnum].instance];
5704 // don't process non player wing ships
5705 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5711 // # of ships - used multiple times in the packet
5712 val = (ubyte)ship_count;
5715 // add ship class information (85 bytes max)
5716 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5717 shipp = &Ships[Objects[so->objnum].instance];
5719 // don't process non player wing ships
5720 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5723 // add the net signature of the object for look up
5724 ADD_DATA_U16( Objects[so->objnum].net_signature );
5726 // add the ship info index
5727 val = (ubyte)(shipp->ship_info_index);
5730 // add the ships's team select index
5731 val = (ubyte)shipp->ts_index;
5735 // add weapon state information for all starting ships (241 bytes max)
5736 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5737 shipp = &Ships[Objects[so->objnum].instance];
5739 // don't process non player wing ships
5740 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5743 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5745 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5746 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5747 if(player_index == -1){
5750 pl = &Net_players[player_index];
5754 // add the net signature and other weapon information
5755 ADD_DATA_U16( Objects[so->objnum].net_signature );
5757 // add number of primary and secondary banks
5758 bval = (char)(shipp->weapons.num_primary_banks);
5760 bval = (char)(shipp->weapons.num_secondary_banks);
5763 // add weapon bank status
5764 bval = (char)(shipp->weapons.current_primary_bank);
5766 pl->s_info.cur_primary_bank = bval;
5768 // Assert(bval != -1);
5771 bval = (char)(shipp->weapons.current_secondary_bank);
5773 pl->s_info.cur_secondary_bank = bval;
5775 // Assert(bval != -1);
5778 // primary weapon info
5779 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5781 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5784 // secondary weapon info
5785 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5787 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5788 ADD_DATA_S16(val_short);
5789 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5791 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5792 ADD_DATA_S16(val_short);
5793 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5795 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5796 ADD_DATA_S16(val_short);
5798 // send primary and secondary weapon link status
5800 if(shipp->flags & SF_PRIMARY_LINKED){
5802 pl->s_info.cur_link_status |= (1<<0);
5806 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5808 pl->s_info.cur_link_status |= (1<<1);
5812 // if this is a player ship add (1<<2)
5813 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5818 // add a ship ets value
5821 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5823 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5825 ship_ets |= ((ushort)shipp->engine_recharge_index);
5826 ADD_DATA_U16(ship_ets);
5830 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5831 // or if I'm the server as well as the host, I should be sending this to all players
5832 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5833 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5836 multi_io_send_to_all_reliable(data, packet_size);
5838 // send to a specific player
5840 multi_io_send_reliable(p, data, packet_size);
5843 multi_io_send_reliable(Net_player, data, packet_size);
5850 multi_io_send_to_all_reliable(data, packet_size);
5852 // send to a specific player
5854 multi_io_send_reliable(p, data, packet_size);
5859 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5861 ubyte val, sinfo_index, ts_index;
5863 ushort net_sig, ship_ets, sval;
5867 int offset = HEADER_LENGTH;
5871 // packet routing information
5874 // 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
5875 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5878 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5879 multi_ts_create_wings();
5881 // send to the standalone through my socket
5882 send_post_sync_data_packet(Net_player);
5888 // add all deleted ships
5890 Multi_ts_num_deleted = (int)val;
5891 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5892 // get the ship's objnum
5895 objp = multi_get_network_object(sval);
5897 // delete the ship appropriately
5898 // mark the object as having been deleted
5899 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5902 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5903 obj_delete(Multi_ts_deleted_objnums[idx]);
5904 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5906 Multi_ts_num_deleted--;
5907 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5915 // process ship class information
5916 for(idx=0; idx<ship_count; idx++){
5917 // get the object's net signature
5918 GET_DATA_U16(net_sig);
5919 GET_DATA(sinfo_index);
5922 // attempt to get the object
5923 objp = multi_get_network_object(net_sig);
5925 // make sure we found a ship
5926 Assert((objp != NULL) && (objp->type == OBJ_SHIP));
5928 // set the ship to be the right class
5929 change_ship_type(objp->instance,(int)sinfo_index);
5931 // set the ship's team select index
5932 Ships[objp->instance].ts_index = (int)ts_index;
5935 // process ship weapon state info
5936 for(idx=0; idx<ship_count; idx++){
5937 // get the object's net signature
5938 GET_DATA_U16(net_sig);
5940 // attempt to get the object
5941 objp = multi_get_network_object(net_sig);
5943 // make sure we found a ship
5944 Assert((objp != NULL) && (objp->type == OBJ_SHIP));
5946 // get a pointer to the ship
5947 shipp = &Ships[objp->instance];
5949 // get number of primary and secondary banks;
5952 shipp->weapons.num_primary_banks = (int)b;
5956 shipp->weapons.num_secondary_banks = (int)b;
5958 // get bank selection info
5963 shipp->weapons.current_primary_bank = (int)b;
5969 shipp->weapons.current_secondary_bank = (int)b;
5971 // primary weapon info
5973 shipp->weapons.primary_bank_weapons[0] = (int)b;
5976 shipp->weapons.primary_bank_weapons[1] = (int)b;
5978 // secondary weapon info
5980 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5981 GET_DATA_S16(val_short);
5982 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5985 shipp->weapons.secondary_bank_weapons[1] = (int)b;
5986 GET_DATA_S16(val_short);
5987 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
5990 shipp->weapons.secondary_bank_weapons[2] = (int)b;
5991 GET_DATA_S16(val_short);
5992 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
5999 shipp->flags |= SF_PRIMARY_LINKED;
6002 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
6004 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6005 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6007 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6009 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6013 GET_DATA_U16(ship_ets);
6015 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6017 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6019 shipp->engine_recharge_index = (ship_ets & 0x000f);
6024 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6025 send_netplayer_update_packet();
6027 // the standalone server will receive this packet from the host of the game, to be applied locally and
6028 // also to be rebroadcast.
6029 if(Game_mode & GM_STANDALONE_SERVER){
6030 // update player ets settings
6031 for(idx=0;idx<MAX_PLAYERS;idx++){
6032 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6033 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6037 send_post_sync_data_packet(NULL,0);
6041 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6043 ubyte data[MAX_PACKET_SIZE],val;
6046 int packet_size = 0;
6049 BUILD_HEADER(WSS_SLOTS_DATA);
6051 // some header information for standalone packet routing purposes
6052 val = (ubyte)std_request;
6056 val = (ubyte)team_num;
6059 // add whether this is the final packet or not
6063 // the standalone has two situations
6064 // 1.) sending a request to the host to distribute this block of data
6065 // 2.) having recevied this block of data from the host, it redistributes it
6066 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6067 // case 1, send the request
6068 multi_io_send_reliable(Netgame.host, data, packet_size);
6071 // case 2 for the standalone is below (as normal)
6073 // add all the slots
6074 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6075 // add the ship class
6076 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6080 for(i = 0;i<MAX_WL_WEAPONS;i++){
6081 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6085 // add the weapon counts
6086 for(i = 0;i<MAX_WL_WEAPONS;i++){
6087 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6088 ADD_DATA_S16(val_short);
6092 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6093 // or if I'm the server as well as the host, I should be sending this to all players
6094 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6095 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6098 multi_io_send_to_all_reliable(data, packet_size);
6100 // send to a specific player
6102 multi_io_send_reliable(p, data, packet_size);
6105 multi_io_send_reliable(Net_player, data, packet_size);
6112 multi_io_send_to_all_reliable(data, packet_size);
6114 // send to a specific player
6116 multi_io_send_reliable(p, data, packet_size);
6121 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6123 ubyte val,team_num,final;
6125 int offset = HEADER_LENGTH;
6128 // packet routing information
6134 // get whether this is the final packet or not
6137 // 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
6138 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6141 // send to the standalone through my socket
6142 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6146 // read in all the slot data
6147 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6148 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6150 // get the ship class
6152 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6155 for(i = 0;i<MAX_WL_WEAPONS;i++){
6157 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6159 // check for signed/unsigned problems
6160 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6161 Wss_slots_teams[team_num][idx].wep[i] = -1;
6165 // get the weapon counts
6166 for(i = 0;i<MAX_WL_WEAPONS;i++){
6167 GET_DATA_S16(val_short);
6168 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6173 // update my netplayer state if this is the final packet
6175 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6176 send_netplayer_update_packet();
6179 // the standalone server will receive this packet from the host of the game, to be applied locally and
6180 // also to be rebroadcast.
6181 if(Game_mode & GM_STANDALONE_SERVER){
6182 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6184 // add some mission sync text
6185 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6189 #define OBJ_VISIBILITY_DOT 0.6f
6191 // send and receive packets for shield explosion information
6192 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6195 ubyte data[MAX_PACKET_SIZE], utri_num;
6198 // Assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6200 Assert( tri_num < UCHAR_MAX );
6201 utri_num = (ubyte)tri_num;
6203 // for each player, determine if this object is behind the player -- if so, don't
6205 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6206 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6208 vector eye_to_obj_vec, diff, eye_pos;
6211 eye_pos = Net_players[i].s_info.eye_pos;
6212 eye_orient = Net_players[i].s_info.eye_orient;
6214 // check for same vectors
6215 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6216 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6220 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6221 dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6223 if ( dot < OBJ_VISIBILITY_DOT ){
6227 BUILD_HEADER(SHIELD_EXPLOSION);
6229 ADD_DATA_U16( Objects[objnum].net_signature );
6232 multi_io_send(&Net_players[i], data, packet_size);
6237 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6239 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6246 // get the shield hit data
6247 offset = HEADER_LENGTH;
6248 GET_DATA_U16(signature);
6250 //GET_DATA(hit_pos);
6253 // find the object with this signature. If found, then do a shield explosion
6254 objp = multi_get_network_object( signature );
6257 shield_info *shieldp;
6262 // given the tri num, find the local position which is the average of the
6263 // three vertices of the triangle affected. Use this average point as the hit
6265 // Assert( objp->type == OBJ_SHIP );
6266 if(objp->type != OBJ_SHIP){
6270 pm = model_get(Ships[objp->instance].modelnum);
6271 shieldp = &pm->shield;
6272 Assert( utri_num < shieldp->ntris );
6273 stri = shieldp->tris[utri_num];
6274 vm_vec_zero(&hit_pos);
6275 for ( i = 0; i < 3; i++ ) {
6276 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6278 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6279 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6283 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6286 ubyte data[MAX_PACKET_SIZE], val;
6288 int packet_size = 0;
6293 sc = &pl->player->stats;
6296 BUILD_HEADER(PLAYER_STATS);
6298 // add the player id
6299 ADD_DATA_S16(pl->player_id);
6301 // add the byte indicating whether these stats are all-time or not
6302 val = (ubyte)stats_code;
6305 // kill information - alltime
6309 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6310 u_tmp = sc->kills[idx];
6311 ADD_DATA_U16(u_tmp);
6313 // medal information
6314 for(idx=0;idx<NUM_MEDALS;idx++){
6315 i_tmp = sc->medals[idx];
6316 ADD_DATA_S32(i_tmp);
6319 ADD_DATA_S32(sc->score);
6320 ADD_DATA_S32(sc->rank);
6321 ADD_DATA_S32(sc->assists);
6322 ADD_DATA_S32(sc->kill_count);
6323 ADD_DATA_S32(sc->kill_count_ok);
6324 ADD_DATA_U32(sc->p_shots_fired);
6325 ADD_DATA_U32(sc->s_shots_fired);
6326 ADD_DATA_U32(sc->p_shots_hit);
6327 ADD_DATA_U32(sc->s_shots_hit);
6328 ADD_DATA_U32(sc->p_bonehead_hits);
6329 ADD_DATA_U32(sc->s_bonehead_hits);
6330 ADD_DATA_S32(sc->bonehead_kills);
6332 ADD_DATA_U32(sc->missions_flown);
6333 ADD_DATA_U32(sc->flight_time);
6334 ADD_DATA_S32(sc->last_flown);
6335 ADD_DATA_S32(sc->last_backup);
6340 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6341 u_tmp = sc->m_okKills[idx];
6342 ADD_DATA_U16(u_tmp);
6345 ADD_DATA_S32(sc->m_score);
6346 ADD_DATA_S32(sc->m_assists);
6347 ADD_DATA_S32(sc->m_kill_count);
6348 ADD_DATA_S32(sc->m_kill_count_ok);
6349 ADD_DATA_U32(sc->mp_shots_fired);
6350 ADD_DATA_U32(sc->ms_shots_fired);
6351 ADD_DATA_U32(sc->mp_shots_hit);
6352 ADD_DATA_U32(sc->ms_shots_hit);
6353 ADD_DATA_U32(sc->mp_bonehead_hits);
6354 ADD_DATA_U32(sc->ms_bonehead_hits);
6355 ADD_DATA_S32(sc->m_bonehead_kills);
6356 ADD_DATA_S32(sc->m_player_deaths);
6357 ADD_DATA_S32(sc->m_medal_earned);
6360 case STATS_MISSION_KILLS:
6361 ADD_DATA_S32(sc->m_kill_count);
6362 ADD_DATA_S32(sc->m_kill_count_ok);
6363 ADD_DATA_S32(sc->m_assists);
6366 case STATS_DOGFIGHT_KILLS:
6367 for(idx=0; idx<MAX_PLAYERS; idx++){
6368 u_tmp = sc->m_dogfight_kills[idx];
6369 ADD_DATA_U16(u_tmp);
6371 ADD_DATA_S32(sc->m_kill_count);
6372 ADD_DATA_S32(sc->m_kill_count_ok);
6373 ADD_DATA_S32(sc->m_assists);
6377 Assert(packet_size < MAX_PACKET_SIZE);
6379 // if we're a client, always send the data to the server
6380 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6381 multi_io_send_reliable(Net_player, data, packet_size);
6383 // otherwise do server specific stuff
6385 // send to a specific target
6387 multi_io_send_reliable(target, data, packet_size);
6389 // otherwise, send to everyone
6391 multi_io_send_to_all_reliable(data, packet_size);
6396 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6400 scoring_struct *sc,bogus;
6402 int offset = HEADER_LENGTH;
6406 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6408 // get the player who these stats are for
6409 GET_DATA_S16(player_id);
6410 player_num = find_player_id(player_id);
6411 if (player_num == -1) {
6412 nprintf(("Network", "Couldn't find player for stats update!\n"));
6413 ml_string("Couldn't find player for stats update!\n");
6418 sc = &Net_players[player_num].player->stats;
6421 // get the stats code
6425 ml_string("Received STATS_ALLTIME\n");
6428 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6429 GET_DATA_U16(u_tmp);
6430 sc->kills[idx] = u_tmp;
6433 // read in the stats
6434 for (idx=0; idx<NUM_MEDALS; idx++) {
6435 GET_DATA_S32(i_tmp);
6436 sc->medals[idx] = i_tmp;
6439 GET_DATA_S32(sc->score);
6440 GET_DATA_S32(sc->rank);
6441 GET_DATA_S32(sc->assists);
6442 GET_DATA_S32(sc->kill_count);
6443 GET_DATA_S32(sc->kill_count_ok);
6444 GET_DATA_U32(sc->p_shots_fired);
6445 GET_DATA_U32(sc->s_shots_fired);
6446 GET_DATA_U32(sc->p_shots_hit);
6447 GET_DATA_U32(sc->s_shots_hit);
6448 GET_DATA_U32(sc->p_bonehead_hits);
6449 GET_DATA_U32(sc->s_bonehead_hits);
6450 GET_DATA_S32(sc->bonehead_kills);
6452 GET_DATA_U32(sc->missions_flown);
6453 GET_DATA_U32(sc->flight_time);
6454 GET_DATA_S32(sc->last_flown);
6455 GET_DATA_S32(sc->last_backup);
6459 ml_string("Received STATS_MISSION\n");
6461 // kills - mission OK
6462 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6463 GET_DATA_U16(u_tmp);
6464 sc->m_okKills[idx] = u_tmp;
6467 GET_DATA_S32(sc->m_score);
6468 GET_DATA_S32(sc->m_assists);
6469 GET_DATA_S32(sc->m_kill_count);
6470 GET_DATA_S32(sc->m_kill_count_ok);
6471 GET_DATA_U32(sc->mp_shots_fired);
6472 GET_DATA_U32(sc->ms_shots_fired);
6473 GET_DATA_U32(sc->mp_shots_hit);
6474 GET_DATA_U32(sc->ms_shots_hit);
6475 GET_DATA_U32(sc->mp_bonehead_hits);
6476 GET_DATA_U32(sc->ms_bonehead_hits);
6477 GET_DATA_S32(sc->m_bonehead_kills);
6478 GET_DATA_S32(sc->m_player_deaths);
6479 GET_DATA_S32(sc->m_medal_earned);
6482 case STATS_MISSION_KILLS:
6483 ml_string("Received STATS_MISSION_KILLS\n");
6485 GET_DATA_S32(sc->m_kill_count);
6486 GET_DATA_S32(sc->m_kill_count_ok);
6487 GET_DATA_S32(sc->m_assists);
6490 case STATS_DOGFIGHT_KILLS:
6491 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6492 if(player_num >= 0){
6493 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6495 for(idx=0; idx<MAX_PLAYERS; idx++){
6496 GET_DATA_U16(u_tmp);
6497 sc->m_dogfight_kills[idx] = u_tmp;
6498 if(player_num >= 0){
6499 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6502 GET_DATA_S32(sc->m_kill_count);
6503 GET_DATA_S32(sc->m_kill_count_ok);
6504 GET_DATA_S32(sc->m_assists);
6509 // if I'm the server of the game, I should always rebroadcast these stats
6510 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6511 // make sure these are alltime stats
6512 Assert(val == STATS_ALLTIME);
6514 multi_broadcast_stats(STATS_ALLTIME);
6518 // called to create asteroid stuff
6519 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6522 ubyte data[MAX_PACKET_SIZE];
6523 ubyte packet_type, atype;
6527 if (relvec != NULL )
6530 BUILD_HEADER( ASTEROID_INFO );
6531 packet_type = ASTEROID_CREATE;
6533 Assert( asteroid_type < UCHAR_MAX );
6534 atype = (ubyte)asteroid_type;
6536 ADD_DATA( packet_type );
6537 ADD_DATA_U16( parent_objp->net_signature );
6538 ADD_DATA_U16( new_objp->net_signature );
6541 add_vector_data( data, &packet_size, vec );
6543 multi_io_send_to_all(data, packet_size);
6546 void send_asteroid_throw( object *objp )
6549 ubyte data[MAX_PACKET_SIZE], packet_type;
6551 BUILD_HEADER( ASTEROID_INFO );
6553 // this packet type is an asteroid throw
6554 packet_type = ASTEROID_THROW;
6555 ADD_DATA( packet_type );
6556 ADD_DATA_U16( objp->net_signature );
6557 //ADD_DATA( objp->pos );
6558 add_vector_data( data, &packet_size, objp->pos );
6559 //ADD_DATA( objp->phys_info.vel );
6560 add_vector_data( data, &packet_size, objp->phys_info.vel );
6562 multi_io_send_to_all(data, packet_size);
6565 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6568 ubyte data[MAX_PACKET_SIZE], packet_type;
6572 if ( hitpos != NULL )
6575 // build up an asteroid hit packet
6576 BUILD_HEADER( ASTEROID_INFO );
6577 packet_type = ASTEROID_HIT;
6578 ADD_DATA( packet_type );
6579 ADD_DATA_U16( objp->net_signature );
6581 if(other_objp == NULL){
6582 ushort invalid_sig = 0xffff;
6583 ADD_DATA_U16(invalid_sig);
6585 ADD_DATA_U16( other_objp->net_signature );
6588 add_vector_data( data, &packet_size, vec );
6589 ADD_DATA_FL( damage );
6591 multi_io_send_to_all(data, packet_size);
6594 void process_asteroid_info( ubyte *data, header *hinfo )
6599 offset = HEADER_LENGTH;
6600 GET_DATA( packet_type );
6602 // based on the packet type, do something interesting with an asteroid!
6603 switch( packet_type ) {
6605 case ASTEROID_CREATE: {
6606 ushort psignature, signature;
6609 object *parent_objp;
6611 GET_DATA_U16( psignature );
6612 GET_DATA_U16( signature );
6614 //GET_DATA( relvec );
6615 get_vector_data( data, &offset, relvec );
6617 // after getting the values, set the next network signature, and call the create sub function
6618 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6619 parent_objp = multi_get_network_object( psignature );
6620 if ( parent_objp ) {
6621 asteroid_sub_create( parent_objp, atype, &relvec );
6623 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6630 // asteroid throw packet -- asteroid has wrapped bounds
6631 case ASTEROID_THROW: {
6636 GET_DATA_U16( signature );
6638 get_vector_data( data, &offset, pos );
6640 get_vector_data( data, &offset, vel );
6641 objp = multi_get_network_object( signature );
6643 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6647 objp->phys_info.vel = vel;
6648 objp->phys_info.desired_vel = vel;
6652 case ASTEROID_HIT: {
6653 ushort signature, osignature;
6654 object *objp, *other_objp;
6658 GET_DATA_U16( signature );
6659 GET_DATA_U16( osignature );
6660 //GET_DATA( hitpos );
6661 get_vector_data( data, &offset, hitpos );
6662 GET_DATA_FL( damage );
6664 objp = multi_get_network_object( signature );
6665 if(osignature == 0xffff){
6668 other_objp = multi_get_network_object( osignature );
6671 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6675 if ( IS_VEC_NULL(&hitpos) ){
6676 asteroid_hit( objp, other_objp, NULL, damage );
6678 asteroid_hit( objp, other_objp, &hitpos, damage );
6681 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6682 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6683 weapon_hit( other_objp, objp, &hitpos );
6696 void send_host_restr_packet(char *callsign,int code,int mode)
6698 ubyte data[MAX_PACKET_SIZE],val;
6699 int packet_size = 0;
6701 // build the header and add the opcode
6702 BUILD_HEADER(HOST_RESTR_QUERY);
6709 ADD_STRING(callsign);
6711 // if I'm the standalone server, I should be sending this to the game host
6712 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6713 multi_io_send_reliable(Netgame.host, data, packet_size);
6715 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6717 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6718 multi_io_send_reliable(Net_player, data, packet_size);
6722 void process_host_restr_packet(ubyte *data, header *hinfo)
6726 int offset = HEADER_LENGTH;
6728 // get the opcode and the callsign
6731 GET_STRING(callsign);
6734 // do code specific operations
6736 // query to the host from standalone
6738 Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6740 // set the join mode
6741 Multi_join_restr_mode = mode;
6743 // set the timestamp
6744 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6746 // notify the host of the event
6747 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6748 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6751 // affirmative reply from the host to the standalone
6753 Assert(Game_mode & GM_STANDALONE_SERVER);
6755 // let the player join if the timestamp has not already elapsed on the server
6756 if(Multi_restr_query_timestamp != -1){
6757 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6763 Assert(Game_mode & GM_STANDALONE_SERVER);
6764 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6765 Multi_restr_query_timestamp = -1;
6770 void send_netgame_end_error_packet(int notify_code,int err_code)
6774 int packet_size = 0;
6776 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6777 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6779 // build the header and add the notification and error codes
6780 BUILD_HEADER(NETGAME_END_ERROR);
6781 code = (char)notify_code;
6783 code = (char)err_code;
6787 multi_io_send_to_all_reliable(data, packet_size);
6790 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6792 int offset = HEADER_LENGTH;
6793 char notify_code,error_code;
6795 // get the error and notification codes
6796 GET_DATA(notify_code);
6797 GET_DATA(error_code);
6801 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6804 // sends info that a countermeasure succeeded.
6805 void send_countermeasure_success_packet( int objnum )
6807 int pnum, packet_size;
6808 ubyte data[MAX_PACKET_SIZE];
6810 pnum = multi_find_player_by_object( &Objects[objnum] );
6812 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6816 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6817 multi_io_send(&Net_players[pnum], data, packet_size);
6820 // start the flashing of my hud gauge
6821 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6825 offset = HEADER_LENGTH;
6828 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6829 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6832 #define UPDATE_IS_PAUSED (1<<0)
6833 #define UPDATE_HULL_INFO (1<<1)
6835 void send_client_update_packet(net_player *pl)
6837 ubyte data[MAX_PACKET_SIZE],val;
6838 int packet_size = 0;
6841 BUILD_HEADER(CLIENT_UPDATE);
6845 // add the pause status
6846 if ( Multi_pause_status ) {
6847 val |= UPDATE_IS_PAUSED;
6848 } 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) ) {
6849 val |= UPDATE_HULL_INFO;
6850 Assert( Player_ship ); // I"d better have one of these!!!!
6855 // if paused, add the net address of the guy who paused
6856 if(val & UPDATE_IS_PAUSED){
6857 Assert(Multi_pause_pauser != NULL);
6858 ADD_DATA_S16(Multi_pause_pauser->player_id);
6861 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6862 if ( val & UPDATE_HULL_INFO ) {
6864 ubyte percent, ns, threats;
6867 ship_subsys *subsysp;
6870 // get the object for the player
6871 Assert( pl->player->objnum != -1 );
6873 objp = &Objects[pl->player->objnum];
6875 Assert ( objp->type == OBJ_SHIP );
6876 shipp = &Ships[objp->instance];
6877 sip = &Ship_info[shipp->ship_info_index];
6879 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6880 // percentage value since that should be close enough
6881 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6885 percent = (ubyte)temp;
6887 ADD_DATA( percent );
6889 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6890 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6891 ADD_DATA( percent );
6894 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6895 // both machines. Added as percent since that number <= 100
6897 // also write out the number of subsystems. We do this because the client might not know
6898 // about the object he is getting data for. (i.e. he killed the object already).
6899 ns = (ubyte)sip->n_subsystems;
6902 // now the subsystems.
6903 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6904 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6905 ADD_DATA( percent );
6908 // compute the threats for this player. Only compute the threats if this player is actually
6909 // playing (i.e. he has a ship)
6910 hud_update_reticle( pl->player );
6911 threats = (ubyte)pl->player->threat_flags;
6912 ADD_DATA( threats );
6914 // add his energy level for guns
6915 ADD_DATA_FL(shipp->weapon_energy);
6917 // add his secondary bank ammo
6918 ADD_DATA_S32(shipp->weapons.num_secondary_banks);
6919 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6920 ADD_DATA_S32(shipp->weapons.secondary_bank_ammo[i]);
6925 ADD_DATA_S32(pl->sv_last_pl);
6927 // send the packet reliably to the player
6928 multi_io_send(pl, data, packet_size);
6931 void process_client_update_packet(ubyte *data, header *hinfo)
6936 int is_paused, have_hull_info;
6939 float weapon_energy;
6940 int offset = HEADER_LENGTH;
6942 // get the header byte containing useful information
6945 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6946 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6948 // if we are paused, get who paused
6950 GET_DATA_S16(pauser);
6951 player_index = find_player_id(pauser);
6952 if(player_index != -1){
6953 Multi_pause_pauser = &Net_players[player_index];
6955 Multi_pause_pauser = NULL;
6959 // if we have hull information, then read it in.
6960 if ( have_hull_info ) {
6964 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6966 ship_subsys *subsysp;
6970 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6971 // percentage value since that should be close enough
6972 GET_DATA( hull_percent );
6974 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6976 shield_percent[i] = ub_tmp;
6979 // get the data for the subsystems
6980 GET_DATA( n_subsystems );
6981 for ( i = 0; i < n_subsystems; i++ ){
6983 subsystem_percent[i] = ub_tmp;
6986 GET_DATA( threats );
6988 // add his energy level for guns
6989 GET_DATA_FL(weapon_energy);
6991 // add his secondary bank ammo
6992 GET_DATA_S32(ammo_count);
6993 for(i=0; i<ammo_count; i++){
6994 GET_DATA_S32(ammo[i]);
6997 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
6998 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
6999 // UDP client update packets. Only read this info if I have a ship.
7000 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
7001 shipp = Player_ship;
7003 sip = &Ship_info[shipp->ship_info_index];
7005 val = hull_percent * sip->initial_hull_strength / 100.0f;
7006 objp->hull_strength = val;
7008 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7009 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7010 objp->shields[i] = val;
7013 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
7014 // then don't read these in.
7015 if ( n_subsystems == sip->n_subsystems ) {
7017 n_subsystems = 0; // reuse this variable
7018 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7021 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7022 subsysp->current_hits = val;
7024 // add the value just generated (it was zero'ed above) into the array of generic system types
7025 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
7026 Assert ( subsys_type < SUBSYSTEM_MAX );
7027 shipp->subsys_info[subsys_type].current_hits += val;
7031 ship_recalc_subsys_strength( shipp );
7033 shipp->weapon_energy = weapon_energy;
7034 for(i=0; i<ammo_count; i++){
7035 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7038 // update my threat flags.
7039 // temporarily commented out until tested.
7040 Net_player->player->threat_flags = threats;
7047 if(Net_player != NULL){
7048 Net_player->cl_last_pl = pl;
7052 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7053 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7055 multi_pause_pause();
7057 multi_pause_unpause();
7062 void send_countdown_packet(int time)
7066 int packet_size = 0;
7068 // build the header and add the time
7069 BUILD_HEADER(COUNTDOWN);
7073 // if we're the server, we should broadcast to everyone
7074 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
7075 multi_io_send_to_all_reliable(data, packet_size);
7077 // otherwise we'de better be a host sending to the standalone
7079 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7080 multi_io_send_reliable(Net_player, data, packet_size);
7084 void process_countdown_packet(ubyte *data, header *hinfo)
7086 int offset = HEADER_LENGTH;
7093 // if we're not in the post sync data screen, ignore it
7094 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7098 // if we're the standalone, this should be a -1 telling us to start the countdown
7099 if(Game_mode & GM_STANDALONE_SERVER){
7100 Assert((int)time == -1);
7102 // start the countdown
7103 multi_sync_start_countdown();
7105 // otherwise if we're clients, just bash the countdown
7107 Multi_sync_countdown = (int)time;
7111 // packets for debriefing information
7112 void send_debrief_info( int stage_count[], int *stages[] )
7114 ubyte data[MAX_PACKET_SIZE];
7115 int packet_size, i, j;
7118 BUILD_HEADER(DEBRIEF_INFO);
7120 // add the data for the teams
7121 for ( i = 0; i < Num_teams; i++ ) {
7124 count = stage_count[i];
7125 ADD_DATA_S32( count );
7126 for ( j = 0; j < count; j++ ) {
7127 i_tmp = stages[i][j];
7128 ADD_DATA_S32( i_tmp );
7132 multi_io_send_to_all_reliable(data, packet_size);
7135 // process a debrief info packet from the server
7136 void process_debrief_info( ubyte *data, header *hinfo )
7139 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7142 offset = HEADER_LENGTH;
7143 for ( i = 0; i < Num_teams; i++ ) {
7146 GET_DATA_S32( count );
7147 stage_counts[i] = count;
7148 stages[i] = active_stages[i];
7149 for ( j = 0; j < count; j++ ) {
7150 GET_DATA_S32(i_tmp);
7151 active_stages[i][j] = i_tmp;
7156 // now that we have the stage data for the debriefing stages, call debrief function with the
7157 // data so that clients can now see the debriefing stuff. Do it only for my team.
7158 Assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7159 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7162 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7163 // sends homing_object and homing_subsystem to all clients.
7164 void send_homing_weapon_info( int weapon_num )
7166 ubyte data[MAX_PACKET_SIZE];
7169 object *homing_object;
7170 ushort homing_signature;
7173 wp = &Weapons[weapon_num];
7175 // be sure that this weapon object is a homing object.
7176 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7179 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7180 // homing signature.
7181 homing_signature = 0;
7182 homing_object = wp->homing_object;
7183 if ( homing_object != NULL ) {
7184 homing_signature = homing_object->net_signature;
7186 // get the subsystem index.
7188 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7191 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7192 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
7193 t_subsys = (char)s_index;
7197 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7198 ADD_DATA_U16( Objects[wp->objnum].net_signature );
7199 ADD_DATA_U16( homing_signature );
7200 ADD_DATA( t_subsys );
7202 multi_io_send_to_all(data, packet_size);
7205 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7206 // packet contains information for multiple weapons (like hornets).
7207 void process_homing_weapon_info( ubyte *data, header *hinfo )
7210 ushort weapon_signature, homing_signature;
7212 object *homing_object, *weapon_objp;
7215 offset = HEADER_LENGTH;
7217 // get the data for the packet
7218 GET_DATA_U16( weapon_signature );
7219 GET_DATA_U16( homing_signature );
7220 GET_DATA( h_subsys );
7223 // deal with changing this weapons homing information
7224 weapon_objp = multi_get_network_object( weapon_signature );
7225 if ( weapon_objp == NULL ) {
7226 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7229 Assert( weapon_objp->type == OBJ_WEAPON );
7230 wp = &Weapons[weapon_objp->instance];
7232 // be sure that we can find these weapons and
7233 homing_object = multi_get_network_object( homing_signature );
7234 if ( homing_object == NULL ) {
7235 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7239 if ( homing_object->type == OBJ_WEAPON ) {
7240 Assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7243 wp->homing_object = homing_object;
7244 wp->homing_subsys = NULL;
7245 wp->target_num = OBJ_INDEX(homing_object);
7246 wp->target_sig = homing_object->signature;
7247 if ( h_subsys != -1 ) {
7248 Assert( homing_object->type == OBJ_SHIP );
7249 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7252 if ( homing_object->type == OBJ_SHIP ) {
7253 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7257 void send_emp_effect(ushort net_sig, float intensity, float time)
7262 Assert(MULTIPLAYER_MASTER);
7264 // build the packet and add the opcode
7265 BUILD_HEADER(EMP_EFFECT);
7266 ADD_DATA_U16(net_sig);
7267 ADD_DATA_FL(intensity);
7270 // send it to the player
7271 multi_io_send_to_all(data, packet_size);
7274 void process_emp_effect(ubyte *data, header *hinfo)
7276 float intensity, time;
7279 int offset = HEADER_LENGTH;
7281 // read in the EMP effect data
7282 GET_DATA_U16(net_sig);
7283 GET_DATA_FL(intensity);
7287 // try and find the object
7288 objp = multi_get_network_object(net_sig);
7289 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7290 // if i'm not an observer and I have a valid ship, play the EMP effect
7291 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7292 emp_start_local(intensity, time);
7295 // start the effect for the ship itself
7296 emp_start_ship(objp, intensity, time);
7300 // tells whether or not reinforcements are available
7301 void send_reinforcement_avail( int rnum )
7306 BUILD_HEADER(REINFORCEMENT_AVAIL);
7307 ADD_DATA_S32( rnum );
7308 multi_io_send_to_all_reliable(data, packet_size);
7311 void process_reinforcement_avail( ubyte *data, header *hinfo )
7316 offset = HEADER_LENGTH;
7317 GET_DATA_S32( rnum );
7320 // sanity check for a valid reinforcement number
7321 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7322 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7326 void send_change_iff_packet(ushort net_signature, int new_team)
7328 ubyte data[MAX_PACKET_SIZE];
7329 int packet_size = 0;
7331 if(Net_player == NULL){
7334 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7338 // build the packet and add the data
7339 BUILD_HEADER(CHANGE_IFF);
7340 ADD_DATA_U16(net_signature);
7341 ADD_DATA_S32(new_team);
7343 // send to all players
7344 multi_io_send_to_all_reliable(data, packet_size);
7347 void process_change_iff_packet( ubyte *data, header *hinfo)
7349 int offset = HEADER_LENGTH;
7350 ushort net_signature;
7355 GET_DATA_U16(net_signature);
7356 GET_DATA_S32(new_team);
7359 // lookup the object
7360 objp = multi_get_network_object(net_signature);
7361 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7362 Ships[objp->instance].team = new_team;
7366 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7368 int packet_size, objnum;
7369 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7372 net_player *ignore = NULL;
7374 // sanity checking for now
7375 Assert ( banks_fired <= 3 );
7377 // get an object pointer for this ship.
7378 objnum = shipp->objnum;
7379 objp = &Objects[objnum];
7381 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7382 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7386 // just in case nothing got fired
7387 if(banks_fired <= 0){
7391 // ubanks_fired = (ubyte)banks_fired;
7392 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7393 // Assert( current_bank <= 3 );
7395 // insert the current primary bank into this byte
7396 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7398 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7399 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7400 // ubanks_fired |= (1<<7);
7403 // determine if its a player ship and don't send to him if we're in "client firing" mode
7404 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7405 if(MULTIPLAYER_MASTER){
7406 np_index = multi_find_player_by_net_signature(objp->net_signature);
7407 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7408 ignore = &Net_players[np_index];
7412 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7413 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7414 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7415 // and server in sync w.r.t. weapon energy for player ship
7416 BUILD_HEADER( PRIMARY_FIRED_NEW );
7417 ADD_DATA_U16(objp->net_signature);
7418 // ADD_DATA(ubanks_fired);
7420 // if I'm a server, broadcast to all players
7421 if(MULTIPLAYER_MASTER){
7422 multi_io_send_to_all(data, packet_size, ignore);
7425 multi_rate_add(1, "wfi", packet_size);
7427 // otherwise just send to the server
7429 multi_io_send(Net_player, data, packet_size);
7433 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7435 int offset; // linked;
7436 // ubyte banks_fired, current_bank;
7441 // read all packet info
7442 offset = HEADER_LENGTH;
7443 GET_DATA_U16(shooter_sig);
7444 // GET_DATA(banks_fired);
7447 // find the object this fired packet is operating on
7448 objp = multi_get_network_object( shooter_sig );
7449 if ( objp == NULL ) {
7450 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7453 // if this object is not actually a valid ship, don't do anything
7454 if(objp->type != OBJ_SHIP){
7457 if(objp->instance < 0){
7460 shipp = &Ships[objp->instance];
7462 // get the link status of the primary banks
7464 // if ( banks_fired & (1<<7) ) {
7466 // banks_fired ^= (1<<7);
7469 // get the current primary bank
7470 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7471 // current_bank &= 0x3;
7472 // Assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7473 // shipp->weapons.current_primary_bank = current_bank;
7475 // strip off all remaining bits and just keep which banks were actually fired.
7476 // banks_fired &= 0x3;
7478 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7481 // shipp->flags &= ~SF_PRIMARY_LINKED;
7483 // shipp->flags |= SF_PRIMARY_LINKED;
7486 // if we're in client firing mode, ignore ones for myself
7487 if((Player_obj != NULL) && (Player_obj == objp)){
7491 ship_fire_primary( objp, 0, 1 );
7494 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7496 ubyte data[MAX_PACKET_SIZE];
7499 net_player *ignore = NULL;
7501 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7502 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7506 Assert ( cmeasure_count < UCHAR_MAX );
7507 BUILD_HEADER(COUNTERMEASURE_NEW);
7508 ADD_DATA_U16( objp->net_signature );
7509 ADD_DATA_S32( rand_val );
7511 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7513 // determine if its a player ship and don't send to him if we're in "client firing" mode
7514 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7515 if(MULTIPLAYER_MASTER){
7516 np_index = multi_find_player_by_net_signature(objp->net_signature);
7517 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7518 ignore = &Net_players[np_index];
7522 // if I'm the server, send to all players
7523 if(MULTIPLAYER_MASTER){
7524 multi_io_send_to_all(data, packet_size, ignore);
7526 // otherwise send to the server
7528 multi_io_send(Net_player, data, packet_size);
7532 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7539 offset = HEADER_LENGTH;
7540 GET_DATA_U16( signature );
7541 GET_DATA_S32( rand_val );
7544 objp = multi_get_network_object( signature );
7545 if ( objp == NULL ) {
7546 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7549 if(objp->type != OBJ_SHIP){
7553 // if we're in client firing mode, ignore ones for myself
7554 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7555 if((Player_obj != NULL) && (Player_obj == objp)){
7559 // make it so ship can fire right away!
7560 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7561 if ( objp == Player_obj ){
7562 nprintf(("network", "firing countermeasure from my ship\n"));
7564 ship_launch_countermeasure( objp, rand_val );
7567 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7569 ubyte data[MAX_PACKET_SIZE];
7570 int packet_size = 0;
7574 // only the server should ever be doing this
7575 Assert(MULTIPLAYER_MASTER);
7577 // setup outgoing data
7578 Assert(shooter != NULL);
7579 Assert(turret != NULL);
7580 Assert(target != NULL);
7581 Assert(override != NULL);
7582 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7585 u_beam_info = (ubyte)beam_info_index;
7586 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7587 Assert(subsys_index >= 0);
7588 if(subsys_index < 0){
7593 BUILD_HEADER(BEAM_FIRED);
7594 ADD_DATA_U16(shooter->net_signature);
7595 ADD_DATA(subsys_index);
7596 ADD_DATA_U16(target->net_signature);
7597 ADD_DATA(u_beam_info);
7598 ADD_DATA((*override));
7600 // send to all clients
7601 multi_io_send_to_all_reliable(data, packet_size);
7604 void process_beam_fired_packet(ubyte *data, header *hinfo)
7607 ushort shooter_sig, target_sig;
7611 beam_fire_info fire_info;
7613 // only clients should ever get this
7614 Assert(MULTIPLAYER_CLIENT);
7616 // read in packet data
7617 offset = HEADER_LENGTH;
7618 GET_DATA_U16(shooter_sig);
7619 GET_DATA(subsys_index);
7620 GET_DATA_U16(target_sig);
7621 GET_DATA(u_beam_info);
7623 b_info.dir_a.xyz.x = INTEL_FLOAT( &b_info.dir_a.xyz.x );
7624 b_info.dir_a.xyz.y = INTEL_FLOAT( &b_info.dir_a.xyz.y );
7625 b_info.dir_a.xyz.z = INTEL_FLOAT( &b_info.dir_a.xyz.z );
7626 b_info.dir_b.xyz.x = INTEL_FLOAT( &b_info.dir_b.xyz.x );
7627 b_info.dir_b.xyz.y = INTEL_FLOAT( &b_info.dir_b.xyz.y );
7628 b_info.dir_b.xyz.z = INTEL_FLOAT( &b_info.dir_b.xyz.z );
7629 b_info.delta_ang = INTEL_FLOAT( &b_info.delta_ang );
7630 for (int i=0; i<MAX_BEAM_SHOTS; i++){
7631 b_info.shot_aim[i] = INTEL_FLOAT( &b_info.shot_aim[i] );
7635 // lookup all relevant data
7636 fire_info.beam_info_index = (int)u_beam_info;
7637 fire_info.shooter = NULL;
7638 fire_info.target = NULL;
7639 fire_info.turret = NULL;
7640 fire_info.target_subsys = NULL;
7641 fire_info.beam_info_override = NULL;
7642 fire_info.shooter = multi_get_network_object(shooter_sig);
7643 fire_info.target = multi_get_network_object(target_sig);
7644 fire_info.beam_info_override = &b_info;
7645 fire_info.accuracy = 1.0f;
7646 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)){
7647 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7650 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7651 if(fire_info.turret == NULL){
7652 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7657 beam_fire(&fire_info);
7660 void send_sw_query_packet(ubyte code, char *txt)
7662 ubyte data[MAX_PACKET_SIZE];
7663 int packet_size = 0;
7665 // build the packet and add the code
7666 BUILD_HEADER(SW_STD_QUERY);
7668 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7672 // if I'm the host, send to standalone
7673 if(MULTIPLAYER_HOST){
7674 Assert(!MULTIPLAYER_MASTER);
7675 Assert(code == SW_STD_START);
7676 multi_io_send_reliable(Net_player, data, packet_size);
7678 // otherwise standalone sends back to host
7680 Assert(Game_mode & GM_STANDALONE_SERVER);
7681 Assert(code != SW_STD_START);
7682 Assert(Netgame.host != NULL);
7683 if(Netgame.host != NULL){
7684 multi_io_send_reliable(Netgame.host, data, packet_size);
7689 void process_sw_query_packet(ubyte *data, header *hinfo)
7693 void send_event_update_packet(int event)
7695 ubyte data[MAX_PACKET_SIZE];
7696 ushort u_event = (ushort)event;
7697 int packet_size = 0;
7699 // build the header and add the event
7700 BUILD_HEADER(EVENT_UPDATE);
7701 ADD_DATA_U16(u_event);
7702 ADD_DATA_S32(Mission_events[event].flags);
7703 ADD_DATA_S32(Mission_events[event].formula);
7704 ADD_DATA_S32(Mission_events[event].result);
7705 ADD_DATA_S32(Mission_events[event].count);
7707 // send to all players
7708 multi_io_send_to_all_reliable(data, packet_size);
7711 void process_event_update_packet(ubyte *data, header *hinfo)
7713 int offset = HEADER_LENGTH;
7718 GET_DATA_U16(u_event);
7719 store_flags = Mission_events[u_event].flags;
7720 GET_DATA_S32(Mission_events[u_event].flags);
7721 GET_DATA_S32(Mission_events[u_event].formula);
7722 GET_DATA_S32(Mission_events[u_event].result);
7723 GET_DATA_S32(Mission_events[u_event].count);
7726 // went from non directive special to directive special
7727 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7728 mission_event_set_directive_special(u_event);
7730 // if we went directive special to non directive special
7731 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7732 mission_event_unset_directive_special(u_event);
7736 // weapon detonate packet
7737 void send_weapon_detonate_packet(object *objp)
7739 ubyte data[MAX_PACKET_SIZE];
7740 int packet_size = 0;
7743 Assert(MULTIPLAYER_MASTER);
7744 if(!MULTIPLAYER_MASTER){
7747 Assert(objp != NULL);
7752 // build the header and add the data
7753 BUILD_HEADER(WEAPON_DET);
7754 ADD_DATA_U16(objp->net_signature);
7756 // send to all players
7757 multi_io_send_to_all(data, packet_size);
7760 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7763 int offset = HEADER_LENGTH;
7764 object *objp = NULL;
7766 // get the weapon signature
7767 GET_DATA_U16(net_sig);
7770 // lookup the weapon
7771 objp = multi_get_network_object(net_sig);
7772 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7773 weapon_detonate(objp);
7777 // flak fired packet
7778 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7781 ushort pnet_signature;
7782 ubyte data[MAX_PACKET_SIZE], cindex;
7788 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7792 // local setup -- be sure we are actually passing a weapon!!!!
7793 objp = &Objects[weapon_objnum];
7794 Assert ( objp->type == OBJ_WEAPON );
7795 pnet_signature = Objects[ship_objnum].net_signature;
7797 Assert( subsys_index < UCHAR_MAX );
7798 cindex = (ubyte)subsys_index;
7800 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7805 // build the fire turret packet.
7806 BUILD_HEADER(FLAK_FIRED);
7807 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7808 ADD_DATA_U16( pnet_signature );
7810 val = (short)ssp->submodel_info_1.angs.h;
7811 ADD_DATA_S16( val );
7812 val = (short)ssp->submodel_info_2.angs.p;
7813 ADD_DATA_S16( val );
7814 ADD_DATA_FL( flak_range );
7816 multi_io_send_to_all(data, packet_size);
7818 multi_rate_add(1, "flk", packet_size);
7821 void process_flak_fired_packet(ubyte *data, header *hinfo)
7823 int offset, weapon_objnum, wid;
7824 ushort pnet_signature;
7832 short pitch, heading;
7835 // get the data for the turret fired packet
7836 offset = HEADER_LENGTH;
7837 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7838 GET_DATA_U16( pnet_signature );
7839 GET_DATA( turret_index );
7840 GET_DATA_S16( heading );
7841 GET_DATA_S16( pitch );
7842 GET_DATA_FL( flak_range );
7843 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7846 objp = multi_get_network_object( pnet_signature );
7847 if ( objp == NULL ) {
7848 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7852 // if this isn't a ship, do nothing
7853 if ( objp->type != OBJ_SHIP ){
7857 // make an orientation matrix from the o_fvec
7858 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7860 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7861 // hack, but should be suitable.
7862 shipp = &Ships[objp->instance];
7863 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7867 wid = ssp->system_info->turret_weapon_type;
7868 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7872 // bash the position and orientation of the turret
7873 ssp->submodel_info_1.angs.h = (float)heading;
7874 ssp->submodel_info_2.angs.p = (float)pitch;
7876 // get the world position of the weapon
7877 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7879 // create the weapon object
7880 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7881 if (weapon_objnum != -1) {
7882 if ( Weapon_info[wid].launch_snd != -1 ) {
7883 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7886 // create a muzzle flash from a flak gun based upon firing position and weapon type
7887 flak_muzzle_flash(&pos, &dir, wid);
7889 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7890 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7894 #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);
7895 #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);
7897 // player pain packet
7898 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7900 ubyte data[MAX_PACKET_SIZE];
7903 int packet_size = 0;
7905 Assert(MULTIPLAYER_MASTER);
7906 if(!MULTIPLAYER_MASTER){
7914 // build the packet and add the code
7915 BUILD_HEADER(NETPLAYER_PAIN);
7916 windex = (ubyte)weapon_info_index;
7918 udamage = (ushort)damage;
7919 ADD_DATA_U16(udamage);
7920 //ADD_DATA((*force));
7921 add_vector_data( data, &packet_size, *force );
7922 //ADD_DATA((*hitpos));
7923 add_vector_data( data, &packet_size, *hitpos );
7925 // send to the player
7926 multi_io_send(pl, data, packet_size);
7928 multi_rate_add(1, "pai", packet_size);
7931 void process_player_pain_packet(ubyte *data, header *hinfo)
7937 vector local_hit_pos;
7940 // get the data for the pain packet
7941 offset = HEADER_LENGTH;
7943 GET_DATA_U16(udamage);
7945 get_vector_data( data, &offset, force );
7946 //GET_DATA(local_hit_pos);
7947 get_vector_data( data, &offset, local_hit_pos );
7950 mprintf(("PAIN!\n"));
7952 // get weapon info pointer
7953 Assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER));
7954 if(! ((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7957 wip = &Weapon_info[windex];
7959 // play the weapon hit sound
7960 Assert(Player_obj != NULL);
7961 if(Player_obj == NULL){
7964 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
7966 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
7967 ship_hit_pain((float)udamage);
7970 ship_apply_whack(&force, &local_hit_pos, Player_obj);
7974 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
7976 ubyte data[MAX_PACKET_SIZE];
7978 int packet_size = 0;
7980 // build the header and add the data
7981 BUILD_HEADER(LIGHTNING_PACKET);
7982 val = (char)bolt_type;
7984 //ADD_DATA((*start));
7985 add_vector_data( data, &packet_size, *start );
7986 //ADD_DATA((*strike));
7987 add_vector_data( data, &packet_size, *strike );
7989 // send to everyone unreliable for now
7990 multi_io_send_to_all(data, packet_size);
7993 void process_lightning_packet(ubyte *data, header *hinfo)
7997 vector start, strike;
8000 offset = HEADER_LENGTH;
8001 GET_DATA(bolt_type);
8003 get_vector_data(data, &offset, start);
8004 // GET_DATA(strike);
8005 get_vector_data(data, &offset, strike);
8014 nebl_bolt(bolt_type, &start, &strike);
8017 void send_bytes_recvd_packet(net_player *pl)
8019 // only clients should ever be doing this
8024 ubyte data[MAX_PACKET_SIZE];
8025 int packet_size = 0;
8026 BUILD_HEADER(BYTES_SENT);
8027 ADD_DATA_S32(pl->cl_bytes_recvd);
8029 // send to the server
8030 multi_io_send_reliable(pl, data, packet_size);
8033 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8037 net_player *pl = NULL;
8038 int offset = HEADER_LENGTH;
8040 GET_DATA_S32(bytes);
8044 if(Net_player == NULL){
8047 if(!MULTIPLAYER_MASTER){
8051 // make sure we know what player sent this
8052 pid = find_player_id(hinfo->id);
8053 if((pid < 0) || (pid >= MAX_PLAYERS)){
8056 pl = &Net_players[pid];
8059 pl->cl_bytes_recvd = bytes;
8063 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8066 pl->sv_bytes_sent = 0;
8070 void send_host_captain_change_packet(short player_id, int captain_change)
8072 ubyte data[MAX_PACKET_SIZE];
8073 int packet_size = 0;
8076 BUILD_HEADER(TRANSFER_HOST);
8077 ADD_DATA_S16(player_id);
8078 ADD_DATA_S32(captain_change);
8081 multi_io_send_to_all_reliable(data, packet_size);
8084 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8086 int offset = HEADER_LENGTH;
8087 int idx, found_player, captain_change;
8090 // get the player id
8091 GET_DATA_S16(player_id);
8092 GET_DATA_S32(captain_change);
8098 for(idx=0; idx<MAX_PLAYERS; idx++){
8099 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8100 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8105 // unflag all old players
8106 for(idx=0; idx<MAX_PLAYERS; idx++){
8107 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8112 for(idx=0; idx<MAX_PLAYERS; idx++){
8113 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8114 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8116 // spew to the HUD config
8117 if(Net_players[idx].player != NULL){
8118 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8128 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8133 void send_self_destruct_packet()
8135 ubyte data[MAX_PACKET_SIZE];
8136 int packet_size = 0;
8139 if(Net_player == NULL){
8143 // if i'm the server, I shouldn't be here
8144 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8145 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8149 // only if this is valid
8150 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8155 if((Player_ship == NULL) || (Player_obj == NULL)){
8160 BUILD_HEADER(SELF_DESTRUCT);
8161 ADD_DATA_U16(Player_obj->net_signature);
8163 // send to the server
8164 multi_io_send_reliable(Net_player, data, packet_size);
8167 void process_self_destruct_packet(ubyte *data, header *hinfo)
8169 int offset = HEADER_LENGTH;
8173 // get the net signature
8174 GET_DATA_U16(net_sig);
8178 np_index = find_player_id(hinfo->id);
8182 if(MULTI_OBSERVER(Net_players[np_index])){
8185 if(Net_players[np_index].player == NULL){
8188 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8191 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8194 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8197 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8202 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);