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.11 2006/04/26 19:48:58 taylor
19 * various big-endian fixes, mainly networking support related
21 * Revision 1.10 2005/10/02 09:30:10 taylor
22 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
24 * Revision 1.9 2005/08/12 08:59:17 taylor
27 * Revision 1.8 2004/09/20 01:31:44 theoddone33
30 * Revision 1.7 2004/06/11 01:49:45 tigital
31 * byte-swapping changes for bigendian systems
33 * Revision 1.6 2003/08/03 16:10:29 taylor
34 * cleanup; compile warning fixes
36 * Revision 1.5 2002/06/17 06:33:10 relnev
37 * ryan's struct patch for gcc 2.95
39 * Revision 1.4 2002/06/09 04:41:24 relnev
40 * added copyright header
42 * Revision 1.3 2002/05/26 20:49:54 theoddone33
45 * Revision 1.2 2002/05/07 03:16:47 theoddone33
46 * The Great Newline Fix
48 * Revision 1.1.1.1 2002/05/03 03:28:10 root
52 * 83 9/14/99 2:21p Dave
53 * Fixed observer mode joining and ingame stuff.
55 * 82 9/14/99 3:26a Dave
56 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
57 * respawn-too-early problem. Made a few crash points safe.
59 * 81 9/13/99 4:52p Dave
62 * 80 9/08/99 10:01p Dave
63 * Make sure game won't run in a drive's root directory. Make sure
64 * standalone routes suqad war messages properly to the host.
66 * 79 8/28/99 4:54p Dave
67 * Fixed directives display for multiplayer clients for wings with
68 * multiple waves. Fixed hud threat indicator rendering color.
70 * 78 8/27/99 12:32a Dave
71 * Allow the user to specify a local port through the launcher.
73 * 77 8/26/99 8:51p Dave
74 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
76 * 76 8/25/99 4:38p Dave
77 * Updated PXO stuff. Make squad war report stuff much more nicely.
79 * 75 8/24/99 1:50a Dave
80 * Fixed client-side afterburner stuttering. Added checkbox for no version
81 * checking on PXO join. Made button info passing more friendly between
84 * 74 8/22/99 5:53p Dave
85 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
86 * instead of ship designations for multiplayer players.
88 * 73 8/22/99 1:55p Dave
89 * Cleaned up host/team-captain leaving code.
91 * 72 8/22/99 1:19p Dave
92 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
93 * which d3d cards are detected.
95 * 71 8/19/99 10:59a Dave
96 * Packet loss detection.
98 * 70 8/17/99 1:12p Dave
99 * Send TvT update when a client has finished joining so he stays nice and
102 * 69 8/16/99 4:05p Dave
103 * Big honking checkin.
105 * 68 8/11/99 5:54p Dave
106 * Fixed collision problem. Fixed standalone ghost problem.
108 * 67 8/06/99 9:46p Dave
109 * Hopefully final changes for the demo.
111 * 66 8/05/99 2:06a Dave
114 * 65 7/30/99 7:01p Dave
115 * Dogfight escort gauge. Fixed up laser rendering in Glide.
117 * 64 7/29/99 5:41p Jefff
118 * Sound hooks for cmeasure success
120 * 63 7/28/99 5:34p Dave
121 * Nailed the missing stats bug to the wall. Problem was optimized build
122 * and using GET_DATA() with array elements. BLECH.
124 * 62 7/26/99 5:50p Dave
125 * Revised ingame join. Better? We'll see....
127 * 61 7/24/99 1:54p Dave
128 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
131 * 60 7/22/99 7:17p Dave
132 * Fixed excessive whacks in multiplayer.
134 * 59 7/08/99 10:53a Dave
135 * New multiplayer interpolation scheme. Not 100% done yet, but still
136 * better than the old way.
138 * 58 7/03/99 5:50p Dave
139 * Make rotated bitmaps draw properly in padlock views.
141 * 57 7/03/99 4:08p Dave
142 * Fixed wss_slots size issues. Fixed potentially nasty bug in low level
145 * 56 6/21/99 7:24p Dave
146 * netplayer pain packet. Added type E unmoving beams.
148 * 55 6/18/99 5:16p Dave
149 * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
150 * dialog to PXO screen.
152 * 54 6/16/99 4:06p Dave
153 * New pilot info popup. Added new draw-bitmap-as-poly function.
155 * 53 6/16/99 10:20a Dave
156 * Added send-message-list sexpression.
158 * 52 6/04/99 3:52p Anoop
159 * Removed bogus assert.
161 * 51 6/01/99 8:35p Dave
162 * Finished lockarm weapons. Added proper supercap weapons/damage. Added
163 * awacs-set-radius sexpression.
165 * 50 5/21/99 5:03p Andsager
166 * Add code to display engine wash death. Modify ship_kill_packet
168 * 49 5/18/99 1:30p Dave
169 * Added muzzle flash table stuff.
171 * 48 5/14/99 1:59p Andsager
172 * Multiplayer message for subsystem cargo revealed.
174 * 47 5/14/99 12:15p Andsager
175 * Add vaporized to kill packet
177 * 46 5/03/99 8:32p Dave
178 * New version of multi host options screen.
180 * 45 4/30/99 12:18p Dave
181 * Several minor bug fixes.
183 * 44 4/29/99 2:29p Dave
184 * Made flak work much better in multiplayer.
186 * 43 4/28/99 11:13p Dave
187 * Temporary checkin of artillery code.
189 * 42 4/16/99 5:54p Dave
190 * Support for on/off style "stream" weapons. Real early support for
191 * target-painting lasers.
193 * 41 4/12/99 2:22p Dave
194 * More checks for dogfight stats.
196 * 40 4/09/99 2:21p Dave
197 * Multiplayer beta stuff. CD checking.
199 * 39 4/02/99 9:55a Dave
200 * Added a few more options in the weapons.tbl for beam weapons. Attempt
201 * at putting "pain" packets into multiplayer.
203 * 38 4/01/99 3:41p Anoop
204 * Removed bogus Int3().
206 * 37 3/19/99 9:51a Dave
207 * Checkin to repair massive source safe crash. Also added support for
208 * pof-style nebulae, and some new weapons code.
210 * 38 3/12/99 2:32p Anoop
211 * Removed bogus asserts.
213 * 37 3/11/99 11:41a Neilk
214 * Don't do multi_io_* operations in single-player
216 * 36 3/10/99 6:50p Dave
217 * Changed the way we buffer packets for all clients. Optimized turret
218 * fired packets. Did some weapon firing optimizations.
220 * 35 3/09/99 6:24p Dave
221 * More work on object update revamping. Identified several sources of
222 * unnecessary bandwidth.
224 * 34 3/08/99 7:03p Dave
225 * First run of new object update system. Looks very promising.
227 * 33 3/04/99 6:09p Dave
228 * Added in sexpressions for firing beams and checking for if a ship is
231 * 32 3/01/99 10:00a Dave
232 * Fxied several dogfight related stats bugs.
234 * 31 2/24/99 2:25p Dave
235 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
236 * bug for dogfight more.
238 * 30 2/23/99 2:29p Dave
239 * First run of oldschool dogfight mode.
241 * 29 2/21/99 6:01p Dave
242 * Fixed standalone WSS packets.
244 * 28 2/21/99 1:48p Dave
245 * Some code for monitoring datarate for multiplayer in detail.
247 * 27 2/17/99 2:11p Dave
248 * First full run of squad war. All freespace and tracker side stuff
251 * 26 2/12/99 6:16p Dave
252 * Pre-mission Squad War code is 95% done.
254 * 25 2/11/99 3:08p Dave
255 * PXO refresh button. Very preliminary squad war support.
257 * 24 1/29/99 5:07p Dave
258 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
261 * 23 1/27/99 9:56a Dave
262 * Temporary checkin of beam weapons for Dan to make cool sounds.
264 * 22 1/26/99 6:33p Anoop
265 * Fixed multiplayer slot switching problem (be sure to remember that
266 * hinfo->id is player id# _not_ player index #)
268 * 21 1/24/99 11:37p Dave
269 * First full rev of beam weapons. Very customizable. Removed some bogus
270 * Int3()'s in low level net code.
272 * 20 1/15/99 4:37p Dave
273 * Potential fix for weapon pair problem.
275 * 19 1/14/99 6:06p Dave
276 * 100% full squad logo support for single player and multiplayer.
278 * 18 1/14/99 12:48a Dave
279 * Todo list bug fixes. Made a pass at putting briefing icons back into
280 * FRED. Sort of works :(
282 * 17 1/12/99 5:45p Dave
283 * Moved weapon pipeline in multiplayer to almost exclusively client side.
284 * Very good results. Bandwidth goes down, playability goes up for crappy
285 * connections. Fixed object update problem for ship subsystems.
287 * 16 1/08/99 4:56p Anoop
288 * Fixed a problem with wss request packets.
290 * 15 12/18/98 12:24p Markm
291 * Fixed a dumb bug where player image_filenames were not being passed
292 * properly in new players packet.
294 * 14 12/14/98 12:13p Dave
295 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
298 * 13 11/30/98 1:07p Dave
299 * 16 bit conversion, first run.
301 * 12 11/20/98 4:08p Dave
302 * Fixed flak effect in multiplayer.
304 * 11 11/19/98 4:19p Dave
305 * Put IPX sockets back in psnet. Consolidated all multiplayer config
308 * 10 11/19/98 8:04a Dave
309 * Full support for D3-style reliable sockets. Revamped packet lag/loss
310 * system, made it receiver side and at the lowest possible level.
312 * 9 11/17/98 11:12a Dave
313 * Removed player identification by address. Now assign explicit id #'s.
315 * 8 11/12/98 11:50a Dave
316 * Multiplayer clients set flak range to be very long.
318 * 7 11/12/98 12:13a Dave
319 * Tidied code up for multiplayer test. Put in network support for flak
322 * 6 11/05/98 5:55p Dave
323 * Big pass at reducing #includes
325 * 5 10/20/98 1:39p Andsager
326 * Make so sparks follow animated ship submodels. Modify
327 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
328 * submodel_num. Add submodel_num to multiplayer hit packet.
330 * 4 10/13/98 9:29a Dave
331 * Started neatening up freespace.h. Many variables renamed and
332 * reorganized. Added AlphaColors.[h,cpp]
334 * 3 10/07/98 6:27p Dave
335 * Globalized mission and campaign file extensions. Removed Silent Threat
336 * special code. Moved \cache \players and \multidata into the \data
339 * 2 10/07/98 10:53a Dave
342 * 1 10/07/98 10:50a Dave
344 * 506 10/02/98 3:22p Allender
345 * fix up the -connect option and fix the -port option
347 * 505 10/02/98 11:45a Dave
348 * Fixed stupid chat message bug.
350 * 504 9/29/98 1:33p Dave
351 * Remove standalone only conditional compiles for pre 1.04 stuff.
353 * 503 9/28/98 1:54p Dave
354 * Make sure French and German don't xfer builtin files they don't have
357 * 502 9/20/98 7:19p Dave
358 * Added CHANGE_IFF packet.
360 * 501 9/17/98 3:08p Dave
361 * PXO to non-pxo game warning popup. Player icon stuff in create and join
362 * game screens. Upped server count refresh time in PXO to 35 secs (from
371 #include <io.h> // for findfirst/findnext, etc
374 #include "multimsgs.h"
375 #include "multiutil.h"
378 #include "multiteamselect.h"
379 #include "linklist.h"
380 #include "gamesequence.h"
381 #include "hudmessage.h"
382 #include "hudsquadmsg.h"
383 #include "freespace.h"
387 #include "missiongoals.h"
388 #include "missionparse.h"
389 #include "missionlog.h"
390 #include "missionmessage.h"
391 #include "missionbrief.h"
393 #include "cmeasure.h"
394 #include "model.h" // for some limits
395 #include "afterburner.h"
396 #include "stand_server.h"
397 #include "multi_xfer.h"
403 #include "managepilot.h"
404 #include "hudsquadmsg.h"
406 #include "missionweaponchoice.h"
407 #include "missionshipchoice.h"
408 #include "fireballs.h"
411 #include "multi_ingame.h"
412 #include "multiteamselect.h"
414 #include "multi_campaign.h"
415 #include "multi_team.h"
416 #include "multi_respawn.h"
417 #include "multi_observer.h"
418 #include "multi_voice.h"
419 #include "asteroid.h"
420 #include "multi_pmsg.h"
421 #include "multi_data.h"
422 #include "multi_options.h"
423 #include "objcollide.h"
424 #include "hudreticle.h"
425 #include "multi_pause.h"
426 #include "multi_endgame.h"
427 #include "missiondebrief.h"
428 #include "multi_obj.h"
429 #include "multi_log.h"
431 #include "multi_kick.h"
435 #include "multi_rate.h"
436 #include "neblightning.h"
437 #include "hudescort.h"
439 // #define _MULTI_SUPER_WACKY_COMPRESSION
441 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
443 #define MAX_CODE ( ( 1 << BITS ) - 1 )
444 #define TABLE_SIZE 35023L
445 #define END_OF_STREAM 256
446 #define BUMP_CODE 257
447 #define FLUSH_CODE 258
448 #define FIRST_CODE 259
457 static DICTIONARY dict[TABLE_SIZE];
458 static char decode_stack[TABLE_SIZE];
459 static uint next_code;
460 static int current_code_bits;
461 static uint next_bump_code;
463 typedef struct BitBuf {
469 void output_bits( BitBuf *bitbuf, uint code, int count )
473 mask = 1L << ( count - 1 );
476 bitbuf->rack |= bitbuf->mask;
478 if ( bitbuf->mask == 0 ) {
479 *bitbuf->data++=(ubyte)bitbuf->rack;
487 uint input_bits( BitBuf *bitbuf, int bit_count )
492 mask = 1L << ( bit_count - 1 );
495 if ( bitbuf->mask == 0x80 ) {
496 bitbuf->rack = *bitbuf->data++;
497 if ( bitbuf->rack == EOF )
498 return END_OF_STREAM;
500 if ( bitbuf->rack & bitbuf->mask )
501 return_value |= mask;
504 if ( bitbuf->mask == 0 )
507 return( return_value );
511 static void InitializeDictionary()
515 for ( i = 0 ; i < TABLE_SIZE ; i++ )
516 dict[i].code_value = UNUSED;
518 next_code = FIRST_CODE;
519 current_code_bits = 9;
520 next_bump_code = 511;
524 static uint find_child_node( int parent_code, int child_character )
529 index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
533 offset = TABLE_SIZE - index;
535 if ( dict[ index ].code_value == UNUSED )
536 return( (uint) index );
537 if ( dict[ index ].parent_code == parent_code &&
538 dict[ index ].character == (char) child_character )
540 if ( (int) index >= offset )
543 index += TABLE_SIZE - offset;
548 static uint decode_string( uint count, uint code )
550 while ( code > 255 ) {
551 decode_stack[ count++ ] = dict[ code ].character;
552 code = dict[ code ].parent_code;
554 decode_stack[ count++ ] = (char) code;
558 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size )
566 // Init output bit buffer
569 output.data = outputbuf;
571 InitializeDictionary();
573 string_code = *inputbuf++;
575 for ( i=1 ; i<input_size ; i++ ) {
576 character = *inputbuf++;
577 index = find_child_node( string_code, character );
578 if ( dict[ index ].code_value != - 1 )
579 string_code = dict[ index ].code_value;
581 dict[ index ].code_value = next_code++;
582 dict[ index ].parent_code = string_code;
583 dict[ index ].character = (char) character;
584 output_bits( &output, (unsigned long) string_code, current_code_bits );
585 string_code = character;
586 if ( next_code > MAX_CODE ) {
587 output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
588 InitializeDictionary();
589 } else if ( next_code > next_bump_code ) {
590 output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
592 next_bump_code <<= 1;
597 output_bits( &output, (unsigned long) string_code, current_code_bits );
598 output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
600 if ( output.mask != 0x80 )
601 *output.data++ = (ubyte)output.rack;
603 return output.data-outputbuf;
607 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf )
618 input.data = inputbuf;
622 InitializeDictionary();
623 old_code = (uint) input_bits( &input, current_code_bits );
624 if ( old_code == END_OF_STREAM )
626 character = old_code;
627 outputbuf[counter++] = ( ubyte )old_code;
629 new_code = (uint) input_bits( &input, current_code_bits );
630 if ( new_code == END_OF_STREAM )
632 if ( new_code == FLUSH_CODE )
634 if ( new_code == BUMP_CODE ) {
638 if ( new_code >= next_code ) {
639 decode_stack[ 0 ] = (char) character;
640 count = decode_string( 1, old_code );
642 count = decode_string( 0, new_code );
644 character = decode_stack[ count - 1 ];
646 outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
647 dict[ next_code ].parent_code = old_code;
648 dict[ next_code ].character = (char) character;
656 // process a join request packet add
657 void add_join_request(ubyte *data, int *size, join_request *jr)
659 int packet_size = *size;
660 join_request *jr_tmp = jr;
662 jr_tmp->tracker_id = INTEL_INT(jr->tracker_id);
663 jr_tmp->player_options.flags = INTEL_INT(jr->player_options.flags);
664 jr_tmp->player_options.obj_update_level = INTEL_INT(jr->player_options.obj_update_level);
671 // process a join request packet get
672 void get_join_request(ubyte *data, int *size, join_request jr)
678 jr.tracker_id = INTEL_INT(jr.tracker_id);
679 jr.player_options.flags = INTEL_INT(jr.player_options.flags);
680 jr.player_options.obj_update_level = INTEL_INT(jr.player_options.obj_update_level);
685 struct net_addr_compat {
692 SDL_COMPILE_TIME_ASSERT(net_addr_compat, sizeof(net_addr_compat) == 16);
694 void add_net_addr(ubyte *data, int &size, const net_addr *addr)
696 int packet_size = size;
697 net_addr_compat addr_c;
701 addr_c.type = INTEL_INT(addr->type);
702 addr_c.port = INTEL_SHORT(addr->port);
703 memcpy(&addr_c.addr, &addr->addr, IP_ADDRESS_LENGTH);
710 void get_net_addr(const ubyte *data, int &size, net_addr &addr)
713 net_addr_compat addr_c;
719 addr.type = INTEL_INT(addr_c.type);
720 addr.port = INTEL_SHORT(addr_c.port);
721 memcpy(&addr.addr, &addr_c.addr, IP_ADDRESS_LENGTH);
726 void add_vector_data(ubyte *data, int *size, vector vec)
728 int packet_size = *size;
730 ADD_FLOAT(vec.xyz.x);
731 ADD_FLOAT(vec.xyz.y);
732 ADD_FLOAT(vec.xyz.z);
737 void get_vector_data(ubyte *data, int *size, vector vec)
741 GET_FLOAT(vec.xyz.x);
742 GET_FLOAT(vec.xyz.y);
743 GET_FLOAT(vec.xyz.z);
748 // send the specified data packet to all players
749 void multi_io_send(net_player *pl, ubyte *data, int len)
752 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
756 // don't do it for single player
757 if(!(Game_mode & GM_MULTIPLAYER)){
762 if(MULTIPLAYER_CLIENT){
763 // SDL_assert(pl == Net_player);
764 if(pl != Net_player){
768 // SDL_assert(pl != Net_player);
769 if(pl == Net_player){
774 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
775 if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
776 multi_io_send_force(pl);
777 pl->s_info.unreliable_buffer_size = 0;
780 SDL_assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
782 memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
783 pl->s_info.unreliable_buffer_size += len;
786 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
789 SDL_assert(MULTIPLAYER_MASTER);
791 // need to check for i > 1, hmmm... and connected. I don't know.
792 for (i = 0; i < MAX_PLAYERS; i++ ) {
793 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
797 // maybe ignore a player
798 if((ignore != NULL) && (&Net_players[i] == ignore)){
802 // ingame joiners not waiting to select a ship doesn't get any packets
803 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
808 multi_io_send(&Net_players[i], data, length);
812 void multi_io_send_force(net_player *pl)
815 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
819 // don't do it for single player
820 if(!(Game_mode & GM_MULTIPLAYER)){
824 // send everything in
825 if (MULTIPLAYER_MASTER) {
826 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
828 // add the bytes sent to this player
829 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
831 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
833 pl->s_info.unreliable_buffer_size = 0;
836 // send the data packet to all players via their reliable sockets
837 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
840 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
844 // don't do it for single player
845 if(!(Game_mode & GM_MULTIPLAYER)){
850 if(MULTIPLAYER_CLIENT){
851 // SDL_assert(pl == Net_player);
852 if(pl != Net_player){
856 // SDL_assert(pl != Net_player);
857 if(pl == Net_player){
862 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
863 if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
864 multi_io_send_reliable_force(pl);
865 pl->s_info.reliable_buffer_size = 0;
868 SDL_assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
870 memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
871 pl->s_info.reliable_buffer_size += len;
874 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
877 SDL_assert(MULTIPLAYER_MASTER);
879 // need to check for i > 1, hmmm... and connected. I don't know.
880 for (i = 0; i < MAX_PLAYERS; i++ ) {
881 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
885 // maybe ignore a player
886 if((ignore != NULL) && (&Net_players[i] == ignore)){
890 // ingame joiners not waiting to select a ship doesn't get any packets
891 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
896 multi_io_send_reliable(&Net_players[i], data, length);
900 void multi_io_send_reliable_force(net_player *pl)
903 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
907 // don't do it for single player
908 if(!(Game_mode & GM_MULTIPLAYER)){
912 // send everything in
913 if(MULTIPLAYER_MASTER) {
914 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
915 } else if(Net_player != NULL){
916 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
918 pl->s_info.reliable_buffer_size = 0;
921 // send all buffered packets
922 void multi_io_send_buffered_packets()
926 // don't do it for single player
927 if(!(Game_mode & GM_MULTIPLAYER)){
932 if(MULTIPLAYER_MASTER){
933 for(idx=0; idx<MAX_PLAYERS; idx++){
934 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
935 // force unreliable data
936 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
937 multi_io_send_force(&Net_players[idx]);
938 Net_players[idx].s_info.unreliable_buffer_size = 0;
941 // force reliable data
942 if(Net_players[idx].s_info.reliable_buffer_size > 0){
943 multi_io_send_reliable_force(&Net_players[idx]);
944 Net_players[idx].s_info.reliable_buffer_size = 0;
950 else if(Net_player != NULL){
951 // force unreliable data
952 if(Net_player->s_info.unreliable_buffer_size > 0){
953 multi_io_send_force(Net_player);
954 Net_player->s_info.unreliable_buffer_size = 0;
957 // force reliable data
958 if(Net_player->s_info.reliable_buffer_size > 0){
959 multi_io_send_reliable_force(Net_player);
960 Net_player->s_info.reliable_buffer_size = 0;
965 // 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)
966 void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
968 ubyte data[MAX_PACKET_SIZE],mode;
971 BUILD_HEADER(GAME_CHAT);
974 ADD_SHORT(from->player_id);
976 // add the message mode and if in MSG_TARGET mode, add who the target is
978 mode = (ubyte)msg_mode;
981 case MULTI_MSG_TARGET:
982 SDL_assert(to != NULL);
983 ADD_SHORT(to->player_id);
986 SDL_assert(expr != NULL);
990 // add the message itself
993 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
995 // message all players
997 for(idx=0;idx<MAX_PLAYERS;idx++){
998 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
999 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1004 // message only friendly players
1005 case MULTI_MSG_FRIENDLY:
1006 for(idx=0;idx<MAX_PLAYERS;idx++){
1007 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)){
1008 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1013 // message only hostile players
1014 case MULTI_MSG_HOSTILE:
1015 for(idx=0;idx<MAX_PLAYERS;idx++){
1016 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)){
1017 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1022 // message the player's target
1023 case MULTI_MSG_TARGET:
1024 SDL_assert(to != NULL);
1025 if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
1026 multi_io_send_reliable(to, data, packet_size);
1030 // message all players who match the expression string
1031 case MULTI_MSG_EXPR:
1032 SDL_assert(expr != NULL);
1033 for(idx=0;idx<MAX_PLAYERS;idx++){
1034 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
1035 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1041 // send to the server, who will take care of routing it
1043 multi_io_send_reliable(Net_player, data, packet_size);
1047 // process a general game chat packet, if we're the standalone we should rebroadcast
1048 void process_game_chat_packet( ubyte *data, header *hinfo )
1052 int color_index,player_index,to_player_index,should_display,server_msg;
1053 char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
1057 offset = HEADER_LENGTH;
1059 // get the id of the sender
1062 // determine if this is a server message
1063 GET_INT(server_msg);
1068 // if targeting a specific player, get the address
1071 case MULTI_MSG_TARGET:
1074 case MULTI_MSG_EXPR:
1078 // get the message itself
1082 // get the index of the sending player
1083 color_index = find_player_id(from);
1084 player_index = color_index;
1086 // if we couldn't find the player - bail
1087 if(player_index == -1){
1088 nprintf(("Network","Could not find player for processing game chat packet!\n"));
1094 // if we're the server, determine what to do with the packet here
1095 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1096 // if he's targeting a specific player, find out who it is
1097 if(mode == MULTI_MSG_TARGET){
1098 to_player_index = find_player_id(to);
1100 to_player_index = -1;
1103 // if we couldn't find who sent the message or who should be getting the message, the bail
1104 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
1108 // determine if _I_ should be seeing the text
1109 if(Game_mode & GM_STANDALONE_SERVER){
1112 // check against myself for several specific cases
1114 if((mode == MULTI_MSG_ALL) ||
1115 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
1116 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
1117 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
1118 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
1123 // if we're the server of a game, we need to rebroadcast to all other players
1125 // individual target mission
1126 case MULTI_MSG_TARGET:
1127 // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
1128 if(to_player_index != MY_NET_PLAYER_NUM){
1129 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1133 case MULTI_MSG_EXPR:
1134 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1138 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1142 // if a client receives this packet, its always ok for him to display it
1147 // if we're not on a standalone
1149 if(server_msg == 2){
1152 multi_display_chat_msg(msg, player_index, !server_msg);
1157 // broadcast a hud message to all players
1158 void send_hud_msg_to_all( char* msg )
1160 ubyte data[MAX_PACKET_SIZE];
1163 // only the server should be sending this packet
1164 BUILD_HEADER(HUD_MSG);
1168 multi_io_send_to_all( data, packet_size );
1171 // process an incoming hud message packet
1172 void process_hud_message(ubyte* data, header* hinfo)
1175 char msg_buffer[255];
1177 offset = HEADER_LENGTH;
1179 GET_STRING(msg_buffer);
1182 // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1183 if(Game_mode & GM_IN_MISSION){
1184 HUD_printf(msg_buffer);
1188 // send a join packet request to the specified address (should be a server)
1189 void send_join_packet(net_addr* addr,join_request *jr)
1191 ubyte data[MAX_PACKET_SIZE];
1194 // build the header and add the request
1197 add_join_request(data, &packet_size, jr);
1199 psnet_send(addr, data, packet_size);
1202 // process an incoming join request packet
1203 void process_join_packet(ubyte* data, header* hinfo)
1208 int host_restr_mode;
1209 // int team0_avail,team1_avail;
1210 char join_string[255];
1213 // only the server of the game should ever receive this packet
1214 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1217 offset = HEADER_LENGTH;
1219 // read in the request info
1220 memset(&jr,0,sizeof(join_request));
1223 jr.tracker_id = INTEL_INT(jr.tracker_id);
1227 // fill in the address information of where this came from
1228 fill_net_addr(&addr, hinfo->addr, hinfo->port);
1230 // determine if we should accept this guy, or return a reason we should reject him
1231 // see the DENY_* codes in multi.h
1232 ret_code = multi_eval_join_request(&jr,&addr);
1234 // evaluate the return code
1236 // he should be accepted
1240 // we have to query the host because this is a restricted game
1241 case JOIN_QUERY_RESTRICTED :
1242 if(!(Game_mode & GM_STANDALONE_SERVER)){
1243 // notify the host of the event
1244 snd_play(&Snds[SND_CUE_VOICE]);
1247 // set the query timestamp
1248 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1249 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1251 // determine what mode we're in
1252 // host_restr_mode = -1;
1253 memset(join_string,0,255);
1254 // if(Netgame.type == NG_TYPE_TEAM){
1255 // multi_player_ships_available(&team0_avail,&team1_avail);
1257 // if(team0_avail && team1_avail){
1258 // host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1259 // sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1260 // } else if(team0_avail && !team1_avail){
1261 // host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1262 // sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1263 // } else if(!team0_avail && team1_avail){
1264 // host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1265 // sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1267 // } else if(Netgame.mode == NG_MODE_RESTRICTED){
1268 host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1269 SDL_snprintf(join_string,SDL_arraysize(join_string),XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1271 SDL_assert(host_restr_mode != -1);
1273 // store the request info
1274 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1275 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1276 Multi_join_restr_mode = host_restr_mode;
1278 // if i'm the standalone server, I need to send a query to the host
1279 if(Game_mode & GM_STANDALONE_SERVER){
1280 send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1282 HUD_printf(join_string);
1286 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1290 // he'e being denied for some reason
1292 // send him the reason he is being denied
1293 send_deny_packet(&addr,ret_code);
1297 // process the rest of the request
1298 multi_process_valid_join_request(&jr,&addr);
1301 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1302 void send_new_player_packet(int new_player_num,net_player *target)
1304 ubyte data[MAX_PACKET_SIZE], val;
1305 int packet_size = 0;
1307 BUILD_HEADER( NOTIFY_NEW_PLAYER );
1309 // add the new player's info
1310 ADD_INT(new_player_num);
1311 // ADD_DATA(Net_players[new_player_num].p_info.addr);
1313 add_net_addr(data, packet_size, &Net_players[new_player_num].p_info.addr);
1315 ADD_SHORT(Net_players[new_player_num].player_id);
1316 ADD_INT(Net_players[new_player_num].flags);
1317 ADD_STRING(Net_players[new_player_num].player->callsign);
1318 ADD_STRING(Net_players[new_player_num].player->image_filename);
1319 ADD_STRING(Net_players[new_player_num].player->squad_filename);
1320 ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1322 val = (ubyte)Net_players[new_player_num].p_info.team;
1325 // broadcast the data
1327 multi_io_send_reliable(target, data, packet_size);
1329 multi_io_send_to_all_reliable(data, packet_size);
1333 // process a notification for a new player who has joined the game
1334 void process_new_player_packet(ubyte* data, header* hinfo)
1336 int already_in_game = 0;
1337 int offset, new_player_num,player_num,new_flags;
1339 char new_player_name[CALLSIGN_LEN+2] = "";
1340 char new_player_image[MAX_FILENAME_LEN+1] = "";
1341 char new_player_squad[MAX_FILENAME_LEN+1] = "";
1342 char new_player_pxo_squad[LOGIN_LEN+1] = "";
1343 char notify_string[256];
1347 offset = HEADER_LENGTH;
1349 // get the new players information
1350 GET_INT(new_player_num);
1351 memset(&new_addr, 0, sizeof(net_addr));
1352 get_net_addr(data, offset, new_addr);
1356 GET_STRING(new_player_name);
1357 GET_STRING(new_player_image);
1358 GET_STRING(new_player_squad);
1359 GET_STRING(new_player_pxo_squad);
1363 player_num = multi_find_open_player_slot();
1364 SDL_assert(player_num != -1);
1366 // note that this new code does not check for duplicate IPs. It merely checks to see if
1367 // the slot referenced by new_player_num is already occupied by a connected player
1368 if(MULTI_CONNECTED(Net_players[new_player_num])){
1372 // if he's not alreayd in the game for one reason or another
1373 if ( !already_in_game ) {
1374 if ( Game_mode & GM_IN_MISSION ){
1375 HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1378 // create the player
1379 if(new_flags & NETINFO_FLAG_OBSERVER){
1380 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1381 Net_players[new_player_num].flags |= new_flags;
1383 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1384 Net_players[new_player_num].flags |= new_flags;
1387 // copy in the filename
1388 if(strlen(new_player_image) > 0){
1389 SDL_strlcpy(Net_players[new_player_num].player->image_filename, new_player_image, MAX_FILENAME_LEN);
1391 SDL_strlcpy(Net_players[new_player_num].player->image_filename, "", MAX_FILENAME_LEN);
1393 // copy his pilot squad filename
1394 Net_players[new_player_num].player->insignia_texture = -1;
1395 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1397 // copy in his pxo squad name
1398 SDL_strlcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad, LOGIN_LEN);
1400 // since we just created the player, set the last_heard_time here.
1401 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1403 Net_players[new_player_num].p_info.team = team;
1405 Net_players[new_player_num].player_id = new_id;
1407 // zero out this players ping
1408 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1410 // add a chat message
1411 if(Net_players[new_player_num].player->callsign[0]){
1412 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1413 multi_display_chat_msg(notify_string,0,0);
1418 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1420 // let the current ui screen know someone joined
1421 switch(gameseq_get_state()){
1422 case GS_STATE_MULTI_HOST_SETUP :
1423 multi_create_handle_join(&Net_players[new_player_num]);
1425 case GS_STATE_MULTI_CLIENT_SETUP :
1426 multi_jw_handle_join(&Net_players[new_player_num]);
1431 #define PLAYER_DATA_SLOP 100
1433 void send_accept_player_data( net_player *npp, int is_ingame )
1437 ubyte data[MAX_PACKET_SIZE], stop;
1439 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1441 // add in the netplayer data for all players
1443 for (i=0; i<MAX_PLAYERS; i++) {
1444 // skip non connected players
1445 if ( !MULTI_CONNECTED(Net_players[i]) ){
1449 // skip this new player's entry
1450 if ( npp->player_id == Net_players[i].player_id ){
1454 // add the stop byte
1457 // add the player's number
1460 // add the player's address
1461 // ADD_DATA(Net_players[i].p_info.addr);
1462 add_net_addr(data, packet_size, &Net_players[i].p_info.addr);
1465 ADD_SHORT(Net_players[i].player_id);
1468 ADD_STRING(Net_players[i].player->callsign);
1470 // add his image filename
1471 ADD_STRING(Net_players[i].player->image_filename);
1473 // add his squad filename
1474 ADD_STRING(Net_players[i].player->squad_filename);
1476 // add his PXO squad name
1477 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1480 ADD_INT(Net_players[i].flags);
1482 // add his object's net sig
1484 ADD_USHORT( Objects[Net_players[i].player->objnum].net_signature );
1487 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1488 stop = APD_END_PACKET;
1490 multi_io_send_reliable( npp, data, packet_size );
1491 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1497 // add the stop byte
1498 stop = APD_END_DATA;
1500 multi_io_send_reliable(npp, data, packet_size);
1503 // send an accept packet to a client in response to a request to join the game
1504 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1506 int packet_size = 0, i;
1507 ubyte data[MAX_PACKET_SIZE],val;
1508 char notify_string[256];
1511 SDL_assert(new_player_num >= 0);
1513 // setup his "reliable" socket
1514 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1516 // build the packet header
1517 BUILD_HEADER(ACCEPT);
1519 // add the accept code
1522 // add code specific accept data
1523 if (code & ACCEPT_INGAME) {
1524 // the game filename
1525 ADD_STRING(Game_current_mission_filename);
1527 // if he is joining on a specific team, mark it here
1528 if(ingame_join_team != -1){
1531 val = (ubyte)ingame_join_team;
1539 if (code & ACCEPT_OBSERVER) {
1540 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1543 if (code & ACCEPT_HOST) {
1544 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1547 if (code & ACCEPT_CLIENT) {
1548 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1551 // add the current skill level setting on the host
1552 ADD_INT(Game_skill_level);
1554 // add this guys player num
1555 ADD_INT(new_player_num);
1557 // add his player id
1558 ADD_SHORT(Net_players[new_player_num].player_id);
1560 // add netgame type flags
1561 ADD_INT(Netgame.type_flags);
1564 // char buffer[100];
1565 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1568 // actually send the packet
1569 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1571 // if he's not an observer, inform all the other players in the game about him
1572 // inform the other players in the game about this new player
1573 for (i=0; i<MAX_PLAYERS; i++) {
1574 // skip unconnected players as well as this new guy himself
1575 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])) {
1579 // send the new packet
1580 send_new_player_packet(new_player_num,&Net_players[i]);
1583 // add a chat message
1584 if(Net_players[new_player_num].player->callsign[0]){
1585 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1586 multi_display_chat_msg(notify_string, 0, 0);
1589 // handle any team vs. team details
1590 if (!(code & ACCEPT_OBSERVER)) {
1591 multi_team_handle_join(&Net_players[new_player_num]);
1595 if(Net_players[new_player_num].tracker_player_id >= 0){
1596 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);
1598 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1603 // process the player data from the server
1604 void process_accept_player_data( ubyte *data, header *hinfo )
1606 int offset, player_num, player_slot_num, new_flags;
1607 char name[CALLSIGN_LEN + 1] = "";
1608 char image_name[MAX_FILENAME_LEN + 1] = "";
1609 char squad_name[MAX_FILENAME_LEN + 1] = "";
1610 char pxo_squad_name[LOGIN_LEN+1] = "";
1614 ushort ig_signature;
1616 offset = HEADER_LENGTH;
1619 while ( stop == APD_NEXT ) {
1620 player_slot_num = multi_find_open_player_slot();
1621 SDL_assert(player_slot_num != -1);
1623 // get the player's number
1624 GET_INT(player_num);
1626 // add the player's address
1627 memset(&addr, 0, sizeof(net_addr));
1628 get_net_addr(data, offset, addr);
1630 // get the player's id#
1631 GET_SHORT(player_id);
1636 // add his image filename
1637 GET_STRING(image_name);
1639 // get his squad logo filename
1640 GET_STRING(squad_name);
1642 // get his PXO squad name
1643 GET_STRING(pxo_squad_name);
1648 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1649 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1654 // the error handling here is less than stellar. We should probably put up a popup and go
1655 // back to the main menu. But then again, this should never ever happen!
1656 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1661 // copy his image filename
1662 SDL_strlcpy(Net_players[player_num].player->image_filename, image_name, MAX_FILENAME_LEN);
1664 // copy his pilot squad filename
1665 Net_players[player_num].player->insignia_texture = -1;
1666 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1668 // copy his pxo squad name
1669 SDL_strlcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name, LOGIN_LEN);
1671 // set his player id#
1672 Net_players[player_num].player_id = player_id;
1674 // mark him as being connected
1675 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1676 Net_players[player_num].flags |= new_flags;
1678 // set the server pointer
1679 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1680 Netgame.server = &Net_players[player_num];
1681 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1683 // also - always set the server address to be where this data came from, NOT from
1684 // the data in the packet
1685 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->port);
1688 // set the host pointer
1689 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1690 Netgame.host = &Net_players[player_num];
1693 // read in the player's object net signature and store as his objnum for now
1694 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1695 GET_USHORT( ig_signature );
1696 Net_players[player_num].player->objnum = ig_signature;
1699 // get the stop byte
1704 if ( stop == APD_END_DATA ) {
1705 // if joining a game automatically, set the connect address to NULl so we don't try and
1706 // do this next time we enter a game
1707 if (Cmdline_connect_addr != NULL) {
1708 Cmdline_connect_addr = NULL;
1711 // send my stats to the server if I'm not in observer mode
1712 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1713 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1716 // if i'm being accepted as a host, then move into the host setup state
1717 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1718 // set my permission bits
1719 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1720 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1722 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1725 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1726 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1728 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1729 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1730 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1734 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1735 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1738 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1739 // flag myself as being an ingame joiner
1740 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1742 // move myself into the ingame join mission sync state
1743 Multi_sync_mode = MULTI_SYNC_INGAME;
1744 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1747 // update my options on the server
1748 multi_options_update_local();
1750 // if we're in PXO mode, mark it down in our player struct
1751 if(MULTI_IS_TRACKER_GAME){
1752 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1753 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1758 // process an accept packet from the server
1759 extern int Select_default_ship;
1761 void process_accept_packet(ubyte* data, header* hinfo)
1763 int code, my_player_num, offset;
1767 // get the accept code
1768 offset = HEADER_LENGTH;
1772 // read in the accept code specific data
1774 if (code & ACCEPT_INGAME) {
1775 // the game filename
1776 GET_STRING(Game_current_mission_filename);
1777 Select_default_ship = 0;
1779 // determine if I'm being placed on a team
1786 if (code & ACCEPT_OBSERVER) {
1787 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1790 if (code & ACCEPT_HOST) {
1791 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1794 if (code & ACCEPT_CLIENT) {
1795 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1798 // fill in the netgame server address
1799 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->port );
1801 // get the skill level setting
1802 GET_INT(Game_skill_level);
1804 // get my netplayer number
1805 GET_INT(my_player_num);
1808 GET_SHORT(player_id);
1810 // get netgame type flags
1811 GET_INT(Netgame.type_flags);
1813 // setup the Net_players structure for myself first
1814 Net_player = &Net_players[my_player_num];
1815 Net_player->flags = 0;
1816 Net_player->tracker_player_id = Multi_tracker_id;
1817 Net_player->player_id = player_id;
1818 Net_player->s_info.xfer_handle = -1;
1819 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1820 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1821 multi_options_local_load(&Net_player->p_info.options, Net_player);
1823 Net_player->p_info.team = team;
1826 // determine if I have a CD
1828 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1831 // set accept code in netplayer for this guy
1832 if ( code & ACCEPT_INGAME ){
1833 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1835 if ( code & ACCEPT_OBSERVER ){
1836 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1838 if ( code & ACCEPT_HOST ){
1839 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1841 if ( code & ACCEPT_CLIENT ){
1842 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1845 // if I have hacked data
1846 if(game_hacked_data()){
1847 Net_player->flags |= NETINFO_FLAG_HAXOR;
1850 // if we're supposed to flush our local data cache, do so now
1851 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1852 multi_flush_multidata_cache();
1855 Net_player->sv_bytes_sent = 0;
1856 Net_player->sv_last_pl = -1;
1857 Net_player->cl_bytes_recvd = 0;
1858 Net_player->cl_last_pl = -1;
1860 // intiialize endgame stuff
1861 multi_endgame_init();
1865 // make a call to psnet to initialize and try to connect with the server.
1866 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1867 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1868 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1872 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1873 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1875 ubyte data[MAX_PACKET_SIZE];
1877 int packet_size = 0;
1879 BUILD_HEADER(LEAVE_GAME);
1881 // add a flag indicating whether he was kicked or not
1882 val = (char)kicked_reason;
1885 if (player_id < 0) {
1886 ADD_SHORT(Net_player->player_id);
1888 // inform the host that we are leaving the game
1889 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1890 multi_io_send_to_all_reliable(data, packet_size);
1892 multi_io_send_reliable(Net_player, data, packet_size);
1895 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1896 // so he has to tell everyone that this guy left
1898 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1900 // a couple of important checks
1901 SDL_assert(player_id != Net_player->player_id);
1902 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1904 // add the id of the guy to be kicked
1905 ADD_SHORT(player_id);
1907 // broadcast to everyone
1908 if (target == NULL) {
1909 multi_io_send_to_all_reliable(data, packet_size);
1911 multi_io_send_reliable(target, data, packet_size);
1916 // process a notification the a player has left the game
1917 void process_leave_game_packet(ubyte* data, header* hinfo)
1925 offset = HEADER_LENGTH;
1927 // get whether he was kicked
1928 GET_DATA(kicked_reason);
1930 // get the address of the guy who is to leave
1931 GET_SHORT(deader_id);
1934 // determine who is dropping and printf out a notification
1935 player_num = find_player_id(deader_id);
1936 if (player_num == -1) {
1937 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1941 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1944 // a hook to display that a player was kicked
1945 if (kicked_reason >= 0){
1946 // if it was me that was kicked, leave the game
1947 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1950 switch(kicked_reason){
1951 case KICK_REASON_BAD_XFER:
1952 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1954 case KICK_REASON_CANT_XFER:
1955 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1957 case KICK_REASON_INGAME_ENDED:
1958 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1961 notify_code = MULTI_END_NOTIFY_KICKED;
1965 multi_quit_game(PROMPT_NONE, notify_code);
1968 // otherwise indicate someone was kicked
1970 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1972 // display the result
1973 memset(str, 0, 512);
1974 multi_kick_get_text(&Net_players[player_num], kicked_reason, str, SDL_arraysize(str));
1975 multi_display_chat_msg(str, player_num, 0);
1979 // first of all, if we're the master, we should be rebroadcasting this packet
1980 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1983 SDL_snprintf(msg, SDL_arraysize(msg), XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1985 if (!(Game_mode & GM_STANDALONE_SERVER)){
1986 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1989 send_hud_msg_to_all(msg);
1990 multi_io_send_to_all_reliable(data, offset);
1993 // leave the game if the host and/or master has dropped
1995 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1996 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1999 ml_string(NOX("Host and/or server has left the game"));
2001 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
2002 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
2003 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
2006 delete_player(player_num);
2009 delete_player(player_num);
2011 // OSAPI GUI stuff (if standalone)
2012 if (Game_mode & GM_STANDALONE_SERVER) {
2013 // returns true if we should reset the standalone
2014 if (std_remove_player(&Net_players[player_num])) {
2015 nprintf(("Network", "Should reset!!\n"));
2019 // update these gui vals
2020 std_connect_set_host_connect_status();
2021 std_connect_set_connect_count();
2025 // send information about this currently active game to the specified address
2026 void send_game_active_packet(net_addr* addr)
2030 ubyte data[MAX_PACKET_SIZE],val;
2032 // build the header and add the data
2033 BUILD_HEADER(GAME_ACTIVE);
2035 // add the server version and compatible version #
2036 val = MULTI_FS_SERVER_VERSION;
2038 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2041 ADD_STRING(Netgame.name);
2042 ADD_STRING(Netgame.mission_name);
2043 ADD_STRING(Netgame.title);
2044 val = (ubyte)multi_num_players();
2047 // add the proper flags
2049 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2050 flags |= AG_FLAG_PASSWD;
2053 // proper netgame type flags
2054 if(Netgame.type_flags & NG_TYPE_TEAM){
2055 flags |= AG_FLAG_TEAMS;
2056 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2057 flags |= AG_FLAG_DOGFIGHT;
2059 flags |= AG_FLAG_COOP;
2062 // proper netgame state flags
2063 switch(Netgame.game_state){
2064 case NETGAME_STATE_FORMING:
2065 flags |= AG_FLAG_FORMING;
2068 case NETGAME_STATE_BRIEFING:
2069 case NETGAME_STATE_MISSION_SYNC:
2070 case NETGAME_STATE_HOST_SETUP:
2071 flags |= AG_FLAG_BRIEFING;
2074 case NETGAME_STATE_IN_MISSION:
2075 flags |= AG_FLAG_IN_MISSION;
2078 case NETGAME_STATE_PAUSED:
2079 flags |= AG_FLAG_PAUSE;
2082 case NETGAME_STATE_ENDGAME:
2083 case NETGAME_STATE_DEBRIEF:
2084 flags |= AG_FLAG_DEBRIEF;
2088 // if this is a standalone
2089 if(Game_mode & GM_STANDALONE_SERVER){
2090 flags |= AG_FLAG_STANDALONE;
2093 // if we're in campaign mode
2094 if(Netgame.campaign_mode == MP_CAMPAIGN){
2095 flags |= AG_FLAG_CAMPAIGN;
2098 // add the data about the connection speed of the host machine
2099 SDL_assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2100 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2105 psnet_send(addr, data, packet_size);
2108 // process information about an active game
2109 void process_game_active_packet(ubyte* data, header* hinfo)
2114 int modes_compatible;
2116 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->port);
2118 // read this game into a temporary structure
2119 offset = HEADER_LENGTH;
2121 // get the server version and compatible version
2122 GET_DATA(ag.version);
2123 GET_DATA(ag.comp_version);
2125 GET_STRING(ag.name);
2126 GET_STRING(ag.mission_name);
2127 GET_STRING(ag.title);
2129 ag.num_players = val;
2130 GET_USHORT(ag.flags);
2134 modes_compatible = 1;
2136 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2137 modes_compatible = 0;
2139 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2140 modes_compatible = 0;
2144 // if this is a compatible version, and our modes are compatible, register it
2145 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2146 multi_update_active_games(&ag);
2150 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2151 // is used to change the current mission, current state, etc.
2152 void send_netgame_update_packet(net_player *pl)
2154 int packet_size = 0;
2156 ubyte data[MAX_PACKET_SIZE];
2158 BUILD_HEADER(GAME_UPDATE);
2160 // with new mission description field, this becomes way to large
2161 // so we must add every element piece by piece except the
2162 ADD_STRING(Netgame.name);
2163 ADD_STRING(Netgame.mission_name);
2164 ADD_STRING(Netgame.title);
2165 ADD_STRING(Netgame.campaign_name);
2166 ADD_INT(Netgame.campaign_mode);
2167 ADD_INT(Netgame.max_players);
2168 ADD_INT(Netgame.security);
2169 ADD_UINT(Netgame.respawn);
2170 ADD_INT(Netgame.flags);
2171 ADD_INT(Netgame.type_flags);
2172 ADD_INT(Netgame.version_info);
2173 ADD_DATA(Netgame.debug_flags);
2175 // only the server should ever send the netgame state (standalone situation)
2176 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2177 ADD_INT(Netgame.game_state);
2180 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2181 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2183 multi_io_send_to_all_reliable(data, packet_size);
2185 for(idx=0; idx<MAX_PLAYERS; idx++){
2186 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2187 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2191 multi_io_send_reliable(pl, data, packet_size);
2192 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2195 SDL_assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2196 multi_io_send_reliable(Net_player, data, packet_size);
2199 // host should always send a netgame options update as well
2200 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2201 multi_options_update_netgame();
2205 // process information about the netgame sent from the server/host
2206 void process_netgame_update_packet( ubyte *data, header *hinfo )
2208 int offset;//,old_flags;
2211 SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
2212 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2214 // read in the netgame information
2215 offset = HEADER_LENGTH;
2216 GET_STRING(Netgame.name);
2217 GET_STRING(Netgame.mission_name);
2218 GET_STRING(Netgame.title);
2219 GET_STRING(Netgame.campaign_name);
2220 GET_INT(Netgame.campaign_mode);
2221 GET_INT(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2222 GET_INT(Netgame.security);
2223 GET_UINT(Netgame.respawn);
2225 // be sure not to blast the quitting flag because of the "one frame extra" problem
2226 // old_flags = Netgame.flags;
2227 GET_INT(Netgame.flags);
2228 GET_INT(Netgame.type_flags);
2229 GET_INT(Netgame.version_info);
2230 GET_DATA(Netgame.debug_flags);
2237 // now compare the passed in game state to our current known state. If it has changed, then maybe
2238 // do something interesting.
2239 // move from the forming or debriefing state to the mission sync state
2240 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2241 // if coming from the forming state
2242 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2243 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2244 // do any special processing for forced state transitions
2245 multi_handle_state_special();
2247 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2248 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2249 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2251 // if coming from the debriefing state
2252 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2253 ((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 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2261 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2262 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2265 // move from mission sync to team select
2266 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2267 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2268 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2270 // do any special processing for forced state transitions
2271 multi_handle_state_special();
2273 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2274 gameseq_post_event(GS_EVENT_START_BRIEFING);
2277 // move from the debriefing to the create game screen
2278 else if ( ng_state == NETGAME_STATE_FORMING ){
2279 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2280 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2281 // do any special processing for forced state transitions
2282 multi_handle_state_special();
2284 multi_flush_mission_stuff();
2286 // move to the proper screen
2287 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2288 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2290 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2295 Netgame.game_state = ng_state;
2298 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2299 void send_netgame_descript_packet(net_addr *addr, int code)
2301 ubyte data[MAX_PACKET_SIZE],val;
2303 int packet_size = 0;
2306 BUILD_HEADER(UPDATE_DESCRIPT);
2312 // add as much of the description as we dare
2313 len = strlen(The_mission.mission_desc);
2314 if(len > MAX_PACKET_SIZE - 10){
2315 len = MAX_PACKET_SIZE - 10;
2317 memcpy(data+packet_size,The_mission.mission_desc,len);
2320 ADD_STRING(The_mission.mission_desc);
2324 SDL_assert(addr != NULL);
2326 psnet_send(addr, data, packet_size);
2330 // process an incoming netgame description packet
2331 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2335 char mission_desc[MISSION_DESC_LENGTH+2];
2338 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2340 // read this game into a temporary structure
2341 offset = HEADER_LENGTH;
2344 // if this is a request for mission description
2346 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2351 // send an update to this guy
2352 send_netgame_descript_packet(&addr, 1);
2354 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2355 GET_STRING(mission_desc);
2357 // only display if we're in the proper state
2358 state = gameseq_get_state();
2360 case GS_STATE_MULTI_JOIN_GAME:
2361 case GS_STATE_MULTI_CLIENT_SETUP:
2362 case GS_STATE_MULTI_HOST_SETUP:
2363 multi_common_set_text(mission_desc);
2371 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2372 void broadcast_game_query()
2376 server_item *s_moveup;
2377 ubyte data[MAX_PACKET_SIZE];
2379 BUILD_HEADER(GAME_QUERY);
2381 // go through the server list and query each of those as well
2382 s_moveup = Game_server_head;
2383 if(s_moveup != NULL){
2385 send_server_query(&s_moveup->server_addr);
2386 s_moveup = s_moveup->next;
2387 } while(s_moveup != Game_server_head);
2390 fill_net_addr(&addr, Psnet_my_addr.addr, DEFAULT_GAME_PORT);
2392 // send out a broadcast if our options allow us
2393 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2394 psnet_broadcast( &addr, data, packet_size);
2398 // send an individual query to an address to see if there is an active game
2399 void send_server_query(net_addr *addr)
2402 ubyte data[MAX_PACKET_SIZE];
2404 // build the header and send the data
2405 BUILD_HEADER(GAME_QUERY);
2406 psnet_send(addr, data, packet_size);
2409 // process a query from a client looking for active freespace games
2410 void process_game_query(ubyte* data, header* hinfo)
2415 offset = HEADER_LENGTH;
2419 // check to be sure that we don't capture our own broadcast message
2420 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2421 if ( psnet_same( &addr, &Psnet_my_addr) ){
2425 // if I am not a server of a game, don't send a reply!!!
2426 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2430 // if the game options are being selected, then ignore the request
2431 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2432 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2436 // send information about this active game
2437 send_game_active_packet(&addr);
2440 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2441 void send_netplayer_update_packet( net_player *pl )
2443 int packet_size,idx;
2444 ubyte data[MAX_PACKET_SIZE],val;
2446 BUILD_HEADER(NETPLAYER_UPDATE);
2448 // if I'm the server of the game, I should send an update for _all_players in the game
2449 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2450 for(idx=0;idx<MAX_PLAYERS;idx++){
2451 // only send info for connected players
2452 if(MULTI_CONNECTED(Net_players[idx])){
2457 // add the net player's information
2458 ADD_SHORT(Net_players[idx].player_id);
2459 ADD_INT(Net_players[idx].state);
2460 ADD_INT(Net_players[idx].p_info.ship_class);
2461 ADD_INT(Net_players[idx].tracker_player_id);
2463 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2471 // add the final stop byte
2475 // broadcast the packet
2476 if(!(Game_mode & GM_IN_MISSION)){
2478 multi_io_send_to_all_reliable(data, packet_size);
2480 multi_io_send_reliable(pl, data, packet_size);
2484 multi_io_send_to_all(data, packet_size);
2486 multi_io_send(pl, data, packet_size);
2494 // add my current state in the netgame to this packet
2495 ADD_SHORT(Net_player->player_id);
2496 ADD_INT(Net_player->state);
2497 ADD_INT(Net_player->p_info.ship_class);
2498 ADD_INT(Multi_tracker_id);
2500 // add if I have a CD or not
2508 // add a final stop byte
2512 // send the packet to the server
2513 SDL_assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2514 if(!(Game_mode & GM_IN_MISSION)){
2515 multi_io_send_reliable(Net_player, data, packet_size);
2517 multi_io_send(Net_player, data, packet_size);
2522 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2523 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2525 int offset, player_num;
2531 offset = HEADER_LENGTH;
2533 // get the first stop byte
2536 while(stop != 0xff){
2537 // look the player up
2538 GET_SHORT(player_id);
2539 player_num = find_player_id(player_id);
2540 // if we couldn't find him, read in the bogus data
2541 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2542 GET_INT(bogus.state);
2543 GET_INT(bogus.p_info.ship_class);
2544 GET_INT(bogus.tracker_player_id);
2548 // otherwise read in the data correctly
2551 GET_INT(Net_players[player_num].p_info.ship_class);
2552 GET_INT(Net_players[player_num].tracker_player_id);
2555 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2557 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2560 // if he's changing state to joined, send a team update
2561 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2562 multi_team_send_update();
2566 Net_players[player_num].state = new_state;
2569 // get the next stop byte
2575 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2576 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2577 send_netplayer_update_packet(NULL);
2580 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2581 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2582 switch(Net_players[player_num].state){
2583 case NETPLAYER_STATE_STD_HOST_SETUP:
2584 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2587 case NETPLAYER_STATE_HOST_SETUP:
2588 // check for race conditions
2589 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2590 Netgame.game_state = NETGAME_STATE_FORMING;
2597 #define EXTRA_DEATH_VAPORIZED (1<<0)
2598 #define EXTRA_DEATH_WASHED (1<<1)
2599 // send a packet indicating a ship has been killed
2600 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2602 int packet_size, model;
2603 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2604 ushort debris_signature;
2608 // only sendable from the master
2609 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2612 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2614 extra_death_info = 0;
2616 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2619 if ( Ships[objp->instance].wash_killed ) {
2620 extra_death_info |= EXTRA_DEATH_WASHED;
2623 // find out the next network signature that will be used for the debris pieces.
2624 model = Ships[objp->instance].modelnum;
2625 pm = model_get(model);
2626 debris_signature = 0;
2627 if ( pm && !vaporized ) {
2628 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2629 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2630 Ships[objp->instance].arrival_distance = debris_signature;
2633 BUILD_HEADER(SHIP_KILL);
2634 ADD_USHORT(objp->net_signature);
2636 // ships which are initially killed get the rest of the data sent. self destructed ships and
2637 if ( other_objp == NULL ) {
2642 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2644 ADD_USHORT( other_objp->net_signature );
2647 ADD_USHORT( debris_signature );
2648 ADD_FLOAT( percent_killed );
2649 sd = (ubyte)self_destruct;
2651 ADD_DATA( extra_death_info );
2653 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2655 if ( objp->flags & OF_PLAYER_SHIP ) {
2659 pnum = multi_find_player_by_object( objp );
2662 ADD_DATA( was_player );
2664 SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2665 temp = (char)Net_players[pnum].player->killer_objtype;
2668 SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2669 temp = (char)Net_players[pnum].player->killer_species;
2672 SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2673 temp = (char)Net_players[pnum].player->killer_weapon_index;
2676 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2678 ADD_DATA( was_player );
2681 ADD_DATA( was_player );
2684 // send the packet reliably!!!
2685 multi_io_send_to_all_reliable(data, packet_size);
2688 // process a packet indicating that a ship has been killed
2689 void process_ship_kill_packet( ubyte *data, header *hinfo )
2692 ushort ship_sig, other_sig, debris_sig;
2693 object *sobjp, *oobjp;
2694 float percent_killed;
2695 ubyte was_player, extra_death_info, sd;
2696 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2698 offset = HEADER_LENGTH;
2699 GET_USHORT(ship_sig);
2701 GET_USHORT( other_sig );
2702 GET_USHORT( debris_sig );
2703 GET_FLOAT( percent_killed );
2705 GET_DATA( extra_death_info );
2706 GET_DATA( was_player );
2709 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2710 if ( was_player != 0 ) {
2711 GET_DATA( killer_objtype );
2712 GET_DATA( killer_species );
2713 GET_DATA( killer_weapon_index );
2714 GET_STRING( killer_name );
2719 sobjp = multi_get_network_object( ship_sig );
2721 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2722 // another message from the server that this happened!
2723 if ( sobjp == NULL ) {
2724 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2728 // set this ship's hull value to 0
2729 sobjp->hull_strength = 0.0f;
2731 // maybe set vaporized
2732 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2733 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2736 // maybe set wash_killed
2737 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2738 Ships[sobjp->instance].wash_killed = 1;
2741 oobjp = multi_get_network_object( other_sig );
2743 if ( was_player != 0 ) {
2746 pnum = multi_find_player_by_object( sobjp );
2748 Net_players[pnum].player->killer_objtype = killer_objtype;
2749 Net_players[pnum].player->killer_species = killer_species;
2750 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2751 SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2755 // check to see if I need to respawn myself
2756 multi_respawn_check(sobjp);
2758 // store the debris signature in the arrival distance which will never get used for player ships
2759 Ships[sobjp->instance].arrival_distance = debris_sig;
2761 // set this bit so that we don't accidentally start switching targets when we die
2762 if(sobjp == Player_obj){
2763 Game_mode |= GM_DEAD_DIED;
2766 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2768 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2769 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2770 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2772 extern void ship_destroyed( int shipnum );
2773 ship_destroyed( sobjp->instance );
2774 sobjp->flags |= OF_SHOULD_BE_DEAD;
2775 obj_delete( OBJ_INDEX(sobjp) );
2779 // send a packet indicating a ship should be created
2780 void send_ship_create_packet( object *objp, int is_support )
2783 ubyte data[MAX_PACKET_SIZE];
2785 // We will pass the ship to create by name.
2786 BUILD_HEADER(SHIP_CREATE);
2787 ADD_USHORT(objp->net_signature);
2788 ADD_INT( is_support );
2790 add_vector_data(data, &packet_size, objp->pos);
2793 // broadcast the packet
2794 multi_io_send_to_all_reliable(data, packet_size);
2797 // process a packet indicating a ship should be created
2798 void process_ship_create_packet( ubyte *data, header *hinfo )
2800 int offset, objnum, is_support;
2803 vector pos = ZERO_VECTOR;
2805 SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2806 offset = HEADER_LENGTH;
2807 GET_USHORT(signature);
2808 GET_INT( is_support );
2810 get_vector_data(data, &offset, pos);
2815 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2816 if ( !is_support ) {
2817 objp = mission_parse_get_arrival_ship( signature );
2818 if ( objp != NULL ) {
2819 parse_create_object(objp);
2821 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2824 SDL_assert( Arriving_support_ship );
2825 if(Arriving_support_ship == NULL){
2828 Arriving_support_ship->pos = pos;
2829 Arriving_support_ship->net_signature = signature;
2830 objnum = parse_create_object( Arriving_support_ship );
2831 SDL_assert( objnum != -1 );
2833 mission_parse_support_arrived( objnum );
2838 // send a packet indicating a wing of ships should be created
2839 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2841 int packet_size, index, ship_instance;
2842 ubyte data[MAX_PACKET_SIZE];
2846 // for creating wing -- we just send the index into the wing array of this wing.
2847 // all players load the same mission, and so their array's should all match. We also
2848 // need to send the signature of the first ship that was created. We can find this by
2849 // looking num_to_create places back in the ship_index field in the wing structure.
2851 index = WING_INDEX(wingp);
2852 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2853 signature = Objects[Ships[ship_instance].objnum].net_signature;
2855 BUILD_HEADER( WING_CREATE );
2857 ADD_INT(num_to_create);
2858 ADD_USHORT(signature);
2859 ADD_INT(pre_create_count);
2860 val = wingp->current_wave - 1;
2863 multi_io_send_to_all_reliable(data, packet_size);
2866 // process a packet saying that a wing should be created
2867 void process_wing_create_packet( ubyte *data, header *hinfo )
2869 int offset, index, num_to_create;
2871 int total_arrived_count, current_wave;
2873 offset = HEADER_LENGTH;
2875 GET_INT(num_to_create);
2876 GET_USHORT(signature);
2877 GET_INT(total_arrived_count);
2878 GET_INT(current_wave);
2882 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2883 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2884 nprintf(("Network", "invalid index %d for wing create packet\n"));
2887 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2888 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2893 Wings[index].current_count = 0;
2894 Wings[index].total_arrived_count = total_arrived_count;
2895 Wings[index].current_wave = current_wave;
2897 // set the network signature that was passed. The client should create ships in the same order
2898 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2899 // need to set some timestamps and cues correctly to be sure that these things get created on
2900 // the clients correctly
2901 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2902 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2905 // packet indicating a ship is departing
2906 void send_ship_depart_packet( object *objp )
2908 ubyte data[MAX_PACKET_SIZE];
2912 signature = objp->net_signature;
2914 BUILD_HEADER(SHIP_DEPART);
2915 ADD_USHORT( signature );
2917 multi_io_send_to_all_reliable(data, packet_size);
2920 // process a packet indicating a ship is departing
2921 void process_ship_depart_packet( ubyte *data, header *hinfo )
2927 offset = HEADER_LENGTH;
2928 GET_USHORT( signature );
2931 // find the object which is departing
2932 objp = multi_get_network_object( signature );
2933 if ( objp == NULL ) {
2934 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2938 // start warping him out
2939 shipfx_warpout_start( objp );
2942 // packet to tell clients cargo of a ship was revealed to all
2943 void send_cargo_revealed_packet( ship *shipp )
2945 ubyte data[MAX_PACKET_SIZE];
2948 // build the header and add the data
2949 BUILD_HEADER(CARGO_REVEALED);
2950 ADD_USHORT( Objects[shipp->objnum].net_signature );
2952 // server sends to all players
2953 if(MULTIPLAYER_MASTER){
2954 multi_io_send_to_all_reliable(data, packet_size);
2956 // clients just send to the server
2958 multi_io_send_reliable(Net_player, data, packet_size);
2962 // process a cargo revealed packet
2963 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2969 offset = HEADER_LENGTH;
2970 GET_USHORT(signature);
2973 // get a ship pointer and call the ship function to reveal the cargo
2974 objp = multi_get_network_object( signature );
2975 if ( objp == NULL ) {
2976 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2980 // SDL_assert( objp->type == OBJ_SHIP );
2981 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2985 // this will take care of re-routing to all other clients
2986 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2988 // server should rebroadcast
2989 if(MULTIPLAYER_MASTER){
2990 send_cargo_revealed_packet(&Ships[objp->instance]);
2994 // defines used for secondary fire packet
2995 #define SFPF_ALLOW_SWARM (1<<7)
2996 #define SFPF_DUAL_FIRE (1<<6)
2997 #define SFPF_TARGET_LOCKED (1<<5)
2999 // send a packet indicating a secondary weapon was fired
3000 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
3002 int packet_size, net_player_num;
3003 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
3005 ushort target_signature;
3009 // SDL_assert ( starting_count < UCHAR_MAX );
3011 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
3012 // we might send the info to the other player different than the one who fired
3013 objp = &Objects[shipp->objnum];
3014 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3015 if ( num_fired == 0 ) {
3020 aip = &Ai_info[shipp->ai_index];
3022 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3023 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3025 // build up the header portion
3026 BUILD_HEADER( SECONDARY_FIRED_AI );
3028 ADD_USHORT( Objects[shipp->objnum].net_signature );
3029 ADD_USHORT( starting_sig );
3031 // add a couple of bits for swarm missiles and dual fire secondary weaspons
3034 sinfo = current_bank;
3037 sinfo |= SFPF_ALLOW_SWARM;
3040 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3041 sinfo |= SFPF_DUAL_FIRE;
3044 if ( aip->current_target_is_locked ){
3045 sinfo |= SFPF_TARGET_LOCKED;
3050 // add the ship's target and any targeted subsystem
3051 target_signature = 0;
3053 if ( aip->target_objnum != -1) {
3054 target_signature = Objects[aip->target_objnum].net_signature;
3055 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3058 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3059 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
3060 t_subsys = (char)s_index;
3063 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3064 SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3069 ADD_USHORT( target_signature );
3070 ADD_DATA( t_subsys );
3072 // just send this packet to everyone, then bail if an AI ship fired.
3073 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3074 multi_io_send_to_all(data, packet_size);
3078 net_player_num = multi_find_player_by_object( objp );
3080 // getting here means a player fired. Send the current packet to all players except the player
3081 // who fired. If nothing got fired, then don't send to the other players -- we will just send
3082 // a packet to the player who will find out that he didn't fire anything
3083 if ( num_fired > 0 ) {
3084 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3087 // if I (the master) fired, then return
3088 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3092 // now build up the packet to send to the player who actually fired.
3093 BUILD_HEADER( SECONDARY_FIRED_PLR );
3094 ADD_USHORT(starting_sig);
3097 // add the targeting information so that the player's weapons will always home on the correct
3099 ADD_USHORT( target_signature );
3100 ADD_DATA( t_subsys );
3102 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3105 /// process a packet indicating a secondary weapon was fired
3106 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3108 int offset, allow_swarm, target_objnum_save;
3109 ushort net_signature, starting_sig, target_signature;
3110 ubyte sinfo, current_bank;
3111 object* objp, *target_objp;
3115 ship_subsys *targeted_subsys_save;
3117 offset = HEADER_LENGTH; // size of the header
3119 // if from_player is false, it means that the secondary weapon info in this packet was
3120 // fired by an ai object (or another player). from_player == 1 means tha me (the person
3121 // receiving this packet) fired the secondary weapon
3122 if ( !from_player ) {
3123 GET_USHORT( net_signature );
3124 GET_USHORT( starting_sig );
3125 GET_DATA( sinfo ); // are we firing swarm missiles
3127 GET_USHORT( target_signature );
3128 GET_DATA( t_subsys );
3132 // find the object (based on network signatures) for the object that fired
3133 objp = multi_get_network_object( net_signature );
3134 if ( objp == NULL ) {
3135 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3139 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3140 // of the next fire time of this bank to 0 so we can fire right away
3141 shipp = &Ships[objp->instance];
3144 GET_USHORT( starting_sig );
3147 GET_USHORT( target_signature );
3148 GET_DATA( t_subsys );
3152 // get the object and ship
3154 shipp = Player_ship;
3157 // check the allow swarm bit
3159 if ( sinfo & SFPF_ALLOW_SWARM ){
3163 // set the dual fire properties of the ship
3164 if ( sinfo & SFPF_DUAL_FIRE ){
3165 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3167 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3170 // determine whether current target is locked
3171 SDL_assert( shipp->ai_index != -1 );
3172 aip = &Ai_info[shipp->ai_index];
3173 if ( sinfo & SFPF_TARGET_LOCKED ) {
3174 aip->current_target_is_locked = 1;
3176 aip->current_target_is_locked = 0;
3179 // find out the current bank
3180 current_bank = (ubyte)(sinfo & 0x3);
3181 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3182 shipp->weapons.current_secondary_bank = current_bank;
3184 // make it so we can fire this ship's secondary bank immediately!!!
3185 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3186 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3188 // set this ship's target and subsystem information. We will save and restore target and
3189 // targeted subsystem so that we do not accidentally change targets for this player or
3190 // any AI ships on his system.
3191 target_objnum_save = aip->target_objnum;
3192 targeted_subsys_save = aip->targeted_subsys;
3194 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3195 aip->target_objnum = -1;
3196 aip->targeted_subsys = NULL;
3198 target_objp = multi_get_network_object( target_signature );
3199 if ( target_objp != NULL ) {
3200 aip->target_objnum = OBJ_INDEX(target_objp);
3202 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3203 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3207 if ( starting_sig != 0 ){
3208 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3210 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3213 ship_fire_secondary( objp, allow_swarm );
3215 // restore targeted object and targeted subsystem
3216 aip->target_objnum = target_objnum_save;
3217 aip->targeted_subsys = targeted_subsys_save;
3220 // send a packet indicating a countermeasure was fired
3221 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3223 ubyte data[MAX_PACKET_SIZE];
3228 SDL_assert ( cmeasure_count < UCHAR_MAX );
3229 BUILD_HEADER(COUNTERMEASURE_FIRED);
3230 ADD_USHORT( objp->net_signature );
3231 ADD_INT( rand_val );
3233 multi_io_send_to_all(data, packet_size);
3236 // process a packet indicating a countermeasure was fired
3237 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3239 int offset, rand_val;
3245 offset = HEADER_LENGTH;
3247 GET_USHORT( signature );
3248 GET_INT( rand_val );
3251 objp = multi_get_network_object( signature );
3252 if ( objp == NULL ) {
3253 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3256 if(objp->type != OBJ_SHIP){
3259 // SDL_assert ( objp->type == OBJ_SHIP );
3261 // make it so ship can fire right away!
3262 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3263 if ( objp == Player_obj ){
3264 nprintf(("network", "firing countermeasure from my ship\n"));
3267 ship_launch_countermeasure( objp, rand_val );
3270 // send a packet indicating that a turret has been fired
3271 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3274 ushort pnet_signature;
3275 ubyte data[MAX_PACKET_SIZE], cindex;
3282 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3286 // local setup -- be sure we are actually passing a weapon!!!!
3287 objp = &Objects[weapon_objnum];
3288 SDL_assert ( objp->type == OBJ_WEAPON );
3289 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3293 pnet_signature = Objects[ship_objnum].net_signature;
3295 SDL_assert( subsys_index < UCHAR_MAX );
3296 cindex = (ubyte)subsys_index;
3298 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3303 // build the fire turret packet.
3304 BUILD_HEADER(FIRE_TURRET_WEAPON);
3305 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3306 ADD_DATA( has_sig );
3307 ADD_USHORT( pnet_signature );
3309 ADD_USHORT( objp->net_signature );
3312 val = (short)ssp->submodel_info_1.angs.h;
3314 val = (short)ssp->submodel_info_2.angs.p;
3317 multi_io_send_to_all(data, packet_size);
3319 multi_rate_add(1, "tur", packet_size);
3322 // process a packet indicating a turret has been fired
3323 void process_turret_fired_packet( ubyte *data, header *hinfo )
3325 int offset, weapon_objnum, wid;
3326 ushort pnet_signature, wnet_signature;
3335 short pitch, heading;
3337 // get the data for the turret fired packet
3338 offset = HEADER_LENGTH;
3339 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3340 GET_DATA( has_sig );
3341 GET_USHORT( pnet_signature );
3343 GET_USHORT( wnet_signature );
3347 GET_DATA( turret_index );
3348 GET_SHORT( heading );
3350 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3353 objp = multi_get_network_object( pnet_signature );
3354 if ( objp == NULL ) {
3355 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3359 // if this isn't a ship, do nothing
3360 if ( objp->type != OBJ_SHIP ){
3364 // make an orientation matrix from the o_fvec
3365 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3367 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3368 // hack, but should be suitable.
3369 shipp = &Ships[objp->instance];
3370 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3374 wid = ssp->system_info->turret_weapon_type;
3376 // bash the position and orientation of the turret
3377 ssp->submodel_info_1.angs.h = (float)heading;
3378 ssp->submodel_info_2.angs.p = (float)pitch;
3380 // get the world position of the weapon
3381 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3383 // create the weapon object
3384 if(wnet_signature != 0){
3385 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3387 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3388 if (weapon_objnum != -1) {
3389 if ( Weapon_info[wid].launch_snd != -1 ) {
3390 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3395 // send a mission log item packet
3396 void send_mission_log_packet( int num )
3399 ubyte data[MAX_PACKET_SIZE];
3404 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3406 // get the data from the log
3407 entry = &log_entries[num];
3408 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3409 sindex = (ushort)entry->index;
3411 BUILD_HEADER(MISSION_LOG_ENTRY);
3413 ADD_INT(entry->flags);
3415 ADD_DATA(entry->timestamp);
3416 ADD_STRING(entry->pname);
3417 ADD_STRING(entry->sname);
3419 // broadcast the packet to all players
3420 multi_io_send_to_all_reliable(data, packet_size);
3423 // process a mission log item packet
3424 void process_mission_log_packet( ubyte *data, header *hinfo )
3429 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3432 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3434 offset = HEADER_LENGTH;
3438 GET_DATA(timestamp);
3444 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3447 // send a mission message packet
3448 void send_mission_message_packet( int id, const char *who_from, int priority, int timing, int source, int builtin_type, int multi_target, int multi_team_filter)
3451 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3453 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3454 SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3455 SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3457 up = (ubyte) priority;
3458 us = (ubyte) source;
3459 utime = (ubyte)timing;
3461 BUILD_HEADER(MISSION_MESSAGE);
3463 ADD_STRING(who_from);
3467 ADD_INT(builtin_type);
3468 ADD_INT(multi_team_filter);
3470 if (multi_target == -1){
3471 multi_io_send_to_all_reliable(data, packet_size);
3473 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3477 // process a mission message packet
3478 void process_mission_message_packet( ubyte *data, header *hinfo )
3480 int offset, id, builtin_type;
3481 ubyte priority, source, utiming;
3482 char who_from[NAME_LENGTH];
3483 int multi_team_filter;
3485 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3487 offset = HEADER_LENGTH;
3489 GET_STRING(who_from);
3493 GET_INT(builtin_type);
3494 GET_INT(multi_team_filter);
3498 // filter out builtin ones in TvT
3499 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3503 // maybe filter this out
3504 if(!message_filter_multi(id)){
3505 // send the message as if it came from an sexpression
3506 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3510 // just send them a pong back as fast as possible
3511 void process_ping_packet(ubyte *data, header *hinfo)
3516 offset = HEADER_LENGTH;
3519 // get the address to return the pong to
3520 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3526 // right now it just routes the pong through to the standalone gui, which is the only
3527 // system which uses ping and pong right now.
3528 void process_pong_packet(ubyte *data, header *hinfo)
3534 offset = HEADER_LENGTH;
3536 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3540 // if we're connected , see who sent us this pong
3541 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3542 lookup = find_player_id(hinfo->id);
3547 p = &Net_players[lookup];
3549 // evaluate the ping
3550 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3552 // put in calls to any functions which may want to know about the ping times from
3554 if(Game_mode & GM_STANDALONE_SERVER){
3555 std_update_player_ping(p);
3559 // mark his socket as still alive (extra precaution)
3560 psnet_mark_received(Net_players[lookup].reliable_socket);
3563 // otherwise, do any special processing
3565 // if we're in the join game state, see if this pong came from a server on our
3567 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3568 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3573 // send a ping packet
3574 void send_ping(net_addr *addr)
3576 unsigned char data[8];
3579 // build the header and send the packet
3580 BUILD_HEADER( PING );
3581 psnet_send(addr, &data[0], packet_size);
3584 // send a pong packet
3585 void send_pong(net_addr *addr)
3587 unsigned char data[8];
3590 // build the header and send the packet
3592 psnet_send(addr, &data[0], packet_size);
3595 // sent from host to master. give me the list of missions you have.
3596 // this will be used only in a standalone mode
3597 void send_mission_list_request( int what )
3599 ubyte data[MAX_PACKET_SIZE];
3602 // build the header and ask for a list of missions or campaigns (depending
3603 // on the 'what' flag).
3604 BUILD_HEADER(MISSION_REQUEST);
3606 multi_io_send_reliable(Net_player, data, packet_size);
3609 // maximum number of bytes that we can send in a mission items packet.
3610 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3612 // defines used to tell what type of packets are being sent
3613 #define MISSION_LIST_ITEMS 1
3614 #define CAMPAIGN_LIST_ITEMS 2
3616 // send an individual mission file item
3617 void send_mission_items( net_player *pl )
3619 ubyte data[MAX_PACKET_SIZE];
3624 BUILD_HEADER(MISSION_ITEM);
3626 // send the list of missions and campaigns avilable on the server. Stop when
3627 // reaching a certain maximum
3628 type = MISSION_LIST_ITEMS;
3630 for (i = 0; i < Multi_create_mission_count; i++ ) {
3634 ADD_STRING( Multi_create_mission_list[i].filename );
3635 ADD_STRING( Multi_create_mission_list[i].name );
3636 ADD_INT( Multi_create_mission_list[i].flags );
3637 ADD_DATA( Multi_create_mission_list[i].max_players );
3638 ADD_UINT( Multi_create_mission_list[i].respawn );
3641 ADD_DATA( Multi_create_mission_list[i].valid_status );
3643 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3646 multi_io_send_reliable(pl, data, packet_size);
3647 BUILD_HEADER( MISSION_ITEM );
3653 multi_io_send_reliable(pl, data, packet_size);
3655 // send the campaign information
3656 type = CAMPAIGN_LIST_ITEMS;
3657 BUILD_HEADER(MISSION_ITEM);
3659 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3663 ADD_STRING( Multi_create_campaign_list[i].filename );
3664 ADD_STRING( Multi_create_campaign_list[i].name );
3665 ADD_INT( Multi_create_campaign_list[i].flags );
3666 ADD_DATA( Multi_create_campaign_list[i].max_players );
3668 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3671 multi_io_send_reliable(pl, data, packet_size);
3672 BUILD_HEADER( MISSION_ITEM );
3678 multi_io_send_reliable(pl, data, packet_size);
3681 // process a request for a list of missions
3682 void process_mission_request_packet(ubyte *data, header *hinfo)
3684 int player_num,offset;
3686 offset = HEADER_LENGTH;
3689 // fill in the address information of where this came from
3690 player_num = find_player_id(hinfo->id);
3691 if(player_num == -1){
3692 nprintf(("Network","Could not find player to send mission list items to!\n"));
3696 send_mission_items( &Net_players[player_num] );
3699 // process an individual mission file item
3700 void process_mission_item_packet(ubyte *data,header *hinfo)
3703 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3704 ubyte stop, type,max_players;
3707 SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3708 offset = HEADER_LENGTH;
3713 GET_STRING( filename );
3716 GET_DATA( max_players );
3718 // missions also have respawns and a crc32 associated with them
3719 if(type == MISSION_LIST_ITEMS){
3723 GET_DATA(valid_status);
3725 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3726 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3727 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3728 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3729 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3730 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3733 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3735 Multi_create_mission_count++;
3737 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3738 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3739 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3740 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3741 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3742 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3743 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3744 Multi_create_campaign_count++;
3753 // this will cause whatever list to get resorted (although they should be appearing in order)
3754 multi_create_setup_list_data(-1);
3757 // send a request to the server to pause or unpause the game
3758 void send_multi_pause_packet(int pause)
3760 ubyte data[MAX_PACKET_SIZE];
3762 int packet_size = 0;
3764 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3767 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3768 val = (ubyte) pause;
3770 // add the pause info
3773 // send the request to the server
3774 multi_io_send_reliable(Net_player, data, packet_size);
3777 // process a pause update packet (pause, unpause, etc)
3778 void process_multi_pause_packet(ubyte *data, header *hinfo)
3784 offset = HEADER_LENGTH;
3790 // get who sent the packet
3791 player_index = find_player_id(hinfo->id);
3792 // if we don't know who sent the packet, don't do anything
3793 if(player_index == -1){
3797 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3798 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3801 // send a game information update
3802 void send_game_info_packet()
3805 ubyte data[MAX_PACKET_SIZE], paused;
3807 // set the paused variable
3808 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3810 BUILD_HEADER(GAME_INFO);
3811 ADD_INT( Missiontime );
3814 multi_io_send_to_all(data, packet_size);
3817 // process a game information update
3818 void process_game_info_packet( ubyte *data, header *hinfo )
3824 offset = HEADER_LENGTH;
3826 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3827 // time, set our time to server time (should take ping time into account!!!)
3828 GET_DATA( mission_time );
3833 // send an ingame nak packet
3834 void send_ingame_nak(int state, net_player *p)
3836 ubyte data[MAX_PACKET_SIZE];
3837 int packet_size = 0;
3839 BUILD_HEADER(INGAME_NAK);
3843 multi_io_send_reliable(p, data, packet_size);
3846 // process an ingame nak packet
3847 void process_ingame_nak(ubyte *data, header *hinfo)
3849 int offset,state,pid;
3851 offset = HEADER_LENGTH;
3855 pid = find_player_id(hinfo->id);
3861 case ACK_FILE_ACCEPTED :
3862 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3863 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3864 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3869 // send a packet telling players to end the mission
3870 void send_endgame_packet(net_player *pl)
3872 ubyte data[MAX_PACKET_SIZE];
3873 int packet_size = 0;
3875 BUILD_HEADER(MISSION_END);
3877 // sending to a specific player?
3879 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3880 multi_io_send_reliable(pl, data, packet_size);
3884 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3885 // send all player stats here
3886 multi_broadcast_stats(STATS_MISSION);
3888 // if in dogfight mode, send all dogfight stats as well
3889 ml_string("Before dogfight stats!");
3890 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3891 ml_string("Sending dogfight stats!");
3893 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3895 ml_string("After dogfight stats!");
3897 // tell everyone to leave the game
3898 multi_io_send_to_all_reliable(data, packet_size);
3900 multi_io_send_reliable(Net_player, data, packet_size);
3904 // process a packet indicating we should end the current mission
3905 void process_endgame_packet(ubyte *data, header *hinfo)
3910 offset = HEADER_LENGTH;
3914 ml_string("Receiving endgame packet");
3916 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3917 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3918 // determine who this came from and make sure he is allowed to end the game
3919 player_num = find_player_id(hinfo->id);
3920 SDL_assert(player_num != -1);
3925 // if the player is allowed to end the mission
3926 if(!multi_can_end_mission(&Net_players[player_num])){
3930 // act as if we hit alt+j locally
3931 multi_handle_end_mission_request();
3933 // all clients process immediately
3935 // ingame joiners should quit when they receive an endgame packet since the game is over
3936 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3937 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3941 // do any special processing for being in a state other than the gameplay state
3942 multi_handle_state_special();
3944 // make sure we're not already in the debrief state
3945 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3946 multi_warpout_all_players();
3951 // send a position/orientation update for myself (if I'm an observer)
3952 void send_observer_update_packet()
3954 ubyte data[MAX_PACKET_SIZE];
3955 int packet_size = 0;
3959 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3960 // to send any update packets to anyone.
3961 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3965 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3969 BUILD_HEADER(OBSERVER_UPDATE);
3971 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3973 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3976 // add targeting infomation
3977 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3978 target_sig = Objects[Player_ai->target_objnum].net_signature;
3982 ADD_USHORT(target_sig);
3984 multi_io_send(Net_player, data, packet_size);
3987 // process a position/orientation update from an observer
3988 void process_observer_update_packet(ubyte *data, header *hinfo)
3994 physics_info bogus_pi;
3997 offset = HEADER_LENGTH;
3999 obs_num = find_player_id(hinfo->id);
4001 memset(&bogus_pi,0,sizeof(physics_info));
4002 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
4004 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
4007 // targeting information
4008 GET_USHORT(target_sig);
4011 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
4015 // set targeting info
4016 if(target_sig == 0){
4017 Net_players[obs_num].s_info.target_objnum = -1;
4019 target_obj = multi_get_network_object(target_sig);
4020 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4023 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4024 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4025 Net_players[obs_num].s_info.eye_pos = g_vec;
4026 Net_players[obs_num].s_info.eye_orient = g_mat;
4029 void send_netplayer_slot_packet()
4031 ubyte data[MAX_PACKET_SIZE];
4032 int packet_size = 0, idx;
4037 BUILD_HEADER(NETPLAYER_SLOTS_P);
4038 for(idx=0;idx<MAX_PLAYERS;idx++){
4039 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4041 ADD_SHORT(Net_players[idx].player_id);
4042 ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4043 ADD_INT(Net_players[idx].p_info.ship_class);
4044 ADD_INT(Net_players[idx].p_info.ship_index);
4050 // standalone case or not
4051 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
4052 multi_io_send_to_all_reliable(data, packet_size);
4054 multi_io_send_reliable(Net_player, data, packet_size);
4058 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4061 int player_num,ship_class,ship_index;
4067 offset = HEADER_LENGTH;
4069 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4070 multi_untag_player_ships();
4074 GET_SHORT(player_id);
4075 GET_USHORT(net_sig);
4076 GET_INT(ship_class);
4077 GET_INT(ship_index);
4078 player_num = find_player_id(player_id);
4080 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4082 // call the function in multiutil.cpp to set up the player object stuff
4083 // being careful not to muck with the standalone object
4084 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4085 objp = multi_get_network_object(net_sig);
4086 SDL_assert(objp != NULL);
4087 multi_assign_player_ship( player_num, objp, ship_class );
4088 Net_players[player_num].p_info.ship_index = ship_index;
4089 objp->flags &= ~(OF_COULD_BE_PLAYER);
4090 objp->flags |= OF_PLAYER_SHIP;
4097 // standalone should forward the packet and wait for a response
4098 if(Game_mode & GM_STANDALONE_SERVER){
4099 send_netplayer_slot_packet();
4102 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4103 send_netplayer_update_packet();
4106 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4107 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4108 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4109 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4111 ubyte data[MAX_PACKET_SIZE], utmp;
4114 BUILD_HEADER(SHIP_WSTATE_CHANGE);
4115 ADD_USHORT( Objects[shipp->objnum].net_signature );
4116 utmp = (ubyte)(what);
4118 utmp = (ubyte)(new_bank);
4120 utmp = (ubyte)(link_status);
4123 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4124 multi_io_send_to_all_reliable(data, packet_size);
4127 void process_ship_weapon_change( ubyte *data, header *hinfo )
4131 ubyte what, new_bank, link_status;
4135 offset = HEADER_LENGTH;
4136 GET_USHORT( signature );
4138 GET_DATA( new_bank );
4139 GET_DATA( link_status );
4142 objp = multi_get_network_object( signature );
4143 if ( objp == NULL ) {
4144 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4147 // SDL_assert( objp->type == OBJ_SHIP );
4148 if(objp->type != OBJ_SHIP){
4152 // if this is my data, do nothing since I already have my own data
4153 if ( objp == Player_obj ){
4157 // now, get the ship and set the new bank and link modes based on the 'what' value
4158 shipp = &Ships[objp->instance];
4159 if ( what == MULTI_PRIMARY_CHANGED ) {
4160 shipp->weapons.current_primary_bank = new_bank;
4162 shipp->flags |= SF_PRIMARY_LINKED;
4164 shipp->flags &= ~SF_PRIMARY_LINKED;
4167 shipp->weapons.current_secondary_bank = new_bank;
4169 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4171 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4176 // ship status change procedure
4177 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4179 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4180 // for added redundancy.
4181 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4182 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4183 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4184 // back to the client. Also sends multiple times for redundancy
4185 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4186 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4187 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4189 #define SHIP_STATUS_REPEAT 2
4190 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4193 ubyte data[MAX_PACKET_SIZE];
4194 int packet_size = 0;
4200 BUILD_HEADER(SHIP_STATUS_CHANGE);
4202 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4203 temp = bi->status[idx];
4207 // server should send reliably (response packet)
4208 if(MULTIPLAYER_MASTER){
4209 multi_io_send_reliable(pl, data, packet_size);
4211 multi_io_send(pl, data, packet_size);
4215 void process_ship_status_packet(ubyte *data, header *hinfo)
4219 int player_num,unique_id;
4223 offset = HEADER_LENGTH;
4225 // zero out the button info structure for good measure
4226 memset(&bi,0,sizeof(button_info));
4228 // read the button-info
4231 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4233 bi.status[idx] = i_tmp;
4238 // this will be handled differently client and server side. Duh.
4239 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4240 // find which net-player has sent us butotn information
4241 player_num = find_player_id(hinfo->id);
4242 SDL_assert(player_num >= 0);
4247 // don't process critical button information for observers
4248 // its a new button_info for this guy. apply and ack
4249 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4250 // mark that he's pressed this button
4251 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4253 // send a return packet
4254 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4256 // apply the button presses to his ship as normal
4257 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4259 // else ignore it as a repeat from the same guy
4260 } else { // CLIENT SIDE
4261 // this is the return from the server, so we should now apply them locally
4262 // if(lookup_ship_status(Net_player,unique_id,1)){
4263 multi_apply_ship_status(Net_player, &bi, 1);
4268 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4269 // for clients. Left all details to this function instead of higher level messaging
4271 void send_player_order_packet(int type, int index, int cmd)
4273 ubyte data[MAX_PACKET_SIZE];
4275 ushort target_signature;
4277 int packet_size = 0;
4279 BUILD_HEADER(PLAYER_ORDER_PACKET);
4282 ADD_DATA(val); // ship order or wing order, or message all fighters
4284 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4285 if ( val != SQUAD_MSG_ALL ){
4286 ADD_INT(index); // net signature of target ship
4289 ADD_INT(cmd); // the command itself
4292 target_signature = 0;
4293 if ( Player_ai->target_objnum != -1 ){
4294 target_signature = Objects[Player_ai->target_objnum].net_signature;
4297 ADD_USHORT( target_signature );
4300 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4303 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4304 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
4305 t_subsys = (char)s_index;
4309 multi_io_send_reliable(Net_player, data, packet_size);
4312 // brief explanation :
4313 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4314 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4315 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4316 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4317 void process_player_order_packet(ubyte *data, header *hinfo)
4319 int offset, player_num, command, index = 0, tobjnum_save;
4320 ushort target_signature;
4321 char t_subsys, type;
4322 object *objp, *target_objp;
4325 ship_subsys *tsubsys_save, *targeted_subsys;
4327 SDL_assert(MULTIPLAYER_MASTER);
4329 // packet values - its easier to read all of these in first
4331 offset = HEADER_LENGTH;
4334 if ( type != SQUAD_MSG_ALL ){
4339 GET_USHORT( target_signature );
4340 GET_DATA( t_subsys );
4344 player_num = find_player_id(hinfo->id);
4345 if(player_num == -1){
4346 nprintf(("Network","Received player order packet from unknown player\n"));
4350 objp = &Objects[Net_players[player_num].player->objnum];
4351 if ( objp->type != OBJ_SHIP ) {
4352 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4356 // HACK HACK HACK HACK HACK HACK
4357 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4358 // the data is BOGUS. All people should be able to to these things as well.
4359 if(command == REARM_REPAIR_ME_ITEM){
4360 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4362 } else if(command == ABORT_REARM_REPAIR_ITEM){
4363 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4367 // if this player is not allowed to do messaging, quit here
4368 if( !multi_can_message(&Net_players[player_num]) ){
4369 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4373 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4374 // then call them in.
4375 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4376 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4377 hud_squadmsg_call_reinforcement(index, player_num);
4381 // set the player's ai information here
4382 shipp = &Ships[objp->instance];
4383 aip = &Ai_info[shipp->ai_index];
4385 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4386 target_objp = multi_get_network_object( target_signature );
4387 if ( target_objp == NULL ) {
4391 targeted_subsys = NULL;
4392 if ( t_subsys != -1 ) {
4393 SDL_assert( target_objp != NULL );
4394 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4397 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4399 tobjnum_save = aip->target_objnum;
4400 tsubsys_save = aip->targeted_subsys;
4402 if ( target_objp ) {
4403 aip->target_objnum = OBJ_INDEX(target_objp);
4405 aip->target_objnum = -1;
4408 aip->targeted_subsys = targeted_subsys;
4410 if ( type == SQUAD_MSG_SHIP ) {
4411 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4412 } else if ( type == SQUAD_MSG_WING ) {
4413 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4414 } else if ( type == SQUAD_MSG_ALL ) {
4415 hud_squadmsg_send_to_all_fighters( command, player_num );
4418 SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4419 aip->target_objnum = tobjnum_save;
4420 aip->targeted_subsys = tsubsys_save;
4423 // FILE SIGNATURE stuff :
4424 // there are 2 cases for file signature sending which are handled very differently
4425 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4426 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4427 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4428 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4429 // would have to keep track of up to potentially 14 other ack handles (ouch).
4430 void send_file_sig_packet(ushort sum_sig,int length_sig)
4432 ubyte data[MAX_PACKET_SIZE];
4433 int packet_size = 0;
4435 BUILD_HEADER(FILE_SIG_INFO);
4436 ADD_USHORT(sum_sig);
4437 ADD_INT(length_sig);
4439 multi_io_send_reliable(Net_player, data, packet_size);
4442 void process_file_sig_packet(ubyte *data, header *hinfo)
4447 offset = HEADER_LENGTH;
4449 // should only be received on the server-side
4450 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4452 GET_USHORT(sum_sig);
4453 GET_INT(length_sig);
4455 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4458 void send_file_sig_request(char *file_name)
4460 ubyte data[MAX_PACKET_SIZE];
4461 int packet_size = 0;
4463 BUILD_HEADER(FILE_SIG_REQUEST);
4464 ADD_STRING(file_name);
4466 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4468 multi_io_send_to_all_reliable(data, packet_size);
4471 void process_file_sig_request(ubyte *data, header *hinfo)
4473 int offset = HEADER_LENGTH;
4475 // get the mission name
4476 GET_STRING(Netgame.mission_name);
4479 // set the current mission filename
4480 SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4483 multi_get_mission_checksum(Game_current_mission_filename);
4485 if(!multi_endgame_ending()){
4486 // reply to the server
4487 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4491 // functions to deal with subsystems getting whacked
4492 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4494 ubyte data[MAX_PACKET_SIZE];
4497 vector tmp, local_hitpos;
4500 SDL_assert ( index < UCHAR_MAX );
4501 uindex = (ubyte)(index);
4503 objp = &Objects[shipp->objnum];
4505 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4506 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4508 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4509 ADD_USHORT( Objects[shipp->objnum].net_signature );
4511 // ADD_DATA( local_hitpos );
4512 add_vector_data(data, &packet_size, local_hitpos);
4514 multi_io_send_to_all_reliable(data, packet_size);
4517 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4523 vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4525 offset = HEADER_LENGTH;
4527 GET_USHORT( signature );
4529 // GET_DATA( local_hit_pos );
4530 get_vector_data(data, &offset, local_hit_pos);
4532 // get the network object. process it if we find it.
4533 objp = multi_get_network_object( signature );
4534 if ( objp != NULL ) {
4536 ship_subsys *subsysp;
4538 // be sure we have a ship!!!
4539 // SDL_assert ( objp->type == OBJ_SHIP );
4540 if(objp->type != OBJ_SHIP){
4545 shipp = &Ships[objp->instance];
4547 // call to get the pointer to the subsystem we should be working on
4548 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4549 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4550 vm_vec_add2( &world_hit_pos, &objp->pos );
4552 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4553 if ( objp == Player_obj ) {
4554 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4562 // packet to tell clients cargo of a ship was revealed to all
4563 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4565 ubyte data[MAX_PACKET_SIZE], uindex;
4568 SDL_assert ( index < UCHAR_MAX );
4569 uindex = (ubyte)(index);
4571 // build the header and add the data
4572 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4573 ADD_USHORT( Objects[shipp->objnum].net_signature );
4576 // server sends to all players
4577 if(MULTIPLAYER_MASTER){
4578 multi_io_send_to_all_reliable(data, packet_size);
4580 // clients just send to the server
4582 multi_io_send_reliable(Net_player, data, packet_size);
4586 // process a subsystem cargo revealed packet
4587 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4594 ship_subsys *subsysp;
4596 offset = HEADER_LENGTH;
4597 GET_USHORT( signature );
4601 // get a ship pointer and call the ship function to reveal the cargo
4602 objp = multi_get_network_object( signature );
4603 if ( objp == NULL ) {
4604 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4608 // SDL_assert( objp->type == OBJ_SHIP );
4609 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4613 shipp = &Ships[objp->instance];
4615 // call to get the pointer to the subsystem we should be working on
4616 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4617 if (subsysp == NULL) {
4618 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4622 // this will take care of re-routing to all other clients
4623 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4624 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4626 // server should rebroadcast
4627 if(MULTIPLAYER_MASTER){
4628 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4632 void send_netplayer_load_packet(net_player *pl)
4634 ubyte data[MAX_PACKET_SIZE];
4635 int packet_size = 0;
4637 BUILD_HEADER(LOAD_MISSION_NOW);
4638 ADD_STRING(Netgame.mission_name);
4641 multi_io_send_to_all_reliable(data, packet_size);
4643 multi_io_send_reliable(pl, data, packet_size);
4647 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4650 int offset = HEADER_LENGTH;
4655 SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4656 SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4657 if(!Multi_mission_loaded){
4659 // MWA 2/3/98 -- ingame join changes!!!
4660 // everyone can go through the same mission loading path here!!!!
4661 nprintf(("Network","Loading mission..."));
4663 // notify everyone that I'm loading the mission
4664 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4665 send_netplayer_update_packet();
4667 // do the load itself
4668 game_start_mission();
4670 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4671 // code will remark the correct player ships
4672 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4673 multi_untag_player_ships();
4676 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4677 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4678 send_netplayer_update_packet();
4680 Multi_mission_loaded = 1;
4681 nprintf(("Network","Finished loading mission\n"));
4685 void send_jump_into_mission_packet(net_player *pl)
4687 ubyte data[MAX_PACKET_SIZE];
4688 int packet_size = 0;
4690 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4692 BUILD_HEADER(JUMP_INTO_GAME);
4694 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4695 // and possible other things.
4697 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4698 ADD_INT(Netgame.game_state);
4704 multi_io_send_to_all_reliable(data, packet_size);
4706 // send to a specific player
4708 multi_io_send_reliable(pl, data, packet_size);
4712 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4714 int offset = HEADER_LENGTH;
4717 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4718 // the game could be paused, so ingame joiner needs to deal with it.
4719 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4721 Netgame.game_state = state;
4726 // handle any special processing for being in a weird substate
4727 multi_handle_state_special();
4729 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4730 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4731 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4732 multi_ingame_observer_finish();
4734 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4735 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4736 send_netplayer_update_packet();
4739 // start the mission!!
4740 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4741 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4742 gameseq_post_event(GS_EVENT_ENTER_GAME);
4743 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4744 send_netplayer_update_packet();
4748 extern time_t Player_multi_died_check;
4749 Player_multi_died_check = -1;
4751 // recalc all object pairs now
4752 extern void obj_reset_all_collisions();
4753 obj_reset_all_collisions();
4755 // display some cool text
4756 multi_common_add_text(XSTR("Received mission start\n",720),1);
4759 ml_string(NOX("Client received mission start from server - entering mission"));
4764 const char *repair_text[] = {
4766 "REPAIR_INFO_BEGIN",
4768 "REPAIR_INFO_UPDATE",
4769 "REPAIR_INFO_QUEUE",
4770 "REPAIR_INFO_ABORT",
4771 "REPAIR_INFO_BROKEN",
4772 "REPAIR_INFO_WARP_ADD",
4773 "REPAIR_INFO_WARP_REMOVE",
4774 "REPAIR_INFO_ONWAY",
4775 "REPAIR_INFO_KILLED",
4776 "REPAIR_INFO_COMPLETE",
4781 // the following two routines deal with updating and sending information regarding players
4782 // rearming and repairing during the game. The process function calls the routines to deal with
4783 // setting flags and other interesting things.
4784 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4786 int packet_size = 0;
4787 ushort repaired_signature, repair_signature;
4788 ubyte data[MAX_PACKET_SIZE];
4791 // use the network signature of the destination object if there is one, -1 otherwise.
4792 // client will piece it all together
4793 repaired_signature = repaired_objp->net_signature;
4795 // the repair ship may be NULL here since it might have been destroyed
4796 repair_signature = 0;
4798 repair_signature = repair_objp->net_signature;
4801 BUILD_HEADER(CLIENT_REPAIR_INFO);
4804 ADD_USHORT( repaired_signature );
4805 ADD_USHORT( repair_signature );
4807 multi_io_send_to_all_reliable(data, packet_size);
4809 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));
4812 void process_repair_info_packet(ubyte *data, header *hinfo)
4814 int offset = HEADER_LENGTH;
4815 ushort repaired_signature, repair_signature;
4816 object *repaired_objp, *repair_objp;
4820 GET_USHORT( repaired_signature );
4821 GET_USHORT( repair_signature );
4824 repaired_objp = multi_get_network_object( repaired_signature );
4825 repair_objp = multi_get_network_object( repair_signature );
4827 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));
4829 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4833 if ( repaired_objp == NULL ) {
4834 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4838 // the hope is to simply call the routine in the ai code to set/unset flags
4839 // based on the code value and everything else should happen..I hope....
4840 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4842 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4844 // set the dock flags when repair begins. Prevents problem in lagging docking
4845 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4847 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4848 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4849 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4852 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4854 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4855 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4858 if ( code == REPAIR_INFO_WARP_ADD ){
4859 mission_warp_in_support_ship( repaired_objp );
4861 mission_remove_scheduled_repair( repaired_objp );
4866 // sends information updating clients on certain AI information that clients will
4867 // need to know about to keep HUD information up to date. objp is the object that we
4868 // are updating, and what is the type of stuff that we are updating.
4869 void send_ai_info_update_packet( object *objp, char what )
4872 ushort other_signature;
4873 ubyte data[MAX_PACKET_SIZE];
4875 ubyte dock_index, dockee_index;
4877 // SDL_assert( objp->type == OBJ_SHIP );
4878 if(objp->type != OBJ_SHIP){
4881 aip = &Ai_info[Ships[objp->instance].ai_index];
4884 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4887 BUILD_HEADER( AI_INFO_UPDATE );
4888 ADD_USHORT( objp->net_signature );
4891 // depending on the "what" value, we will send different information
4895 case AI_UPDATE_DOCK:
4896 // for docking ships, add the signature of the ship that we are docking with.
4897 SDL_assert( aip->dock_objnum != -1 );
4898 other_signature = Objects[aip->dock_objnum].net_signature;
4899 dock_index = (ubyte)(aip->dock_index);
4900 dockee_index = (ubyte)(aip->dockee_index);
4901 ADD_USHORT( other_signature );
4902 ADD_DATA(dock_index);
4903 ADD_DATA(dockee_index);
4906 case AI_UPDATE_UNDOCK:
4907 // for undocking ships, check the dock_objnum since we might or might not have it
4908 // depending on whether or not a ship was destroyed while we were docked.
4909 other_signature = 0;
4910 if ( aip->dock_objnum != -1 )
4911 other_signature = Objects[aip->dock_objnum].net_signature;
4912 ADD_USHORT( other_signature );
4916 case AI_UPDATE_ORDERS: {
4919 // for orders, we only need to send a little bit of information here. Be sure that the
4920 // first order for this ship is active
4921 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4922 ADD_INT( aip->goals[0].ai_mode );
4923 ADD_INT( aip->goals[0].ai_submode );
4925 if ( aip->goals[0].ship_name != NULL )
4926 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4928 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4929 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4930 if ( shipnum != -1 ) {
4931 SDL_assert( Ships[shipnum].objnum != -1 );
4932 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4934 other_signature = 0;
4936 ADD_USHORT( other_signature );
4938 // for docking, add the dock and dockee index
4939 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4940 SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4941 SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4942 dock_index = (ubyte)aip->goals[0].docker.index;
4943 dockee_index = (ubyte)aip->goals[0].dockee.index;
4944 ADD_DATA( dock_index );
4945 ADD_DATA( dockee_index );
4954 multi_rate_add(1, "aiu", packet_size);
4955 multi_io_send_to_all_reliable(data, packet_size);
4958 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4959 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4960 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4962 int offset = HEADER_LENGTH;
4964 ushort net_signature, other_net_signature;
4965 object *objp, *other_objp;
4968 ubyte dock_index = 0, dockee_index = 0;
4970 GET_USHORT( net_signature ); // signature of the object that we are dealing with.
4971 GET_DATA( code ); // code of what we are doing.
4972 objp = multi_get_network_object( net_signature );
4974 nprintf(("Network", "Couldn't find object for ai update\n"));
4978 case AI_UPDATE_DOCK:
4979 GET_USHORT( other_net_signature );
4980 GET_DATA( dock_index );
4981 GET_DATA( dockee_index );
4982 other_objp = multi_get_network_object( other_net_signature );
4983 if ( !other_objp ) {
4984 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4987 // if we don't have an object to work with, break out of loop
4988 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4992 SDL_assert( other_objp->type == OBJ_SHIP );
4993 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4994 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4996 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4997 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4999 ai_do_objects_docked_stuff( objp, other_objp );
5002 case AI_UPDATE_UNDOCK:
5003 GET_USHORT( other_net_signature );
5004 other_objp = multi_get_network_object( other_net_signature );
5006 // if we don't have an object to work with, break out of loop
5010 ai_do_objects_undocked_stuff( objp, other_objp );
5013 case AI_UPDATE_ORDERS:
5016 GET_USHORT( other_net_signature );
5017 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5018 GET_DATA(dock_index);
5019 GET_DATA(dockee_index);
5022 // be sure that we have a ship object!!!
5023 if ( !objp || (objp->type != OBJ_SHIP) )
5026 // set up the information in the first goal element of the object in question
5027 aip = &Ai_info[Ships[objp->instance].ai_index];
5028 aip->active_goal = 0;
5029 aip->goals[0].ai_mode = mode;
5030 aip->goals[0].ai_submode = submode;
5032 // for docking, add the dock and dockee index
5033 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5034 aip->dock_index = dock_index;
5035 aip->dockee_index = dockee_index;
5038 // get a shipname if we can.
5039 other_objp = multi_get_network_object( other_net_signature );
5040 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5041 // get a pointer to the shipname in question. Use the ship_name value in the
5042 // ship. We are only using this for HUD display, so I think that using this
5043 // method will be fine.
5044 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5046 // special case for destroy subsystem -- get the ai_info pointer to our target ship
5047 // so that we can properly set up what subsystem this ship is attacking.
5048 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5049 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5051 // if docking -- set the dock index and dockee index of this other ship
5052 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5053 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5054 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5061 Int3(); // this Int3() should be temporary
5062 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5068 // tell the standalone to move into the MISSION_SYNC_STATE
5069 void send_mission_sync_packet(int mode,int start_campaign)
5071 ubyte data[MAX_PACKET_SIZE],is_campaign;
5072 int packet_size = 0;
5074 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5076 // build the header and add the sync mode (pre or post briefing)
5077 BUILD_HEADER(MISSION_SYNC_DATA);
5080 // if this is a campaign game
5081 if(mode == MULTI_SYNC_PRE_BRIEFING){
5082 if(Game_mode & GM_CAMPAIGN_MODE){
5083 // add a byte indicating campaign mode
5085 ADD_DATA(is_campaign);
5087 // add a byte indicating if we should be starting a campaign or continuing it
5088 is_campaign = (ubyte)start_campaign;
5089 ADD_DATA(is_campaign);
5091 // add the campaign filename
5092 ADD_STRING(Netgame.campaign_name);
5094 // otherwise if this is a single mission
5096 // add a byte indicating single mission mode
5098 ADD_DATA(is_campaign);
5100 // add the mission filename
5101 ADD_STRING(Game_current_mission_filename);
5104 multi_io_send_reliable(Net_player, data, packet_size);
5107 // move into the MISSION_SYNC state when this is received
5108 // this packet is sent only from a game host to a standalone
5109 void process_mission_sync_packet(ubyte *data, header *hinfo)
5112 ubyte campaign_flag;
5113 int offset = HEADER_LENGTH;
5115 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5117 // if this is a team vs team situation, lock the players send a final team update
5118 if(Netgame.type_flags & NG_TYPE_TEAM){
5119 multi_team_host_lock_all();
5120 multi_team_send_update();
5123 // get the sync mode (pre or post briefing)
5126 if(mode == MULTI_SYNC_PRE_BRIEFING){
5127 // get the flag indicating if this is a single mission or a campaign mode
5128 GET_DATA(campaign_flag);
5130 // get the flag indicating whether we should be starting a new campaign
5131 GET_DATA(campaign_flag);
5133 // get the campaign filename
5134 GET_STRING(Netgame.campaign_name);
5136 // either start a new campaign or continue on to the next mission in the current campaign
5138 multi_campaign_start(Netgame.campaign_name);
5140 multi_campaign_next_mission();
5143 // make sure we remove the campaign mode flag
5144 Game_mode &= ~(GM_CAMPAIGN_MODE);
5146 // get the single mission filename
5147 GET_STRING(Game_current_mission_filename);
5148 SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5153 // set the correct mode and m ove into the state
5154 Multi_sync_mode = mode;
5155 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5158 // tell a player to merge his mission stats into his alltime stats
5159 void send_store_stats_packet(int accept)
5162 int packet_size = 0;
5164 BUILD_HEADER(STORE_MISSION_STATS);
5166 // add whether we're accepting or tossing
5167 val = (ubyte)accept;
5170 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5171 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5172 multi_io_send_to_all_reliable(data, packet_size);
5174 multi_io_send_reliable(Net_player, data, packet_size);
5178 void process_store_stats_packet(ubyte *data, header *hinfo)
5180 int offset = HEADER_LENGTH;
5186 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5187 if(Game_mode & GM_STANDALONE_SERVER){
5188 // rebroadcast the packet to all others in the game
5189 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5190 multi_io_send_to_all_reliable(data, offset);
5193 // all players should mark the stats as being accepted in the debriefing
5194 multi_debrief_stats_accept();
5196 // all players should mark the stats as being "tossed" in the debriefing
5197 multi_debrief_stats_toss();
5202 void send_debris_update_packet(object *objp,int code)
5204 ubyte data[MAX_PACKET_SIZE];
5206 int packet_size = 0;
5208 BUILD_HEADER(DEBRIS_UPDATE);
5209 ADD_USHORT(objp->net_signature);
5213 // add any extra relevant data
5215 case DEBRIS_UPDATE_UPDATE:
5216 // ADD_DATA(objp->pos); // add position
5217 add_vector_data(data, &packet_size, objp->pos);
5218 ADD_ORIENT(objp->orient); // add orientation
5219 // ADD_DATA(objp->phys_info.vel); // add velocity
5220 add_vector_data(data, &packet_size, objp->phys_info.vel);
5221 // ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5222 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5225 multi_io_send_to_all(data, packet_size);
5228 void process_debris_update_packet(ubyte *data, header *hinfo)
5232 object bogus_object;
5234 int offset = HEADER_LENGTH;
5236 GET_USHORT(net_sig);
5240 objp = multi_get_network_object(net_sig);
5242 objp = &bogus_object;
5246 // update the object
5247 case DEBRIS_UPDATE_UPDATE:
5248 //GET_DATA(objp->pos);
5249 get_vector_data( data, &offset, objp->pos );
5251 GET_ORIENT(objp->orient);
5252 GET_DATA(objp->phys_info.vel);
5253 GET_DATA(objp->phys_info.rotvel);
5255 // simply remove it (no explosion)
5256 case DEBRIS_UPDATE_REMOVE:
5257 if(objp != &bogus_object){
5258 SDL_assert(objp->type == OBJ_DEBRIS);
5259 obj_delete(OBJ_INDEX(objp));
5263 case DEBRIS_UPDATE_NUKE:
5264 if(objp != &bogus_object)
5265 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5273 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)
5275 ubyte data[MAX_PACKET_SIZE];
5277 int packet_size = 0;
5279 BUILD_HEADER(WSS_REQUEST_PACKET);
5281 // add the request information
5282 ADD_SHORT(player_id);
5284 ADD_INT(from_index);
5287 ADD_INT(wl_ship_slot); // only used in weapons loadout
5288 ADD_INT(ship_class);
5291 // a standard request
5293 multi_io_send_reliable(Net_player, data, packet_size);
5295 // being routed through the standalone to the host of the game
5297 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5298 multi_io_send_reliable(p, data, packet_size);
5302 void process_wss_request_packet(ubyte *data, header *hinfo)
5304 int offset = HEADER_LENGTH;
5305 int from_slot,from_index;
5306 int to_slot,to_index;
5308 int wl_ship_slot,ship_class;
5312 // determine who this request is from
5313 GET_SHORT(player_id);
5314 player_num = find_player_id(player_id);
5316 // read in the request data
5318 GET_INT(from_index);
5321 GET_INT(wl_ship_slot); // only used in weapons loadout
5322 GET_INT(ship_class); // only used in multi team select
5326 SDL_assert(player_num != -1);
5327 if(player_num == -1){
5331 // if we're the standalone, we have to route this packet to the host of the game
5332 if(Game_mode & GM_STANDALONE_SERVER){
5333 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5335 // otherwise we're the host and should process the request
5338 case WSS_WEAPON_SELECT :
5339 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5341 case WSS_SHIP_SELECT :
5342 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5350 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5352 ubyte data[MAX_PACKET_SIZE],team;
5353 int packet_size = 0;
5355 SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5357 BUILD_HEADER(WSS_UPDATE_PACKET);
5359 // add the team/pool # this is for
5360 team = (ubyte)team_num;
5363 // add the data block size
5366 // add the data itself
5367 memcpy(data + packet_size,wss_data,size);
5368 packet_size += size;
5370 // if we're also the master of the game (not on a standalone)
5371 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5372 multi_io_send_to_all_reliable(data, packet_size);
5374 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5376 multi_io_send_reliable(Net_player, data, packet_size);
5380 void process_wss_update_packet(ubyte *data, header *hinfo)
5383 int size,player_index,idx;
5384 int offset = HEADER_LENGTH;
5386 // get the team/pool #
5389 // get the data size
5392 // if we're the standalone, then we should be routing this data to all the other clients
5393 if(Game_mode & GM_STANDALONE_SERVER){
5398 // determine where this came from
5399 player_index = find_player_id(hinfo->id);
5400 SDL_assert(player_index != -1);
5401 if(player_index < 0){
5405 // route the packet (don't resend it to the host)
5406 for(idx=0;idx<MAX_PLAYERS;idx++){
5407 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5408 multi_io_send_reliable(&Net_players[idx], data, offset);
5412 // set the proper pool pointers
5413 ss_set_team_pointers((int)team);
5415 // read in the block of data, and apply it to the weapons/ship pools
5416 offset += restore_wss_data(data + offset);
5419 // set the pool pointers back to my own team
5420 ss_set_team_pointers(Net_player->p_info.team);
5422 // sync the interface if this was for my own team
5423 if((int)team == Net_player->p_info.team){
5424 multi_ts_sync_interface();
5431 // function to send firing information from the client to the server once they reach
5432 // the final sync screen.
5433 void send_firing_info_packet()
5435 ubyte data[MAX_PACKET_SIZE];
5437 ubyte plinked, sdual;
5439 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5441 BUILD_HEADER(FIRING_INFO);
5442 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5443 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5444 ADD_DATA( plinked );
5447 multi_io_send_reliable(Net_player, data, packet_size);
5450 void process_firing_info_packet( ubyte *data, header *hinfo )
5452 int offset, player_num;
5453 ubyte plinked, sdual;
5456 // only the master of the game should be dealing with these packets
5457 SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5459 offset = HEADER_LENGTH;
5460 GET_DATA( plinked );
5464 player_num = find_player_id(hinfo->id);
5466 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5470 // get the ship pointer for this player and set the flags accordingly.
5471 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5473 shipp->flags |= SF_PRIMARY_LINKED;
5475 shipp->flags &= ~SF_PRIMARY_LINKED;
5478 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5480 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5483 // packet to deal with changing status of mission goals. used to be sent every so often from server
5484 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5485 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5486 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5487 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5489 ubyte data[MAX_PACKET_SIZE];
5492 BUILD_HEADER(MISSION_GOAL_INFO);
5495 ADD_INT(new_status);
5498 multi_io_send_to_all_reliable(data, packet_size);
5501 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5503 int offset, goal_num, new_status, valid;
5505 offset = HEADER_LENGTH;
5507 GET_INT(new_status);
5511 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5512 if ( new_status != -1 ){
5513 mission_goal_status_change( goal_num, new_status );
5515 mission_goal_validation_change( goal_num, valid );
5519 void send_player_settings_packet(net_player *p)
5521 ubyte data[MAX_PACKET_SIZE];
5524 int packet_size = 0;
5527 BUILD_HEADER(PLAYER_SETTINGS);
5529 // add all the data for all the players
5531 for(idx=0;idx<MAX_PLAYERS;idx++){
5532 if(MULTI_CONNECTED(Net_players[idx])){
5534 ADD_SHORT(Net_players[idx].player_id);
5536 // break the p_info structure by member, so we don't overwrite any absolute pointers
5537 // ADD_DATA(Net_players[idx].p_info);
5538 ADD_INT(Net_players[idx].p_info.team);
5539 ADD_INT(Net_players[idx].p_info.ship_index);
5540 ADD_INT(Net_players[idx].p_info.ship_class);
5543 // add the stop byte
5547 // either broadcast the data or send to a specific player
5549 multi_io_send_to_all_reliable(data, packet_size);
5551 multi_io_send_reliable(p, data, packet_size);
5555 void process_player_settings_packet(ubyte *data, header *hinfo)
5557 int offset,player_num;
5558 net_player_info bogus,*ptr;
5562 offset = HEADER_LENGTH;
5564 // read in the data for all the players
5566 while(stop != 0xff){
5567 // lookup the player
5568 GET_SHORT(player_id);
5569 player_num = find_player_id(player_id);
5571 // make sure this is a valid player
5572 if(player_num == -1){
5575 ptr = &Net_players[player_num].p_info;
5579 GET_INT(ptr->ship_index);
5580 GET_INT(ptr->ship_class);
5587 // update the server with my new state
5588 // MWA -- 3/31/98 -- check for in mission instead of state.
5589 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5590 if( !(Game_mode & GM_IN_MISSION) ) {
5591 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5592 send_netplayer_update_packet();
5596 // display some cool text
5597 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5600 void send_deny_packet(net_addr *addr, int code)
5603 int packet_size = 0;
5605 // build the header and add the rejection code
5611 psnet_send(addr, data, packet_size);
5614 void process_deny_packet(ubyte *data, header *hinfo)
5618 // get the denial code
5619 offset = HEADER_LENGTH;
5623 // if there is already a dialog active, do nothing - who cares at this point.
5628 // display the appropriate dialog
5630 case JOIN_DENY_JR_STATE :
5631 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));
5633 case JOIN_DENY_JR_TRACKER_INVAL :
5634 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));
5636 case JOIN_DENY_JR_PASSWD :
5637 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5639 case JOIN_DENY_JR_CLOSED :
5640 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));
5642 case JOIN_DENY_JR_TEMP_CLOSED :
5643 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));
5645 case JOIN_DENY_JR_RANK_HIGH :
5646 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));
5648 case JOIN_DENY_JR_RANK_LOW :
5649 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));
5651 case JOIN_DENY_JR_DUP :
5652 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5654 case JOIN_DENY_JR_FULL :
5655 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5657 case JOIN_DENY_JR_BANNED :
5658 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5660 case JOIN_DENY_JR_NOOBS :
5661 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5663 case JOIN_DENY_JR_INGAME_JOIN :
5664 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));
5666 case JOIN_DENY_JR_BAD_VERSION :
5667 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));
5669 case JOIN_DENY_JR_TYPE :
5670 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5674 // call this so that the join request timestamp automatically expires when we hear back from the server
5675 multi_join_reset_join_stamp();
5678 // this packet will consist of
5679 // 1.) netplayer ship classes (85 bytes max)
5680 // 2.) ship weapon state data (241 bytes max)
5681 // 3.) player settings et. al. (133 bytes max)
5682 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5683 void send_post_sync_data_packet(net_player *p, int std_request)
5685 ubyte data[MAX_PACKET_SIZE], val;
5690 ushort sval, ship_ets;
5691 int idx, player_index;
5692 int packet_size = 0;
5696 BUILD_HEADER(POST_SYNC_DATA);
5698 // some header information for standalone packet routing purposes
5699 val = (ubyte)std_request;
5702 // the standalone has two situations
5703 // 1.) sending a request to the host to distribute this block of data
5704 // 2.) having recevied this block of data from the host, it redistributes it
5705 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5706 // case 1, send the request
5707 multi_io_send_reliable(Netgame.host, data, packet_size);
5710 // case 2 for the standalone is below (as normal)
5712 // otherwise build the data now
5714 // add all deleted ships
5715 val = (ubyte)Multi_ts_num_deleted;
5717 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5718 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5724 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5725 shipp = &Ships[Objects[so->objnum].instance];
5727 // don't process non player wing ships
5728 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5734 // # of ships - used multiple times in the packet
5735 val = (ubyte)ship_count;
5738 // add ship class information (85 bytes max)
5739 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5740 shipp = &Ships[Objects[so->objnum].instance];
5742 // don't process non player wing ships
5743 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5746 // add the net signature of the object for look up
5747 ADD_USHORT( Objects[so->objnum].net_signature );
5749 // add the ship info index
5750 val = (ubyte)(shipp->ship_info_index);
5753 // add the ships's team select index
5754 val = (ubyte)shipp->ts_index;
5758 // add weapon state information for all starting ships (241 bytes max)
5759 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5760 shipp = &Ships[Objects[so->objnum].instance];
5762 // don't process non player wing ships
5763 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5766 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5768 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5769 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5770 if(player_index == -1){
5773 pl = &Net_players[player_index];
5777 // add the net signature and other weapon information
5778 ADD_USHORT( Objects[so->objnum].net_signature );
5780 // add number of primary and secondary banks
5781 bval = (char)(shipp->weapons.num_primary_banks);
5783 bval = (char)(shipp->weapons.num_secondary_banks);
5786 // add weapon bank status
5787 bval = (char)(shipp->weapons.current_primary_bank);
5789 pl->s_info.cur_primary_bank = bval;
5791 // SDL_assert(bval != -1);
5794 bval = (char)(shipp->weapons.current_secondary_bank);
5796 pl->s_info.cur_secondary_bank = bval;
5798 // SDL_assert(bval != -1);
5801 // primary weapon info
5802 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5804 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5807 // secondary weapon info
5808 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5810 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5811 ADD_SHORT(val_short);
5812 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5814 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5815 ADD_SHORT(val_short);
5816 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5818 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5819 ADD_SHORT(val_short);
5821 // send primary and secondary weapon link status
5823 if(shipp->flags & SF_PRIMARY_LINKED){
5825 pl->s_info.cur_link_status |= (1<<0);
5829 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5831 pl->s_info.cur_link_status |= (1<<1);
5835 // if this is a player ship add (1<<2)
5836 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5841 // add a ship ets value
5844 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5846 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5848 ship_ets |= ((ushort)shipp->engine_recharge_index);
5849 ADD_USHORT(ship_ets);
5853 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5854 // or if I'm the server as well as the host, I should be sending this to all players
5855 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5856 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5859 multi_io_send_to_all_reliable(data, packet_size);
5861 // send to a specific player
5863 multi_io_send_reliable(p, data, packet_size);
5866 multi_io_send_reliable(Net_player, data, packet_size);
5873 multi_io_send_to_all_reliable(data, packet_size);
5875 // send to a specific player
5877 multi_io_send_reliable(p, data, packet_size);
5882 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5884 ubyte val, sinfo_index, ts_index;
5886 ushort net_sig, ship_ets, sval;
5890 int offset = HEADER_LENGTH;
5894 // packet routing information
5897 // 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
5898 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5901 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5902 multi_ts_create_wings();
5904 // send to the standalone through my socket
5905 send_post_sync_data_packet(Net_player);
5911 // add all deleted ships
5913 Multi_ts_num_deleted = (int)val;
5914 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5915 // get the ship's objnum
5918 objp = multi_get_network_object(sval);
5920 // delete the ship appropriately
5921 // mark the object as having been deleted
5922 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5925 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5926 obj_delete(Multi_ts_deleted_objnums[idx]);
5927 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5929 Multi_ts_num_deleted--;
5930 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5938 // process ship class information
5939 for(idx=0; idx<ship_count; idx++){
5940 // get the object's net signature
5941 GET_USHORT(net_sig);
5942 GET_DATA(sinfo_index);
5945 // attempt to get the object
5946 objp = multi_get_network_object(net_sig);
5948 // make sure we found a ship
5949 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5951 // set the ship to be the right class
5952 change_ship_type(objp->instance,(int)sinfo_index);
5954 // set the ship's team select index
5955 Ships[objp->instance].ts_index = (int)ts_index;
5958 // process ship weapon state info
5959 for(idx=0; idx<ship_count; idx++){
5960 // get the object's net signature
5961 GET_USHORT(net_sig);
5963 // attempt to get the object
5964 objp = multi_get_network_object(net_sig);
5966 // make sure we found a ship
5967 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5969 // get a pointer to the ship
5970 shipp = &Ships[objp->instance];
5972 // get number of primary and secondary banks;
5974 SDL_assert( b != -1 );
5975 shipp->weapons.num_primary_banks = (int)b;
5978 SDL_assert( b != -1 );
5979 shipp->weapons.num_secondary_banks = (int)b;
5981 // get bank selection info
5986 shipp->weapons.current_primary_bank = (int)b;
5992 shipp->weapons.current_secondary_bank = (int)b;
5994 // primary weapon info
5996 shipp->weapons.primary_bank_weapons[0] = (int)b;
5999 shipp->weapons.primary_bank_weapons[1] = (int)b;
6001 // secondary weapon info
6003 shipp->weapons.secondary_bank_weapons[0] = (int)b;
6004 GET_SHORT(val_short);
6005 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
6008 shipp->weapons.secondary_bank_weapons[1] = (int)b;
6009 GET_SHORT(val_short);
6010 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
6013 shipp->weapons.secondary_bank_weapons[2] = (int)b;
6014 GET_SHORT(val_short);
6015 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6022 shipp->flags |= SF_PRIMARY_LINKED;
6025 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
6027 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6028 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6030 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6032 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6036 GET_USHORT(ship_ets);
6038 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6040 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6042 shipp->engine_recharge_index = (ship_ets & 0x000f);
6047 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6048 send_netplayer_update_packet();
6050 // the standalone server will receive this packet from the host of the game, to be applied locally and
6051 // also to be rebroadcast.
6052 if(Game_mode & GM_STANDALONE_SERVER){
6053 // update player ets settings
6054 for(idx=0;idx<MAX_PLAYERS;idx++){
6055 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6056 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6060 send_post_sync_data_packet(NULL,0);
6064 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6066 ubyte data[MAX_PACKET_SIZE],val;
6069 int packet_size = 0;
6072 BUILD_HEADER(WSS_SLOTS_DATA);
6074 // some header information for standalone packet routing purposes
6075 val = (ubyte)std_request;
6079 val = (ubyte)team_num;
6082 // add whether this is the final packet or not
6086 // the standalone has two situations
6087 // 1.) sending a request to the host to distribute this block of data
6088 // 2.) having recevied this block of data from the host, it redistributes it
6089 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6090 // case 1, send the request
6091 multi_io_send_reliable(Netgame.host, data, packet_size);
6094 // case 2 for the standalone is below (as normal)
6096 // add all the slots
6097 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6098 // add the ship class
6099 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6103 for(i = 0;i<MAX_WL_WEAPONS;i++){
6104 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6108 // add the weapon counts
6109 for(i = 0;i<MAX_WL_WEAPONS;i++){
6110 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6111 ADD_SHORT(val_short);
6115 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6116 // or if I'm the server as well as the host, I should be sending this to all players
6117 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6118 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6121 multi_io_send_to_all_reliable(data, packet_size);
6123 // send to a specific player
6125 multi_io_send_reliable(p, data, packet_size);
6128 multi_io_send_reliable(Net_player, data, packet_size);
6135 multi_io_send_to_all_reliable(data, packet_size);
6137 // send to a specific player
6139 multi_io_send_reliable(p, data, packet_size);
6144 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6146 ubyte val,team_num,final;
6148 int offset = HEADER_LENGTH;
6151 // packet routing information
6157 // get whether this is the final packet or not
6160 // 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
6161 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6164 // send to the standalone through my socket
6165 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6169 // read in all the slot data
6170 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6171 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6173 // get the ship class
6175 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6178 for(i = 0;i<MAX_WL_WEAPONS;i++){
6180 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6182 // check for signed/unsigned problems
6183 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6184 Wss_slots_teams[team_num][idx].wep[i] = -1;
6188 // get the weapon counts
6189 for(i = 0;i<MAX_WL_WEAPONS;i++){
6190 GET_SHORT(val_short);
6191 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6196 // update my netplayer state if this is the final packet
6198 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6199 send_netplayer_update_packet();
6202 // the standalone server will receive this packet from the host of the game, to be applied locally and
6203 // also to be rebroadcast.
6204 if(Game_mode & GM_STANDALONE_SERVER){
6205 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6207 // add some mission sync text
6208 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6212 #define OBJ_VISIBILITY_DOT 0.6f
6214 // send and receive packets for shield explosion information
6215 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6218 ubyte data[MAX_PACKET_SIZE], utri_num;
6221 // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6223 SDL_assert( tri_num < UCHAR_MAX );
6224 utri_num = (ubyte)tri_num;
6226 // for each player, determine if this object is behind the player -- if so, don't
6228 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6229 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6231 vector eye_to_obj_vec, diff, eye_pos;
6234 eye_pos = Net_players[i].s_info.eye_pos;
6235 eye_orient = Net_players[i].s_info.eye_orient;
6237 // check for same vectors
6238 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6239 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6243 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6244 dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6246 if ( dot < OBJ_VISIBILITY_DOT ){
6250 BUILD_HEADER(SHIELD_EXPLOSION);
6252 ADD_USHORT( Objects[objnum].net_signature );
6255 multi_io_send(&Net_players[i], data, packet_size);
6260 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6262 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6269 // get the shield hit data
6270 offset = HEADER_LENGTH;
6271 GET_USHORT(signature);
6273 //GET_DATA(hit_pos);
6276 // find the object with this signature. If found, then do a shield explosion
6277 objp = multi_get_network_object( signature );
6280 shield_info *shieldp;
6285 // given the tri num, find the local position which is the average of the
6286 // three vertices of the triangle affected. Use this average point as the hit
6288 // SDL_assert( objp->type == OBJ_SHIP );
6289 if(objp->type != OBJ_SHIP){
6293 pm = model_get(Ships[objp->instance].modelnum);
6294 shieldp = &pm->shield;
6295 SDL_assert( utri_num < shieldp->ntris );
6296 stri = shieldp->tris[utri_num];
6297 vm_vec_zero(&hit_pos);
6298 for ( i = 0; i < 3; i++ ) {
6299 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6301 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6302 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6306 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6309 ubyte data[MAX_PACKET_SIZE], val;
6311 int packet_size = 0;
6316 sc = &pl->player->stats;
6319 BUILD_HEADER(PLAYER_STATS);
6321 // add the player id
6322 ADD_SHORT(pl->player_id);
6324 // add the byte indicating whether these stats are all-time or not
6325 val = (ubyte)stats_code;
6328 // kill information - alltime
6332 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6333 u_tmp = sc->kills[idx];
6336 // medal information
6337 for(idx=0;idx<NUM_MEDALS;idx++){
6338 i_tmp = sc->medals[idx];
6344 ADD_INT(sc->assists);
6345 ADD_INT(sc->kill_count);
6346 ADD_INT(sc->kill_count_ok);
6347 ADD_UINT(sc->p_shots_fired);
6348 ADD_UINT(sc->s_shots_fired);
6349 ADD_UINT(sc->p_shots_hit);
6350 ADD_UINT(sc->s_shots_hit);
6351 ADD_UINT(sc->p_bonehead_hits);
6352 ADD_UINT(sc->s_bonehead_hits);
6353 ADD_INT(sc->bonehead_kills);
6355 ADD_UINT(sc->missions_flown);
6356 ADD_UINT(sc->flight_time);
6357 ADD_INT(sc->last_flown);
6358 ADD_INT(sc->last_backup);
6363 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6364 u_tmp = sc->m_okKills[idx];
6368 ADD_INT(sc->m_score);
6369 ADD_INT(sc->m_assists);
6370 ADD_INT(sc->m_kill_count);
6371 ADD_INT(sc->m_kill_count_ok);
6372 ADD_UINT(sc->mp_shots_fired);
6373 ADD_UINT(sc->ms_shots_fired);
6374 ADD_UINT(sc->mp_shots_hit);
6375 ADD_UINT(sc->ms_shots_hit);
6376 ADD_UINT(sc->mp_bonehead_hits);
6377 ADD_UINT(sc->ms_bonehead_hits);
6378 ADD_INT(sc->m_bonehead_kills);
6379 ADD_INT(sc->m_player_deaths);
6380 ADD_INT(sc->m_medal_earned);
6383 case STATS_MISSION_KILLS:
6384 ADD_INT(sc->m_kill_count);
6385 ADD_INT(sc->m_kill_count_ok);
6386 ADD_INT(sc->m_assists);
6389 case STATS_DOGFIGHT_KILLS:
6390 for(idx=0; idx<MAX_PLAYERS; idx++){
6392 u_tmp = sc->m_dogfight_kills[idx];
6398 ADD_INT(sc->m_kill_count);
6399 ADD_INT(sc->m_kill_count_ok);
6400 ADD_INT(sc->m_assists);
6404 SDL_assert(packet_size < MAX_PACKET_SIZE);
6406 // if we're a client, always send the data to the server
6407 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6408 multi_io_send_reliable(Net_player, data, packet_size);
6410 // otherwise do server specific stuff
6412 // send to a specific target
6414 multi_io_send_reliable(target, data, packet_size);
6416 // otherwise, send to everyone
6418 multi_io_send_to_all_reliable(data, packet_size);
6423 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6427 scoring_struct *sc,bogus;
6429 int offset = HEADER_LENGTH;
6433 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6435 // get the player who these stats are for
6436 GET_SHORT(player_id);
6437 player_num = find_player_id(player_id);
6438 if (player_num == -1) {
6439 nprintf(("Network", "Couldn't find player for stats update!\n"));
6440 ml_string("Couldn't find player for stats update!\n");
6445 sc = &Net_players[player_num].player->stats;
6448 // get the stats code
6452 ml_string("Received STATS_ALLTIME\n");
6455 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6457 sc->kills[idx] = u_tmp;
6460 // read in the stats
6461 for (idx=0; idx<NUM_MEDALS; idx++) {
6463 sc->medals[idx] = i_tmp;
6468 GET_INT(sc->assists);
6469 GET_INT(sc->kill_count);
6470 GET_INT(sc->kill_count_ok);
6471 GET_UINT(sc->p_shots_fired);
6472 GET_UINT(sc->s_shots_fired);
6473 GET_UINT(sc->p_shots_hit);
6474 GET_UINT(sc->s_shots_hit);
6475 GET_UINT(sc->p_bonehead_hits);
6476 GET_UINT(sc->s_bonehead_hits);
6477 GET_INT(sc->bonehead_kills);
6479 GET_UINT(sc->missions_flown);
6480 GET_UINT(sc->flight_time);
6481 GET_INT(sc->last_flown);
6482 GET_INT(sc->last_backup);
6486 ml_string("Received STATS_MISSION\n");
6488 // kills - mission OK
6489 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6491 sc->m_okKills[idx] = u_tmp;
6494 GET_INT(sc->m_score);
6495 GET_INT(sc->m_assists);
6496 GET_INT(sc->m_kill_count);
6497 GET_INT(sc->m_kill_count_ok);
6498 GET_UINT(sc->mp_shots_fired);
6499 GET_UINT(sc->ms_shots_fired);
6500 GET_UINT(sc->mp_shots_hit);
6501 GET_UINT(sc->ms_shots_hit);
6502 GET_UINT(sc->mp_bonehead_hits);
6503 GET_UINT(sc->ms_bonehead_hits);
6504 GET_INT(sc->m_bonehead_kills);
6505 GET_INT(sc->m_player_deaths);
6506 GET_INT(sc->m_medal_earned);
6509 case STATS_MISSION_KILLS:
6510 ml_string("Received STATS_MISSION_KILLS\n");
6512 GET_INT(sc->m_kill_count);
6513 GET_INT(sc->m_kill_count_ok);
6514 GET_INT(sc->m_assists);
6517 case STATS_DOGFIGHT_KILLS:
6518 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6519 if(player_num >= 0){
6520 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6522 for(idx=0; idx<MAX_PLAYERS; idx++){
6525 sc->m_dogfight_kills[idx] = u_tmp;
6526 if(player_num >= 0){
6527 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6531 GET_INT(sc->m_kill_count);
6532 GET_INT(sc->m_kill_count_ok);
6533 GET_INT(sc->m_assists);
6538 // if I'm the server of the game, I should always rebroadcast these stats
6539 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6540 // make sure these are alltime stats
6541 SDL_assert(val == STATS_ALLTIME);
6543 multi_broadcast_stats(STATS_ALLTIME);
6547 // called to create asteroid stuff
6548 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6551 ubyte data[MAX_PACKET_SIZE];
6552 ubyte packet_type, atype;
6556 if (relvec != NULL )
6559 BUILD_HEADER( ASTEROID_INFO );
6560 packet_type = ASTEROID_CREATE;
6562 SDL_assert( asteroid_type < UCHAR_MAX );
6563 atype = (ubyte)asteroid_type;
6565 ADD_DATA( packet_type );
6566 ADD_USHORT( parent_objp->net_signature );
6567 ADD_USHORT( new_objp->net_signature );
6570 add_vector_data( data, &packet_size, vec );
6572 multi_io_send_to_all(data, packet_size);
6575 void send_asteroid_throw( object *objp )
6578 ubyte data[MAX_PACKET_SIZE], packet_type;
6580 BUILD_HEADER( ASTEROID_INFO );
6582 // this packet type is an asteroid throw
6583 packet_type = ASTEROID_THROW;
6584 ADD_DATA( packet_type );
6585 ADD_USHORT( objp->net_signature );
6586 //ADD_DATA( objp->pos );
6587 add_vector_data( data, &packet_size, objp->pos );
6588 //ADD_DATA( objp->phys_info.vel );
6589 add_vector_data( data, &packet_size, objp->phys_info.vel );
6591 multi_io_send_to_all(data, packet_size);
6594 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6597 ubyte data[MAX_PACKET_SIZE], packet_type;
6601 if ( hitpos != NULL )
6604 // build up an asteroid hit packet
6605 BUILD_HEADER( ASTEROID_INFO );
6606 packet_type = ASTEROID_HIT;
6607 ADD_DATA( packet_type );
6608 ADD_USHORT( objp->net_signature );
6610 if(other_objp == NULL){
6611 ushort invalid_sig = 0xffff;
6612 ADD_USHORT(invalid_sig);
6614 ADD_USHORT( other_objp->net_signature );
6617 add_vector_data( data, &packet_size, vec );
6618 ADD_FLOAT( damage );
6620 multi_io_send_to_all(data, packet_size);
6623 void process_asteroid_info( ubyte *data, header *hinfo )
6628 offset = HEADER_LENGTH;
6629 GET_DATA( packet_type );
6631 // based on the packet type, do something interesting with an asteroid!
6632 switch( packet_type ) {
6634 case ASTEROID_CREATE: {
6635 ushort psignature, signature;
6637 vector relvec = ZERO_VECTOR;
6638 object *parent_objp;
6640 GET_USHORT( psignature );
6641 GET_USHORT( signature );
6643 //GET_DATA( relvec );
6644 get_vector_data( data, &offset, relvec );
6646 // after getting the values, set the next network signature, and call the create sub function
6647 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6648 parent_objp = multi_get_network_object( psignature );
6649 if ( parent_objp ) {
6650 asteroid_sub_create( parent_objp, atype, &relvec );
6652 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6659 // asteroid throw packet -- asteroid has wrapped bounds
6660 case ASTEROID_THROW: {
6662 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6665 GET_USHORT( signature );
6667 get_vector_data( data, &offset, pos );
6669 get_vector_data( data, &offset, vel );
6670 objp = multi_get_network_object( signature );
6672 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6676 objp->phys_info.vel = vel;
6677 objp->phys_info.desired_vel = vel;
6681 case ASTEROID_HIT: {
6682 ushort signature, osignature;
6683 object *objp, *other_objp;
6684 vector hitpos = ZERO_VECTOR;
6687 GET_USHORT( signature );
6688 GET_USHORT( osignature );
6689 //GET_DATA( hitpos );
6690 get_vector_data( data, &offset, hitpos );
6691 GET_FLOAT( damage );
6693 objp = multi_get_network_object( signature );
6694 if(osignature == 0xffff){
6697 other_objp = multi_get_network_object( osignature );
6700 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6704 if ( IS_VEC_NULL(&hitpos) ){
6705 asteroid_hit( objp, other_objp, NULL, damage );
6707 asteroid_hit( objp, other_objp, &hitpos, damage );
6710 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6711 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6712 weapon_hit( other_objp, objp, &hitpos );
6725 void send_host_restr_packet(const char *callsign, int code, int mode)
6727 ubyte data[MAX_PACKET_SIZE],val;
6728 int packet_size = 0;
6730 // build the header and add the opcode
6731 BUILD_HEADER(HOST_RESTR_QUERY);
6738 ADD_STRING(callsign);
6740 // if I'm the standalone server, I should be sending this to the game host
6741 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6742 multi_io_send_reliable(Netgame.host, data, packet_size);
6744 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6746 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6747 multi_io_send_reliable(Net_player, data, packet_size);
6751 void process_host_restr_packet(ubyte *data, header *hinfo)
6755 int offset = HEADER_LENGTH;
6757 // get the opcode and the callsign
6760 GET_STRING(callsign);
6763 // do code specific operations
6765 // query to the host from standalone
6767 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6769 // set the join mode
6770 Multi_join_restr_mode = mode;
6772 // set the timestamp
6773 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6775 // notify the host of the event
6776 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6777 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6780 // affirmative reply from the host to the standalone
6782 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6784 // let the player join if the timestamp has not already elapsed on the server
6785 if(Multi_restr_query_timestamp != -1){
6786 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6792 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6793 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6794 Multi_restr_query_timestamp = -1;
6799 void send_netgame_end_error_packet(int notify_code,int err_code)
6803 int packet_size = 0;
6805 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6806 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6808 // build the header and add the notification and error codes
6809 BUILD_HEADER(NETGAME_END_ERROR);
6810 code = (char)notify_code;
6812 code = (char)err_code;
6816 multi_io_send_to_all_reliable(data, packet_size);
6819 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6821 int offset = HEADER_LENGTH;
6822 char notify_code,error_code;
6824 // get the error and notification codes
6825 GET_DATA(notify_code);
6826 GET_DATA(error_code);
6830 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6833 // sends info that a countermeasure succeeded.
6834 void send_countermeasure_success_packet( int objnum )
6836 int pnum, packet_size;
6837 ubyte data[MAX_PACKET_SIZE];
6839 pnum = multi_find_player_by_object( &Objects[objnum] );
6841 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6845 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6846 multi_io_send(&Net_players[pnum], data, packet_size);
6849 // start the flashing of my hud gauge
6850 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6854 offset = HEADER_LENGTH;
6857 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6858 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6861 #define UPDATE_IS_PAUSED (1<<0)
6862 #define UPDATE_HULL_INFO (1<<1)
6864 void send_client_update_packet(net_player *pl)
6866 ubyte data[MAX_PACKET_SIZE],val;
6867 int packet_size = 0;
6870 BUILD_HEADER(CLIENT_UPDATE);
6874 // add the pause status
6875 if ( Multi_pause_status ) {
6876 val |= UPDATE_IS_PAUSED;
6877 } 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) ) {
6878 val |= UPDATE_HULL_INFO;
6879 SDL_assert( Player_ship ); // I"d better have one of these!!!!
6884 // if paused, add the net address of the guy who paused
6885 if(val & UPDATE_IS_PAUSED){
6886 SDL_assert(Multi_pause_pauser != NULL);
6887 ADD_SHORT(Multi_pause_pauser->player_id);
6890 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6891 if ( val & UPDATE_HULL_INFO ) {
6893 ubyte percent, ns, threats;
6896 ship_subsys *subsysp;
6899 // get the object for the player
6900 SDL_assert( pl->player->objnum != -1 );
6902 objp = &Objects[pl->player->objnum];
6904 SDL_assert ( objp->type == OBJ_SHIP );
6905 shipp = &Ships[objp->instance];
6906 sip = &Ship_info[shipp->ship_info_index];
6908 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6909 // percentage value since that should be close enough
6910 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6914 percent = (ubyte)temp;
6916 ADD_DATA( percent );
6918 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6919 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6920 ADD_DATA( percent );
6923 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6924 // both machines. Added as percent since that number <= 100
6926 // also write out the number of subsystems. We do this because the client might not know
6927 // about the object he is getting data for. (i.e. he killed the object already).
6928 ns = (ubyte)sip->n_subsystems;
6931 // now the subsystems.
6932 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6933 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6934 ADD_DATA( percent );
6937 // compute the threats for this player. Only compute the threats if this player is actually
6938 // playing (i.e. he has a ship)
6939 hud_update_reticle( pl->player );
6940 threats = (ubyte)pl->player->threat_flags;
6941 ADD_DATA( threats );
6943 // add his energy level for guns
6944 ADD_FLOAT(shipp->weapon_energy);
6946 // add his secondary bank ammo
6947 ADD_INT(shipp->weapons.num_secondary_banks);
6948 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6949 ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6954 ADD_INT(pl->sv_last_pl);
6956 // send the packet reliably to the player
6957 multi_io_send(pl, data, packet_size);
6960 void process_client_update_packet(ubyte *data, header *hinfo)
6965 int is_paused, have_hull_info;
6968 float weapon_energy;
6969 int offset = HEADER_LENGTH;
6971 // get the header byte containing useful information
6974 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6975 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6977 // if we are paused, get who paused
6980 player_index = find_player_id(pauser);
6981 if(player_index != -1){
6982 Multi_pause_pauser = &Net_players[player_index];
6984 Multi_pause_pauser = NULL;
6988 // if we have hull information, then read it in.
6989 if ( have_hull_info ) {
6993 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6995 ship_subsys *subsysp;
6999 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
7000 // percentage value since that should be close enough
7001 GET_DATA( hull_percent );
7003 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
7005 shield_percent[i] = ub_tmp;
7008 // get the data for the subsystems
7009 GET_DATA( n_subsystems );
7010 for ( i = 0; i < n_subsystems; i++ ){
7012 subsystem_percent[i] = ub_tmp;
7015 GET_DATA( threats );
7017 // add his energy level for guns
7018 GET_FLOAT(weapon_energy);
7020 // add his secondary bank ammo
7021 GET_INT(ammo_count);
7022 for(i=0; i<ammo_count; i++){
7026 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
7027 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7028 // UDP client update packets. Only read this info if I have a ship.
7029 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
7030 shipp = Player_ship;
7032 sip = &Ship_info[shipp->ship_info_index];
7034 val = hull_percent * sip->initial_hull_strength / 100.0f;
7035 objp->hull_strength = val;
7037 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7038 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7039 objp->shields[i] = val;
7042 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
7043 // then don't read these in.
7044 if ( n_subsystems == sip->n_subsystems ) {
7046 n_subsystems = 0; // reuse this variable
7047 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7050 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7051 subsysp->current_hits = val;
7053 // add the value just generated (it was zero'ed above) into the array of generic system types
7054 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
7055 SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7056 shipp->subsys_info[subsys_type].current_hits += val;
7060 ship_recalc_subsys_strength( shipp );
7062 shipp->weapon_energy = weapon_energy;
7063 for(i=0; i<ammo_count; i++){
7064 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7067 // update my threat flags.
7068 // temporarily commented out until tested.
7069 Net_player->player->threat_flags = threats;
7076 if(Net_player != NULL){
7077 Net_player->cl_last_pl = pl;
7081 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7082 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7084 multi_pause_pause();
7086 multi_pause_unpause();
7091 void send_countdown_packet(int time)
7095 int packet_size = 0;
7097 // build the header and add the time
7098 BUILD_HEADER(COUNTDOWN);
7102 // if we're the server, we should broadcast to everyone
7103 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
7104 multi_io_send_to_all_reliable(data, packet_size);
7106 // otherwise we'de better be a host sending to the standalone
7108 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7109 multi_io_send_reliable(Net_player, data, packet_size);
7113 void process_countdown_packet(ubyte *data, header *hinfo)
7115 int offset = HEADER_LENGTH;
7122 // if we're not in the post sync data screen, ignore it
7123 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7127 // if we're the standalone, this should be a -1 telling us to start the countdown
7128 if(Game_mode & GM_STANDALONE_SERVER){
7129 SDL_assert((int)time == -1);
7131 // start the countdown
7132 multi_sync_start_countdown();
7134 // otherwise if we're clients, just bash the countdown
7136 Multi_sync_countdown = (int)time;
7140 // packets for debriefing information
7141 void send_debrief_info( int stage_count[], int *stages[] )
7143 ubyte data[MAX_PACKET_SIZE];
7144 int packet_size, i, j;
7147 BUILD_HEADER(DEBRIEF_INFO);
7149 // add the data for the teams
7150 for ( i = 0; i < Num_teams; i++ ) {
7153 count = stage_count[i];
7155 for ( j = 0; j < count; j++ ) {
7156 i_tmp = stages[i][j];
7161 multi_io_send_to_all_reliable(data, packet_size);
7164 // process a debrief info packet from the server
7165 void process_debrief_info( ubyte *data, header *hinfo )
7168 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7171 offset = HEADER_LENGTH;
7172 for ( i = 0; i < Num_teams; i++ ) {
7176 stage_counts[i] = count;
7177 stages[i] = active_stages[i];
7178 for ( j = 0; j < count; j++ ) {
7180 active_stages[i][j] = i_tmp;
7185 // now that we have the stage data for the debriefing stages, call debrief function with the
7186 // data so that clients can now see the debriefing stuff. Do it only for my team.
7187 SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7188 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7191 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7192 // sends homing_object and homing_subsystem to all clients.
7193 void send_homing_weapon_info( int weapon_num )
7195 ubyte data[MAX_PACKET_SIZE];
7198 object *homing_object;
7199 ushort homing_signature;
7202 wp = &Weapons[weapon_num];
7204 // be sure that this weapon object is a homing object.
7205 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7208 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7209 // homing signature.
7210 homing_signature = 0;
7211 homing_object = wp->homing_object;
7212 if ( homing_object != NULL ) {
7213 homing_signature = homing_object->net_signature;
7215 // get the subsystem index.
7217 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7220 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7221 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
7222 t_subsys = (char)s_index;
7226 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7227 ADD_USHORT( Objects[wp->objnum].net_signature );
7228 ADD_USHORT( homing_signature );
7229 ADD_DATA( t_subsys );
7231 multi_io_send_to_all(data, packet_size);
7234 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7235 // packet contains information for multiple weapons (like hornets).
7236 void process_homing_weapon_info( ubyte *data, header *hinfo )
7239 ushort weapon_signature, homing_signature;
7241 object *homing_object, *weapon_objp;
7244 offset = HEADER_LENGTH;
7246 // get the data for the packet
7247 GET_USHORT( weapon_signature );
7248 GET_USHORT( homing_signature );
7249 GET_DATA( h_subsys );
7252 // deal with changing this weapons homing information
7253 weapon_objp = multi_get_network_object( weapon_signature );
7254 if ( weapon_objp == NULL ) {
7255 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7258 SDL_assert( weapon_objp->type == OBJ_WEAPON );
7259 wp = &Weapons[weapon_objp->instance];
7261 // be sure that we can find these weapons and
7262 homing_object = multi_get_network_object( homing_signature );
7263 if ( homing_object == NULL ) {
7264 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7268 if ( homing_object->type == OBJ_WEAPON ) {
7269 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7272 wp->homing_object = homing_object;
7273 wp->homing_subsys = NULL;
7274 wp->target_num = OBJ_INDEX(homing_object);
7275 wp->target_sig = homing_object->signature;
7276 if ( h_subsys != -1 ) {
7277 SDL_assert( homing_object->type == OBJ_SHIP );
7278 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7281 if ( homing_object->type == OBJ_SHIP ) {
7282 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7286 void send_emp_effect(ushort net_sig, float intensity, float time)
7291 SDL_assert(MULTIPLAYER_MASTER);
7293 // build the packet and add the opcode
7294 BUILD_HEADER(EMP_EFFECT);
7295 ADD_USHORT(net_sig);
7296 ADD_FLOAT(intensity);
7299 // send it to the player
7300 multi_io_send_to_all(data, packet_size);
7303 void process_emp_effect(ubyte *data, header *hinfo)
7305 float intensity, time;
7308 int offset = HEADER_LENGTH;
7310 // read in the EMP effect data
7311 GET_USHORT(net_sig);
7312 GET_FLOAT(intensity);
7316 // try and find the object
7317 objp = multi_get_network_object(net_sig);
7318 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7319 // if i'm not an observer and I have a valid ship, play the EMP effect
7320 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7321 emp_start_local(intensity, time);
7324 // start the effect for the ship itself
7325 emp_start_ship(objp, intensity, time);
7329 // tells whether or not reinforcements are available
7330 void send_reinforcement_avail( int rnum )
7335 BUILD_HEADER(REINFORCEMENT_AVAIL);
7337 multi_io_send_to_all_reliable(data, packet_size);
7340 void process_reinforcement_avail( ubyte *data, header *hinfo )
7345 offset = HEADER_LENGTH;
7349 // sanity check for a valid reinforcement number
7350 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7351 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7355 void send_change_iff_packet(ushort net_signature, int new_team)
7357 ubyte data[MAX_PACKET_SIZE];
7358 int packet_size = 0;
7360 if(Net_player == NULL){
7363 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7367 // build the packet and add the data
7368 BUILD_HEADER(CHANGE_IFF);
7369 ADD_USHORT(net_signature);
7372 // send to all players
7373 multi_io_send_to_all_reliable(data, packet_size);
7376 void process_change_iff_packet( ubyte *data, header *hinfo)
7378 int offset = HEADER_LENGTH;
7379 ushort net_signature;
7384 GET_USHORT(net_signature);
7388 // lookup the object
7389 objp = multi_get_network_object(net_signature);
7390 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7391 Ships[objp->instance].team = new_team;
7395 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7397 int packet_size, objnum;
7398 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7401 net_player *ignore = NULL;
7403 // sanity checking for now
7404 SDL_assert ( banks_fired <= 3 );
7406 // get an object pointer for this ship.
7407 objnum = shipp->objnum;
7408 objp = &Objects[objnum];
7410 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7411 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7415 // just in case nothing got fired
7416 if(banks_fired <= 0){
7420 // ubanks_fired = (ubyte)banks_fired;
7421 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7422 // SDL_assert( current_bank <= 3 );
7424 // insert the current primary bank into this byte
7425 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7427 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7428 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7429 // ubanks_fired |= (1<<7);
7432 // determine if its a player ship and don't send to him if we're in "client firing" mode
7433 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7434 if(MULTIPLAYER_MASTER){
7435 np_index = multi_find_player_by_net_signature(objp->net_signature);
7436 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7437 ignore = &Net_players[np_index];
7441 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7442 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7443 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7444 // and server in sync w.r.t. weapon energy for player ship
7445 BUILD_HEADER( PRIMARY_FIRED_NEW );
7446 ADD_USHORT(objp->net_signature);
7447 // ADD_DATA(ubanks_fired);
7449 // if I'm a server, broadcast to all players
7450 if(MULTIPLAYER_MASTER){
7451 multi_io_send_to_all(data, packet_size, ignore);
7454 multi_rate_add(1, "wfi", packet_size);
7456 // otherwise just send to the server
7458 multi_io_send(Net_player, data, packet_size);
7462 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7464 int offset; // linked;
7465 // ubyte banks_fired, current_bank;
7470 // read all packet info
7471 offset = HEADER_LENGTH;
7472 GET_USHORT(shooter_sig);
7473 // GET_DATA(banks_fired);
7476 // find the object this fired packet is operating on
7477 objp = multi_get_network_object( shooter_sig );
7478 if ( objp == NULL ) {
7479 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7482 // if this object is not actually a valid ship, don't do anything
7483 if(objp->type != OBJ_SHIP){
7486 if(objp->instance < 0){
7489 // shipp = &Ships[objp->instance];
7491 // get the link status of the primary banks
7493 // if ( banks_fired & (1<<7) ) {
7495 // banks_fired ^= (1<<7);
7498 // get the current primary bank
7499 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7500 // current_bank &= 0x3;
7501 // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7502 // shipp->weapons.current_primary_bank = current_bank;
7504 // strip off all remaining bits and just keep which banks were actually fired.
7505 // banks_fired &= 0x3;
7507 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7510 // shipp->flags &= ~SF_PRIMARY_LINKED;
7512 // shipp->flags |= SF_PRIMARY_LINKED;
7515 // if we're in client firing mode, ignore ones for myself
7516 if((Player_obj != NULL) && (Player_obj == objp)){
7520 ship_fire_primary( objp, 0, 1 );
7523 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7525 ubyte data[MAX_PACKET_SIZE];
7528 net_player *ignore = NULL;
7530 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7531 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7535 SDL_assert ( cmeasure_count < UCHAR_MAX );
7536 BUILD_HEADER(COUNTERMEASURE_NEW);
7537 ADD_USHORT( objp->net_signature );
7538 ADD_INT( rand_val );
7540 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7542 // determine if its a player ship and don't send to him if we're in "client firing" mode
7543 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7544 if(MULTIPLAYER_MASTER){
7545 np_index = multi_find_player_by_net_signature(objp->net_signature);
7546 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7547 ignore = &Net_players[np_index];
7551 // if I'm the server, send to all players
7552 if(MULTIPLAYER_MASTER){
7553 multi_io_send_to_all(data, packet_size, ignore);
7555 // otherwise send to the server
7557 multi_io_send(Net_player, data, packet_size);
7561 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7568 offset = HEADER_LENGTH;
7569 GET_USHORT( signature );
7570 GET_INT( rand_val );
7573 objp = multi_get_network_object( signature );
7574 if ( objp == NULL ) {
7575 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7578 if(objp->type != OBJ_SHIP){
7582 // if we're in client firing mode, ignore ones for myself
7583 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7584 if((Player_obj != NULL) && (Player_obj == objp)){
7588 // make it so ship can fire right away!
7589 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7590 if ( objp == Player_obj ){
7591 nprintf(("network", "firing countermeasure from my ship\n"));
7593 ship_launch_countermeasure( objp, rand_val );
7596 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7598 ubyte data[MAX_PACKET_SIZE];
7599 int packet_size = 0;
7604 // only the server should ever be doing this
7605 SDL_assert(MULTIPLAYER_MASTER);
7607 // setup outgoing data
7608 SDL_assert(shooter != NULL);
7609 SDL_assert(turret != NULL);
7610 SDL_assert(target != NULL);
7611 SDL_assert(override != NULL);
7612 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7615 u_beam_info = (ubyte)beam_info_index;
7616 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7617 SDL_assert(subsys_index >= 0);
7618 if(subsys_index < 0){
7622 // swap the beam_info override info into little endian byte order
7623 b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7624 b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7625 b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7627 b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7628 b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7629 b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7631 b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7632 b_info.shot_count = override->shot_count;
7634 for (int i = 0; i < b_info.shot_count; i++) {
7635 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7639 BUILD_HEADER(BEAM_FIRED);
7640 ADD_USHORT(shooter->net_signature);
7641 ADD_DATA(subsys_index);
7642 ADD_USHORT(target->net_signature);
7643 ADD_DATA(u_beam_info);
7644 ADD_DATA(b_info); // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7646 // send to all clients
7647 multi_io_send_to_all_reliable(data, packet_size);
7650 void process_beam_fired_packet(ubyte *data, header *hinfo)
7653 ushort shooter_sig, target_sig;
7657 beam_fire_info fire_info;
7659 // only clients should ever get this
7660 SDL_assert(MULTIPLAYER_CLIENT);
7662 // read in packet data
7663 offset = HEADER_LENGTH;
7664 GET_USHORT(shooter_sig);
7665 GET_DATA(subsys_index);
7666 GET_USHORT(target_sig);
7667 GET_DATA(u_beam_info);
7672 // swap the beam_info override info into native byte order
7673 b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7674 b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7675 b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7676 b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7677 b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7678 b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7679 b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7681 for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7682 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7685 // lookup all relevant data
7686 fire_info.beam_info_index = (int)u_beam_info;
7687 fire_info.shooter = NULL;
7688 fire_info.target = NULL;
7689 fire_info.turret = NULL;
7690 fire_info.target_subsys = NULL;
7691 fire_info.beam_info_override = NULL;
7692 fire_info.shooter = multi_get_network_object(shooter_sig);
7693 fire_info.target = multi_get_network_object(target_sig);
7694 fire_info.beam_info_override = &b_info;
7695 fire_info.accuracy = 1.0f;
7696 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)){
7697 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7700 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7701 if(fire_info.turret == NULL){
7702 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7707 beam_fire(&fire_info);
7710 void send_sw_query_packet(ubyte code, char *txt)
7712 ubyte data[MAX_PACKET_SIZE];
7713 int packet_size = 0;
7715 // build the packet and add the code
7716 BUILD_HEADER(SW_STD_QUERY);
7718 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7722 // if I'm the host, send to standalone
7723 if(MULTIPLAYER_HOST){
7724 SDL_assert(!MULTIPLAYER_MASTER);
7725 SDL_assert(code == SW_STD_START);
7726 multi_io_send_reliable(Net_player, data, packet_size);
7728 // otherwise standalone sends back to host
7730 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7731 SDL_assert(code != SW_STD_START);
7732 SDL_assert(Netgame.host != NULL);
7733 if(Netgame.host != NULL){
7734 multi_io_send_reliable(Netgame.host, data, packet_size);
7739 void process_sw_query_packet(ubyte *data, header *hinfo)
7743 void send_event_update_packet(int event)
7745 ubyte data[MAX_PACKET_SIZE];
7746 ushort u_event = (ushort)event;
7747 int packet_size = 0;
7749 // build the header and add the event
7750 BUILD_HEADER(EVENT_UPDATE);
7751 ADD_USHORT(u_event);
7752 ADD_INT(Mission_events[event].flags);
7753 ADD_INT(Mission_events[event].formula);
7754 ADD_INT(Mission_events[event].result);
7755 ADD_INT(Mission_events[event].count);
7757 // send to all players
7758 multi_io_send_to_all_reliable(data, packet_size);
7761 void process_event_update_packet(ubyte *data, header *hinfo)
7763 int offset = HEADER_LENGTH;
7768 GET_USHORT(u_event);
7769 store_flags = Mission_events[u_event].flags;
7770 GET_INT(Mission_events[u_event].flags);
7771 GET_INT(Mission_events[u_event].formula);
7772 GET_INT(Mission_events[u_event].result);
7773 GET_INT(Mission_events[u_event].count);
7776 // went from non directive special to directive special
7777 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7778 mission_event_set_directive_special(u_event);
7780 // if we went directive special to non directive special
7781 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7782 mission_event_unset_directive_special(u_event);
7786 // weapon detonate packet
7787 void send_weapon_detonate_packet(object *objp)
7789 ubyte data[MAX_PACKET_SIZE];
7790 int packet_size = 0;
7793 SDL_assert(MULTIPLAYER_MASTER);
7794 if(!MULTIPLAYER_MASTER){
7797 SDL_assert(objp != NULL);
7802 // build the header and add the data
7803 BUILD_HEADER(WEAPON_DET);
7804 ADD_USHORT(objp->net_signature);
7806 // send to all players
7807 multi_io_send_to_all(data, packet_size);
7810 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7813 int offset = HEADER_LENGTH;
7814 object *objp = NULL;
7816 // get the weapon signature
7817 GET_USHORT(net_sig);
7820 // lookup the weapon
7821 objp = multi_get_network_object(net_sig);
7822 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7823 weapon_detonate(objp);
7827 // flak fired packet
7828 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7831 ushort pnet_signature;
7832 ubyte data[MAX_PACKET_SIZE], cindex;
7838 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7842 // local setup -- be sure we are actually passing a weapon!!!!
7843 objp = &Objects[weapon_objnum];
7844 SDL_assert ( objp->type == OBJ_WEAPON );
7845 pnet_signature = Objects[ship_objnum].net_signature;
7847 SDL_assert( subsys_index < UCHAR_MAX );
7848 cindex = (ubyte)subsys_index;
7850 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7855 // build the fire turret packet.
7856 BUILD_HEADER(FLAK_FIRED);
7857 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7858 ADD_USHORT( pnet_signature );
7860 val = (short)ssp->submodel_info_1.angs.h;
7862 val = (short)ssp->submodel_info_2.angs.p;
7864 ADD_FLOAT( flak_range );
7866 multi_io_send_to_all(data, packet_size);
7868 multi_rate_add(1, "flk", packet_size);
7871 void process_flak_fired_packet(ubyte *data, header *hinfo)
7873 int offset, weapon_objnum, wid;
7874 ushort pnet_signature;
7882 short pitch, heading;
7885 // get the data for the turret fired packet
7886 offset = HEADER_LENGTH;
7887 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7888 GET_USHORT( pnet_signature );
7889 GET_DATA( turret_index );
7890 GET_SHORT( heading );
7892 GET_FLOAT( flak_range );
7893 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7896 objp = multi_get_network_object( pnet_signature );
7897 if ( objp == NULL ) {
7898 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7902 // if this isn't a ship, do nothing
7903 if ( objp->type != OBJ_SHIP ){
7907 // make an orientation matrix from the o_fvec
7908 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7910 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7911 // hack, but should be suitable.
7912 shipp = &Ships[objp->instance];
7913 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7917 wid = ssp->system_info->turret_weapon_type;
7918 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7922 // bash the position and orientation of the turret
7923 ssp->submodel_info_1.angs.h = (float)heading;
7924 ssp->submodel_info_2.angs.p = (float)pitch;
7926 // get the world position of the weapon
7927 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7929 // create the weapon object
7930 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7931 if (weapon_objnum != -1) {
7932 if ( Weapon_info[wid].launch_snd != -1 ) {
7933 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7936 // create a muzzle flash from a flak gun based upon firing position and weapon type
7937 flak_muzzle_flash(&pos, &dir, wid);
7939 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7940 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7944 #define ADD_NORM_VEC(d) do { SDL_assert((packet_size + 3) < MAX_PACKET_SIZE); char vnorm[3] = { (char)(d.x * 127.0f), (char)(d.y * 127.0f), (char)(d.z * 127.0f) }; memcpy(data + packet_size, vnorm, 3); packet_size += 3; } while(0);
7945 #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);
7947 // player pain packet
7948 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7950 ubyte data[MAX_PACKET_SIZE];
7953 int packet_size = 0;
7955 SDL_assert(MULTIPLAYER_MASTER);
7956 if(!MULTIPLAYER_MASTER){
7959 SDL_assert(pl != NULL);
7964 // build the packet and add the code
7965 BUILD_HEADER(NETPLAYER_PAIN);
7966 windex = (ubyte)weapon_info_index;
7968 udamage = (ushort)damage;
7969 ADD_USHORT(udamage);
7970 //ADD_DATA((*force));
7971 add_vector_data( data, &packet_size, *force );
7972 //ADD_DATA((*hitpos));
7973 add_vector_data( data, &packet_size, *hitpos );
7975 // send to the player
7976 multi_io_send(pl, data, packet_size);
7978 multi_rate_add(1, "pai", packet_size);
7981 void process_player_pain_packet(ubyte *data, header *hinfo)
7986 vector force = ZERO_VECTOR;
7987 vector local_hit_pos = ZERO_VECTOR;
7990 // get the data for the pain packet
7991 offset = HEADER_LENGTH;
7993 GET_USHORT(udamage);
7995 get_vector_data( data, &offset, force );
7996 //GET_DATA(local_hit_pos);
7997 get_vector_data( data, &offset, local_hit_pos );
8000 mprintf(("PAIN!\n"));
8002 // get weapon info pointer
8003 //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)); // always true
8004 if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
8007 wip = &Weapon_info[windex];
8009 // play the weapon hit sound
8010 SDL_assert(Player_obj != NULL);
8011 if(Player_obj == NULL){
8014 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
8016 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
8017 ship_hit_pain((float)udamage);
8020 ship_apply_whack(&force, &local_hit_pos, Player_obj);
8024 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8026 ubyte data[MAX_PACKET_SIZE];
8028 int packet_size = 0;
8030 // build the header and add the data
8031 BUILD_HEADER(LIGHTNING_PACKET);
8032 val = (char)bolt_type;
8034 //ADD_DATA((*start));
8035 add_vector_data( data, &packet_size, *start );
8036 //ADD_DATA((*strike));
8037 add_vector_data( data, &packet_size, *strike );
8039 // send to everyone unreliable for now
8040 multi_io_send_to_all(data, packet_size);
8043 void process_lightning_packet(ubyte *data, header *hinfo)
8047 vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8050 offset = HEADER_LENGTH;
8051 GET_DATA(bolt_type);
8053 get_vector_data(data, &offset, start);
8054 // GET_DATA(strike);
8055 get_vector_data(data, &offset, strike);
8064 nebl_bolt(bolt_type, &start, &strike);
8067 void send_bytes_recvd_packet(net_player *pl)
8069 // only clients should ever be doing this
8074 ubyte data[MAX_PACKET_SIZE];
8075 int packet_size = 0;
8076 BUILD_HEADER(BYTES_SENT);
8077 ADD_INT(pl->cl_bytes_recvd);
8079 // send to the server
8080 multi_io_send_reliable(pl, data, packet_size);
8083 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8087 net_player *pl = NULL;
8088 int offset = HEADER_LENGTH;
8094 if(Net_player == NULL){
8097 if(!MULTIPLAYER_MASTER){
8101 // make sure we know what player sent this
8102 pid = find_player_id(hinfo->id);
8103 if((pid < 0) || (pid >= MAX_PLAYERS)){
8106 pl = &Net_players[pid];
8109 pl->cl_bytes_recvd = bytes;
8113 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8116 pl->sv_bytes_sent = 0;
8120 void send_host_captain_change_packet(short player_id, int captain_change)
8122 ubyte data[MAX_PACKET_SIZE];
8123 int packet_size = 0;
8126 BUILD_HEADER(TRANSFER_HOST);
8127 ADD_SHORT(player_id);
8128 ADD_INT(captain_change);
8131 multi_io_send_to_all_reliable(data, packet_size);
8134 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8136 int offset = HEADER_LENGTH;
8137 int idx, found_player, captain_change;
8140 // get the player id
8141 GET_SHORT(player_id);
8142 GET_INT(captain_change);
8148 for(idx=0; idx<MAX_PLAYERS; idx++){
8149 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8150 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8155 // unflag all old players
8156 for(idx=0; idx<MAX_PLAYERS; idx++){
8157 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8162 for(idx=0; idx<MAX_PLAYERS; idx++){
8163 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8164 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8166 // spew to the HUD config
8167 if(Net_players[idx].player != NULL){
8168 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8178 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8183 void send_self_destruct_packet()
8185 ubyte data[MAX_PACKET_SIZE];
8186 int packet_size = 0;
8189 if(Net_player == NULL){
8193 // if i'm the server, I shouldn't be here
8194 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8195 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8199 // only if this is valid
8200 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8205 if((Player_ship == NULL) || (Player_obj == NULL)){
8210 BUILD_HEADER(SELF_DESTRUCT);
8211 ADD_USHORT(Player_obj->net_signature);
8213 // send to the server
8214 multi_io_send_reliable(Net_player, data, packet_size);
8217 void process_self_destruct_packet(ubyte *data, header *hinfo)
8219 int offset = HEADER_LENGTH;
8223 // get the net signature
8224 GET_USHORT(net_sig);
8228 np_index = find_player_id(hinfo->id);
8232 if(MULTI_OBSERVER(Net_players[np_index])){
8235 if(Net_players[np_index].player == NULL){
8238 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8241 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8244 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8247 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8252 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);