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_gui.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 void add_net_addr(ubyte *data, int *size, net_addr addr)
687 int packet_size = *size;
688 net_addr addr_tmp = addr;
690 addr_tmp.type = INTEL_INT(addr.type);
691 addr_tmp.port = INTEL_SHORT(addr.port);
698 void get_net_addr(ubyte *data, int *size, net_addr addr)
704 addr.type = INTEL_INT(addr.type);
705 addr.port = INTEL_SHORT(addr.port);
710 void add_vector_data(ubyte *data, int *size, vector vec)
712 int packet_size = *size;
714 ADD_FLOAT(vec.xyz.x);
715 ADD_FLOAT(vec.xyz.y);
716 ADD_FLOAT(vec.xyz.z);
721 void get_vector_data(ubyte *data, int *size, vector vec)
725 GET_FLOAT(vec.xyz.x);
726 GET_FLOAT(vec.xyz.y);
727 GET_FLOAT(vec.xyz.z);
732 // send the specified data packet to all players
733 void multi_io_send(net_player *pl, ubyte *data, int len)
736 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
740 // don't do it for single player
741 if(!(Game_mode & GM_MULTIPLAYER)){
746 if(MULTIPLAYER_CLIENT){
747 // SDL_assert(pl == Net_player);
748 if(pl != Net_player){
752 // SDL_assert(pl != Net_player);
753 if(pl == Net_player){
758 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
759 if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
760 multi_io_send_force(pl);
761 pl->s_info.unreliable_buffer_size = 0;
764 SDL_assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
766 memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
767 pl->s_info.unreliable_buffer_size += len;
770 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
773 SDL_assert(MULTIPLAYER_MASTER);
775 // need to check for i > 1, hmmm... and connected. I don't know.
776 for (i = 0; i < MAX_PLAYERS; i++ ) {
777 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
781 // maybe ignore a player
782 if((ignore != NULL) && (&Net_players[i] == ignore)){
786 // ingame joiners not waiting to select a ship doesn't get any packets
787 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
792 multi_io_send(&Net_players[i], data, length);
796 void multi_io_send_force(net_player *pl)
799 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
803 // don't do it for single player
804 if(!(Game_mode & GM_MULTIPLAYER)){
808 // send everything in
809 if (MULTIPLAYER_MASTER) {
810 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
812 // add the bytes sent to this player
813 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
815 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
817 pl->s_info.unreliable_buffer_size = 0;
820 // send the data packet to all players via their reliable sockets
821 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
824 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
828 // don't do it for single player
829 if(!(Game_mode & GM_MULTIPLAYER)){
834 if(MULTIPLAYER_CLIENT){
835 // SDL_assert(pl == Net_player);
836 if(pl != Net_player){
840 // SDL_assert(pl != Net_player);
841 if(pl == Net_player){
846 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
847 if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
848 multi_io_send_reliable_force(pl);
849 pl->s_info.reliable_buffer_size = 0;
852 SDL_assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
854 memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
855 pl->s_info.reliable_buffer_size += len;
858 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
861 SDL_assert(MULTIPLAYER_MASTER);
863 // need to check for i > 1, hmmm... and connected. I don't know.
864 for (i = 0; i < MAX_PLAYERS; i++ ) {
865 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
869 // maybe ignore a player
870 if((ignore != NULL) && (&Net_players[i] == ignore)){
874 // ingame joiners not waiting to select a ship doesn't get any packets
875 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
880 multi_io_send_reliable(&Net_players[i], data, length);
884 void multi_io_send_reliable_force(net_player *pl)
887 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
891 // don't do it for single player
892 if(!(Game_mode & GM_MULTIPLAYER)){
896 // send everything in
897 if(MULTIPLAYER_MASTER) {
898 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
899 } else if(Net_player != NULL){
900 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
902 pl->s_info.reliable_buffer_size = 0;
905 // send all buffered packets
906 void multi_io_send_buffered_packets()
910 // don't do it for single player
911 if(!(Game_mode & GM_MULTIPLAYER)){
916 if(MULTIPLAYER_MASTER){
917 for(idx=0; idx<MAX_PLAYERS; idx++){
918 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
919 // force unreliable data
920 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
921 multi_io_send_force(&Net_players[idx]);
922 Net_players[idx].s_info.unreliable_buffer_size = 0;
925 // force reliable data
926 if(Net_players[idx].s_info.reliable_buffer_size > 0){
927 multi_io_send_reliable_force(&Net_players[idx]);
928 Net_players[idx].s_info.reliable_buffer_size = 0;
934 else if(Net_player != NULL){
935 // force unreliable data
936 if(Net_player->s_info.unreliable_buffer_size > 0){
937 multi_io_send_force(Net_player);
938 Net_player->s_info.unreliable_buffer_size = 0;
941 // force reliable data
942 if(Net_player->s_info.reliable_buffer_size > 0){
943 multi_io_send_reliable_force(Net_player);
944 Net_player->s_info.reliable_buffer_size = 0;
949 // send a general game chat packet (if msg_mode == MULTI_MSG_TARGET, need to pass in "to", if == MULTI_MSG_EXPR, need to pass in expr)
950 void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
952 ubyte data[MAX_PACKET_SIZE],mode;
955 BUILD_HEADER(GAME_CHAT);
958 ADD_SHORT(from->player_id);
960 // add the message mode and if in MSG_TARGET mode, add who the target is
962 mode = (ubyte)msg_mode;
965 case MULTI_MSG_TARGET:
966 SDL_assert(to != NULL);
967 ADD_SHORT(to->player_id);
970 SDL_assert(expr != NULL);
974 // add the message itself
977 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
979 // message all players
981 for(idx=0;idx<MAX_PLAYERS;idx++){
982 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
983 multi_io_send_reliable(&Net_players[idx], data, packet_size);
988 // message only friendly players
989 case MULTI_MSG_FRIENDLY:
990 for(idx=0;idx<MAX_PLAYERS;idx++){
991 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team == from->p_info.team)){
992 multi_io_send_reliable(&Net_players[idx], data, packet_size);
997 // message only hostile players
998 case MULTI_MSG_HOSTILE:
999 for(idx=0;idx<MAX_PLAYERS;idx++){
1000 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team != from->p_info.team)){
1001 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1006 // message the player's target
1007 case MULTI_MSG_TARGET:
1008 SDL_assert(to != NULL);
1009 if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
1010 multi_io_send_reliable(to, data, packet_size);
1014 // message all players who match the expression string
1015 case MULTI_MSG_EXPR:
1016 SDL_assert(expr != NULL);
1017 for(idx=0;idx<MAX_PLAYERS;idx++){
1018 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
1019 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1025 // send to the server, who will take care of routing it
1027 multi_io_send_reliable(Net_player, data, packet_size);
1031 // process a general game chat packet, if we're the standalone we should rebroadcast
1032 void process_game_chat_packet( ubyte *data, header *hinfo )
1036 int color_index,player_index,to_player_index,should_display,server_msg;
1037 char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
1041 offset = HEADER_LENGTH;
1043 // get the id of the sender
1046 // determine if this is a server message
1047 GET_INT(server_msg);
1052 // if targeting a specific player, get the address
1055 case MULTI_MSG_TARGET:
1058 case MULTI_MSG_EXPR:
1062 // get the message itself
1066 // get the index of the sending player
1067 color_index = find_player_id(from);
1068 player_index = color_index;
1070 // if we couldn't find the player - bail
1071 if(player_index == -1){
1072 nprintf(("Network","Could not find player for processing game chat packet!\n"));
1078 // if we're the server, determine what to do with the packet here
1079 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1080 // if he's targeting a specific player, find out who it is
1081 if(mode == MULTI_MSG_TARGET){
1082 to_player_index = find_player_id(to);
1084 to_player_index = -1;
1087 // if we couldn't find who sent the message or who should be getting the message, the bail
1088 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
1092 // determine if _I_ should be seeing the text
1093 if(Game_mode & GM_STANDALONE_SERVER){
1096 // check against myself for several specific cases
1098 if((mode == MULTI_MSG_ALL) ||
1099 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
1100 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
1101 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
1102 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
1107 // if we're the server of a game, we need to rebroadcast to all other players
1109 // individual target mission
1110 case MULTI_MSG_TARGET:
1111 // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
1112 if(to_player_index != MY_NET_PLAYER_NUM){
1113 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1117 case MULTI_MSG_EXPR:
1118 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1122 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1126 // if a client receives this packet, its always ok for him to display it
1131 // if we're not on a standalone
1133 if(server_msg == 2){
1136 multi_display_chat_msg(msg, player_index, !server_msg);
1141 // broadcast a hud message to all players
1142 void send_hud_msg_to_all( char* msg )
1144 ubyte data[MAX_PACKET_SIZE];
1147 // only the server should be sending this packet
1148 BUILD_HEADER(HUD_MSG);
1152 multi_io_send_to_all( data, packet_size );
1155 // process an incoming hud message packet
1156 void process_hud_message(ubyte* data, header* hinfo)
1159 char msg_buffer[255];
1161 offset = HEADER_LENGTH;
1163 GET_STRING(msg_buffer);
1166 // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1167 if(Game_mode & GM_IN_MISSION){
1168 HUD_printf(msg_buffer);
1172 // send a join packet request to the specified address (should be a server)
1173 void send_join_packet(net_addr* addr,join_request *jr)
1175 ubyte data[MAX_PACKET_SIZE];
1178 // build the header and add the request
1181 add_join_request(data, &packet_size, jr);
1183 psnet_send(addr, data, packet_size);
1186 // process an incoming join request packet
1187 void process_join_packet(ubyte* data, header* hinfo)
1192 int host_restr_mode;
1193 // int team0_avail,team1_avail;
1194 char join_string[255];
1197 // only the server of the game should ever receive this packet
1198 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1201 offset = HEADER_LENGTH;
1203 // read in the request info
1204 memset(&jr,0,sizeof(join_request));
1207 jr.tracker_id = INTEL_INT(jr.tracker_id);
1211 // fill in the address information of where this came from
1212 fill_net_addr(&addr, hinfo->addr, hinfo->port);
1214 // determine if we should accept this guy, or return a reason we should reject him
1215 // see the DENY_* codes in multi.h
1216 ret_code = multi_eval_join_request(&jr,&addr);
1218 // evaluate the return code
1220 // he should be accepted
1224 // we have to query the host because this is a restricted game
1225 case JOIN_QUERY_RESTRICTED :
1226 if(!(Game_mode & GM_STANDALONE_SERVER)){
1227 // notify the host of the event
1228 snd_play(&Snds[SND_CUE_VOICE]);
1231 // set the query timestamp
1232 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1233 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1235 // determine what mode we're in
1236 // host_restr_mode = -1;
1237 memset(join_string,0,255);
1238 // if(Netgame.type == NG_TYPE_TEAM){
1239 // multi_player_ships_available(&team0_avail,&team1_avail);
1241 // if(team0_avail && team1_avail){
1242 // host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1243 // sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1244 // } else if(team0_avail && !team1_avail){
1245 // host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1246 // sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1247 // } else if(!team0_avail && team1_avail){
1248 // host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1249 // sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1251 // } else if(Netgame.mode == NG_MODE_RESTRICTED){
1252 host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1253 SDL_snprintf(join_string,SDL_arraysize(join_string),XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1255 SDL_assert(host_restr_mode != -1);
1257 // store the request info
1258 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1259 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1260 Multi_join_restr_mode = host_restr_mode;
1262 // if i'm the standalone server, I need to send a query to the host
1263 if(Game_mode & GM_STANDALONE_SERVER){
1264 send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1266 HUD_printf(join_string);
1270 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1274 // he'e being denied for some reason
1276 // send him the reason he is being denied
1277 send_deny_packet(&addr,ret_code);
1281 // process the rest of the request
1282 multi_process_valid_join_request(&jr,&addr);
1285 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1286 void send_new_player_packet(int new_player_num,net_player *target)
1288 ubyte data[MAX_PACKET_SIZE], val;
1289 int packet_size = 0;
1291 BUILD_HEADER( NOTIFY_NEW_PLAYER );
1293 // add the new player's info
1294 ADD_INT(new_player_num);
1295 // ADD_DATA(Net_players[new_player_num].p_info.addr);
1297 add_net_addr(data, &packet_size, Net_players[new_player_num].p_info.addr);
1299 ADD_SHORT(Net_players[new_player_num].player_id);
1300 ADD_INT(Net_players[new_player_num].flags);
1301 ADD_STRING(Net_players[new_player_num].player->callsign);
1302 ADD_STRING(Net_players[new_player_num].player->image_filename);
1303 ADD_STRING(Net_players[new_player_num].player->squad_filename);
1304 ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1306 val = (ubyte)Net_players[new_player_num].p_info.team;
1309 // broadcast the data
1311 multi_io_send_reliable(target, data, packet_size);
1313 multi_io_send_to_all_reliable(data, packet_size);
1317 // process a notification for a new player who has joined the game
1318 void process_new_player_packet(ubyte* data, header* hinfo)
1320 int already_in_game = 0;
1321 int offset, new_player_num,player_num,new_flags;
1323 char new_player_name[CALLSIGN_LEN+2] = "";
1324 char new_player_image[MAX_FILENAME_LEN+1] = "";
1325 char new_player_squad[MAX_FILENAME_LEN+1] = "";
1326 char new_player_pxo_squad[LOGIN_LEN+1] = "";
1327 char notify_string[256];
1331 offset = HEADER_LENGTH;
1333 // get the new players information
1334 GET_INT(new_player_num);
1335 memset(&new_addr, 0, sizeof(net_addr));
1336 get_net_addr(data, &offset, new_addr);
1340 GET_STRING(new_player_name);
1341 GET_STRING(new_player_image);
1342 GET_STRING(new_player_squad);
1343 GET_STRING(new_player_pxo_squad);
1347 player_num = multi_find_open_player_slot();
1348 SDL_assert(player_num != -1);
1350 // note that this new code does not check for duplicate IPs. It merely checks to see if
1351 // the slot referenced by new_player_num is already occupied by a connected player
1352 if(MULTI_CONNECTED(Net_players[new_player_num])){
1356 // if he's not alreayd in the game for one reason or another
1357 if ( !already_in_game ) {
1358 if ( Game_mode & GM_IN_MISSION ){
1359 HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1362 // create the player
1363 if(new_flags & NETINFO_FLAG_OBSERVER){
1364 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1365 Net_players[new_player_num].flags |= new_flags;
1367 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1368 Net_players[new_player_num].flags |= new_flags;
1371 // copy in the filename
1372 if(strlen(new_player_image) > 0){
1373 SDL_strlcpy(Net_players[new_player_num].player->image_filename, new_player_image, MAX_FILENAME_LEN);
1375 SDL_strlcpy(Net_players[new_player_num].player->image_filename, "", MAX_FILENAME_LEN);
1377 // copy his pilot squad filename
1378 Net_players[new_player_num].player->insignia_texture = -1;
1379 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1381 // copy in his pxo squad name
1382 SDL_strlcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad, LOGIN_LEN);
1384 // since we just created the player, set the last_heard_time here.
1385 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1387 Net_players[new_player_num].p_info.team = team;
1389 Net_players[new_player_num].player_id = new_id;
1391 // zero out this players ping
1392 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1394 // add a chat message
1395 if(Net_players[new_player_num].player->callsign != NULL){
1396 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1397 multi_display_chat_msg(notify_string,0,0);
1402 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1404 // let the current ui screen know someone joined
1405 switch(gameseq_get_state()){
1406 case GS_STATE_MULTI_HOST_SETUP :
1407 multi_create_handle_join(&Net_players[new_player_num]);
1409 case GS_STATE_MULTI_CLIENT_SETUP :
1410 multi_jw_handle_join(&Net_players[new_player_num]);
1415 #define PLAYER_DATA_SLOP 100
1417 void send_accept_player_data( net_player *npp, int is_ingame )
1421 ubyte data[MAX_PACKET_SIZE], stop;
1423 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1425 // add in the netplayer data for all players
1427 for (i=0; i<MAX_PLAYERS; i++) {
1428 // skip non connected players
1429 if ( !MULTI_CONNECTED(Net_players[i]) ){
1433 // skip this new player's entry
1434 if ( npp->player_id == Net_players[i].player_id ){
1438 // add the stop byte
1441 // add the player's number
1444 // add the player's address
1445 // ADD_DATA(Net_players[i].p_info.addr);
1446 add_net_addr(data, &packet_size, Net_players[i].p_info.addr);
1449 ADD_SHORT(Net_players[i].player_id);
1452 ADD_STRING(Net_players[i].player->callsign);
1454 // add his image filename
1455 ADD_STRING(Net_players[i].player->image_filename);
1457 // add his squad filename
1458 ADD_STRING(Net_players[i].player->squad_filename);
1460 // add his PXO squad name
1461 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1464 ADD_INT(Net_players[i].flags);
1466 // add his object's net sig
1468 ADD_USHORT( Objects[Net_players[i].player->objnum].net_signature );
1471 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1472 stop = APD_END_PACKET;
1474 multi_io_send_reliable( npp, data, packet_size );
1475 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1481 // add the stop byte
1482 stop = APD_END_DATA;
1484 multi_io_send_reliable(npp, data, packet_size);
1487 // send an accept packet to a client in response to a request to join the game
1488 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1490 int packet_size = 0, i;
1491 ubyte data[MAX_PACKET_SIZE],val;
1492 char notify_string[256];
1495 SDL_assert(new_player_num >= 0);
1497 // setup his "reliable" socket
1498 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1500 // build the packet header
1501 BUILD_HEADER(ACCEPT);
1503 // add the accept code
1506 // add code specific accept data
1507 if (code & ACCEPT_INGAME) {
1508 // the game filename
1509 ADD_STRING(Game_current_mission_filename);
1511 // if he is joining on a specific team, mark it here
1512 if(ingame_join_team != -1){
1515 val = (ubyte)ingame_join_team;
1523 if (code & ACCEPT_OBSERVER) {
1524 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1527 if (code & ACCEPT_HOST) {
1528 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1531 if (code & ACCEPT_CLIENT) {
1532 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1535 // add the current skill level setting on the host
1536 ADD_INT(Game_skill_level);
1538 // add this guys player num
1539 ADD_INT(new_player_num);
1541 // add his player id
1542 ADD_SHORT(Net_players[new_player_num].player_id);
1544 // add netgame type flags
1545 ADD_INT(Netgame.type_flags);
1548 // char buffer[100];
1549 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1552 // actually send the packet
1553 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1555 // if he's not an observer, inform all the other players in the game about him
1556 // inform the other players in the game about this new player
1557 for (i=0; i<MAX_PLAYERS; i++) {
1558 // skip unconnected players as well as this new guy himself
1559 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])) {
1563 // send the new packet
1564 send_new_player_packet(new_player_num,&Net_players[i]);
1567 // add a chat message
1568 if(Net_players[new_player_num].player->callsign != NULL){
1569 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1570 multi_display_chat_msg(notify_string, 0, 0);
1573 // handle any team vs. team details
1574 if (!(code & ACCEPT_OBSERVER)) {
1575 multi_team_handle_join(&Net_players[new_player_num]);
1579 if(Net_players[new_player_num].tracker_player_id >= 0){
1580 ml_printf(NOX("Server accepted %s (tracker id %d) as new client"), Net_players[new_player_num].player->callsign, Net_players[new_player_num].tracker_player_id);
1582 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1587 // process the player data from the server
1588 void process_accept_player_data( ubyte *data, header *hinfo )
1590 int offset, player_num, player_slot_num, new_flags;
1591 char name[CALLSIGN_LEN + 1] = "";
1592 char image_name[MAX_FILENAME_LEN + 1] = "";
1593 char squad_name[MAX_FILENAME_LEN + 1] = "";
1594 char pxo_squad_name[LOGIN_LEN+1] = "";
1598 ushort ig_signature;
1600 offset = HEADER_LENGTH;
1603 while ( stop == APD_NEXT ) {
1604 player_slot_num = multi_find_open_player_slot();
1605 SDL_assert(player_slot_num != -1);
1607 // get the player's number
1608 GET_INT(player_num);
1610 // add the player's address
1611 memset(&addr, 0, sizeof(net_addr));
1612 get_net_addr(data, &offset, addr);
1614 // get the player's id#
1615 GET_SHORT(player_id);
1620 // add his image filename
1621 GET_STRING(image_name);
1623 // get his squad logo filename
1624 GET_STRING(squad_name);
1626 // get his PXO squad name
1627 GET_STRING(pxo_squad_name);
1632 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1633 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1638 // the error handling here is less than stellar. We should probably put up a popup and go
1639 // back to the main menu. But then again, this should never ever happen!
1640 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1645 // copy his image filename
1646 SDL_strlcpy(Net_players[player_num].player->image_filename, image_name, MAX_FILENAME_LEN);
1648 // copy his pilot squad filename
1649 Net_players[player_num].player->insignia_texture = -1;
1650 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1652 // copy his pxo squad name
1653 SDL_strlcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name, LOGIN_LEN);
1655 // set his player id#
1656 Net_players[player_num].player_id = player_id;
1658 // mark him as being connected
1659 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1660 Net_players[player_num].flags |= new_flags;
1662 // set the server pointer
1663 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1664 Netgame.server = &Net_players[player_num];
1665 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1667 // also - always set the server address to be where this data came from, NOT from
1668 // the data in the packet
1669 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->port);
1672 // set the host pointer
1673 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1674 Netgame.host = &Net_players[player_num];
1677 // read in the player's object net signature and store as his objnum for now
1678 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1679 GET_USHORT( ig_signature );
1680 Net_players[player_num].player->objnum = ig_signature;
1683 // get the stop byte
1688 if ( stop == APD_END_DATA ) {
1689 // if joining a game automatically, set the connect address to NULl so we don't try and
1690 // do this next time we enter a game
1691 if (Cmdline_connect_addr != NULL) {
1692 Cmdline_connect_addr = NULL;
1695 // send my stats to the server if I'm not in observer mode
1696 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1697 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1700 // if i'm being accepted as a host, then move into the host setup state
1701 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1702 // set my permission bits
1703 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1704 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1706 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1709 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1710 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1712 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1713 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1714 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1718 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1719 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1722 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1723 // flag myself as being an ingame joiner
1724 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1726 // move myself into the ingame join mission sync state
1727 Multi_sync_mode = MULTI_SYNC_INGAME;
1728 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1731 // update my options on the server
1732 multi_options_update_local();
1734 // if we're in PXO mode, mark it down in our player struct
1735 if(MULTI_IS_TRACKER_GAME){
1736 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1737 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1742 // process an accept packet from the server
1743 extern int Select_default_ship;
1745 void process_accept_packet(ubyte* data, header* hinfo)
1747 int code, my_player_num, offset;
1751 // get the accept code
1752 offset = HEADER_LENGTH;
1756 // read in the accept code specific data
1758 if (code & ACCEPT_INGAME) {
1759 // the game filename
1760 GET_STRING(Game_current_mission_filename);
1761 Select_default_ship = 0;
1763 // determine if I'm being placed on a team
1770 if (code & ACCEPT_OBSERVER) {
1771 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1774 if (code & ACCEPT_HOST) {
1775 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1778 if (code & ACCEPT_CLIENT) {
1779 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1782 // fill in the netgame server address
1783 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->port );
1785 // get the skill level setting
1786 GET_INT(Game_skill_level);
1788 // get my netplayer number
1789 GET_INT(my_player_num);
1792 GET_SHORT(player_id);
1794 // get netgame type flags
1795 GET_INT(Netgame.type_flags);
1797 // setup the Net_players structure for myself first
1798 Net_player = &Net_players[my_player_num];
1799 Net_player->flags = 0;
1800 Net_player->tracker_player_id = Multi_tracker_id;
1801 Net_player->player_id = player_id;
1802 Net_player->s_info.xfer_handle = -1;
1803 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1804 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1805 multi_options_local_load(&Net_player->p_info.options, Net_player);
1807 Net_player->p_info.team = team;
1810 // determine if I have a CD
1812 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1815 // set accept code in netplayer for this guy
1816 if ( code & ACCEPT_INGAME ){
1817 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1819 if ( code & ACCEPT_OBSERVER ){
1820 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1822 if ( code & ACCEPT_HOST ){
1823 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1825 if ( code & ACCEPT_CLIENT ){
1826 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1829 // if I have hacked data
1830 if(game_hacked_data()){
1831 Net_player->flags |= NETINFO_FLAG_HAXOR;
1834 // if we're supposed to flush our local data cache, do so now
1835 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1836 multi_flush_multidata_cache();
1839 Net_player->sv_bytes_sent = 0;
1840 Net_player->sv_last_pl = -1;
1841 Net_player->cl_bytes_recvd = 0;
1842 Net_player->cl_last_pl = -1;
1844 // intiialize endgame stuff
1845 multi_endgame_init();
1849 // make a call to psnet to initialize and try to connect with the server.
1850 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1851 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1852 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1856 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1857 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1859 ubyte data[MAX_PACKET_SIZE];
1861 int packet_size = 0;
1863 BUILD_HEADER(LEAVE_GAME);
1865 // add a flag indicating whether he was kicked or not
1866 val = (char)kicked_reason;
1869 if (player_id < 0) {
1870 ADD_SHORT(Net_player->player_id);
1872 // inform the host that we are leaving the game
1873 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1874 multi_io_send_to_all_reliable(data, packet_size);
1876 multi_io_send_reliable(Net_player, data, packet_size);
1879 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1880 // so he has to tell everyone that this guy left
1882 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1884 // a couple of important checks
1885 SDL_assert(player_id != Net_player->player_id);
1886 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1888 // add the id of the guy to be kicked
1889 ADD_SHORT(player_id);
1891 // broadcast to everyone
1892 if (target == NULL) {
1893 multi_io_send_to_all_reliable(data, packet_size);
1895 multi_io_send_reliable(target, data, packet_size);
1900 // process a notification the a player has left the game
1901 void process_leave_game_packet(ubyte* data, header* hinfo)
1909 offset = HEADER_LENGTH;
1911 // get whether he was kicked
1912 GET_DATA(kicked_reason);
1914 // get the address of the guy who is to leave
1915 GET_SHORT(deader_id);
1918 // determine who is dropping and printf out a notification
1919 player_num = find_player_id(deader_id);
1920 if (player_num == -1) {
1921 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1925 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1928 // a hook to display that a player was kicked
1929 if (kicked_reason >= 0){
1930 // if it was me that was kicked, leave the game
1931 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1934 switch(kicked_reason){
1935 case KICK_REASON_BAD_XFER:
1936 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1938 case KICK_REASON_CANT_XFER:
1939 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1941 case KICK_REASON_INGAME_ENDED:
1942 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1945 notify_code = MULTI_END_NOTIFY_KICKED;
1949 multi_quit_game(PROMPT_NONE, notify_code);
1952 // otherwise indicate someone was kicked
1954 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1956 // display the result
1957 memset(str, 0, 512);
1958 multi_kick_get_text(&Net_players[player_num], kicked_reason, str, SDL_arraysize(str));
1959 multi_display_chat_msg(str, player_num, 0);
1963 // first of all, if we're the master, we should be rebroadcasting this packet
1964 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1967 SDL_snprintf(msg, SDL_arraysize(msg), XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1969 if (!(Game_mode & GM_STANDALONE_SERVER)){
1970 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1973 send_hud_msg_to_all(msg);
1974 multi_io_send_to_all_reliable(data, offset);
1977 // leave the game if the host and/or master has dropped
1979 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1980 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1983 ml_string(NOX("Host and/or server has left the game"));
1985 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1986 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1987 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1990 delete_player(player_num);
1993 delete_player(player_num);
1995 // OSAPI GUI stuff (if standalone)
1996 if (Game_mode & GM_STANDALONE_SERVER) {
1997 // returns true if we should reset the standalone
1998 if (std_remove_player(&Net_players[player_num])) {
1999 nprintf(("Network", "Should reset!!\n"));
2003 // update these gui vals
2004 std_connect_set_host_connect_status();
2005 std_connect_set_connect_count();
2009 // send information about this currently active game to the specified address
2010 void send_game_active_packet(net_addr* addr)
2014 ubyte data[MAX_PACKET_SIZE],val;
2016 // build the header and add the data
2017 BUILD_HEADER(GAME_ACTIVE);
2019 // add the server version and compatible version #
2020 val = MULTI_FS_SERVER_VERSION;
2022 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2025 ADD_STRING(Netgame.name);
2026 ADD_STRING(Netgame.mission_name);
2027 ADD_STRING(Netgame.title);
2028 val = (ubyte)multi_num_players();
2031 // add the proper flags
2033 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2034 flags |= AG_FLAG_PASSWD;
2037 // proper netgame type flags
2038 if(Netgame.type_flags & NG_TYPE_TEAM){
2039 flags |= AG_FLAG_TEAMS;
2040 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2041 flags |= AG_FLAG_DOGFIGHT;
2043 flags |= AG_FLAG_COOP;
2046 // proper netgame state flags
2047 switch(Netgame.game_state){
2048 case NETGAME_STATE_FORMING:
2049 flags |= AG_FLAG_FORMING;
2052 case NETGAME_STATE_BRIEFING:
2053 case NETGAME_STATE_MISSION_SYNC:
2054 case NETGAME_STATE_HOST_SETUP:
2055 flags |= AG_FLAG_BRIEFING;
2058 case NETGAME_STATE_IN_MISSION:
2059 flags |= AG_FLAG_IN_MISSION;
2062 case NETGAME_STATE_PAUSED:
2063 flags |= AG_FLAG_PAUSE;
2066 case NETGAME_STATE_ENDGAME:
2067 case NETGAME_STATE_DEBRIEF:
2068 flags |= AG_FLAG_DEBRIEF;
2072 // if this is a standalone
2073 if(Game_mode & GM_STANDALONE_SERVER){
2074 flags |= AG_FLAG_STANDALONE;
2077 // if we're in campaign mode
2078 if(Netgame.campaign_mode == MP_CAMPAIGN){
2079 flags |= AG_FLAG_CAMPAIGN;
2082 // add the data about the connection speed of the host machine
2083 SDL_assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2084 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2089 psnet_send(addr, data, packet_size);
2092 // process information about an active game
2093 void process_game_active_packet(ubyte* data, header* hinfo)
2098 int modes_compatible;
2100 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->port);
2102 // read this game into a temporary structure
2103 offset = HEADER_LENGTH;
2105 // get the server version and compatible version
2106 GET_DATA(ag.version);
2107 GET_DATA(ag.comp_version);
2109 GET_STRING(ag.name);
2110 GET_STRING(ag.mission_name);
2111 GET_STRING(ag.title);
2113 ag.num_players = val;
2114 GET_USHORT(ag.flags);
2118 modes_compatible = 1;
2120 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2121 modes_compatible = 0;
2123 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2124 modes_compatible = 0;
2128 // if this is a compatible version, and our modes are compatible, register it
2129 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2130 multi_update_active_games(&ag);
2134 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2135 // is used to change the current mission, current state, etc.
2136 void send_netgame_update_packet(net_player *pl)
2138 int packet_size = 0;
2140 ubyte data[MAX_PACKET_SIZE];
2142 BUILD_HEADER(GAME_UPDATE);
2144 // with new mission description field, this becomes way to large
2145 // so we must add every element piece by piece except the
2146 ADD_STRING(Netgame.name);
2147 ADD_STRING(Netgame.mission_name);
2148 ADD_STRING(Netgame.title);
2149 ADD_STRING(Netgame.campaign_name);
2150 ADD_INT(Netgame.campaign_mode);
2151 ADD_INT(Netgame.max_players);
2152 ADD_INT(Netgame.security);
2153 ADD_UINT(Netgame.respawn);
2154 ADD_INT(Netgame.flags);
2155 ADD_INT(Netgame.type_flags);
2156 ADD_INT(Netgame.version_info);
2157 ADD_DATA(Netgame.debug_flags);
2159 // only the server should ever send the netgame state (standalone situation)
2160 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2161 ADD_INT(Netgame.game_state);
2164 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2165 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2167 multi_io_send_to_all_reliable(data, packet_size);
2169 for(idx=0; idx<MAX_PLAYERS; idx++){
2170 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2171 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2175 multi_io_send_reliable(pl, data, packet_size);
2176 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2179 SDL_assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2180 multi_io_send_reliable(Net_player, data, packet_size);
2183 // host should always send a netgame options update as well
2184 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2185 multi_options_update_netgame();
2189 // process information about the netgame sent from the server/host
2190 void process_netgame_update_packet( ubyte *data, header *hinfo )
2192 int offset;//,old_flags;
2195 SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
2196 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2198 // read in the netgame information
2199 offset = HEADER_LENGTH;
2200 GET_STRING(Netgame.name);
2201 GET_STRING(Netgame.mission_name);
2202 GET_STRING(Netgame.title);
2203 GET_STRING(Netgame.campaign_name);
2204 GET_INT(Netgame.campaign_mode);
2205 GET_INT(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2206 GET_INT(Netgame.security);
2207 GET_UINT(Netgame.respawn);
2209 // be sure not to blast the quitting flag because of the "one frame extra" problem
2210 // old_flags = Netgame.flags;
2211 GET_INT(Netgame.flags);
2212 GET_INT(Netgame.type_flags);
2213 GET_INT(Netgame.version_info);
2214 GET_DATA(Netgame.debug_flags);
2221 // now compare the passed in game state to our current known state. If it has changed, then maybe
2222 // do something interesting.
2223 // move from the forming or debriefing state to the mission sync state
2224 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2225 // if coming from the forming state
2226 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2227 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2228 // do any special processing for forced state transitions
2229 multi_handle_state_special();
2231 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2232 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2233 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2235 // if coming from the debriefing state
2236 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2237 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2239 // do any special processing for forced state transitions
2240 multi_handle_state_special();
2242 multi_flush_mission_stuff();
2244 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2245 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2246 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2249 // move from mission sync to team select
2250 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2251 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2252 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2254 // do any special processing for forced state transitions
2255 multi_handle_state_special();
2257 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2258 gameseq_post_event(GS_EVENT_START_BRIEFING);
2261 // move from the debriefing to the create game screen
2262 else if ( ng_state == NETGAME_STATE_FORMING ){
2263 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2264 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2265 // do any special processing for forced state transitions
2266 multi_handle_state_special();
2268 multi_flush_mission_stuff();
2270 // move to the proper screen
2271 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2272 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2274 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2279 Netgame.game_state = ng_state;
2282 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2283 void send_netgame_descript_packet(net_addr *addr, int code)
2285 ubyte data[MAX_PACKET_SIZE],val;
2287 int packet_size = 0;
2290 BUILD_HEADER(UPDATE_DESCRIPT);
2296 // add as much of the description as we dare
2297 len = strlen(The_mission.mission_desc);
2298 if(len > MAX_PACKET_SIZE - 10){
2299 len = MAX_PACKET_SIZE - 10;
2301 memcpy(data+packet_size,The_mission.mission_desc,len);
2304 ADD_STRING(The_mission.mission_desc);
2308 SDL_assert(addr != NULL);
2310 psnet_send(addr, data, packet_size);
2314 // process an incoming netgame description packet
2315 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2319 char mission_desc[MISSION_DESC_LENGTH+2];
2322 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2324 // read this game into a temporary structure
2325 offset = HEADER_LENGTH;
2328 // if this is a request for mission description
2330 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2335 // send an update to this guy
2336 send_netgame_descript_packet(&addr, 1);
2338 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2339 GET_STRING(mission_desc);
2341 // only display if we're in the proper state
2342 state = gameseq_get_state();
2344 case GS_STATE_MULTI_JOIN_GAME:
2345 case GS_STATE_MULTI_CLIENT_SETUP:
2346 case GS_STATE_MULTI_HOST_SETUP:
2347 multi_common_set_text(mission_desc);
2355 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2356 void broadcast_game_query()
2360 server_item *s_moveup;
2361 ubyte data[MAX_PACKET_SIZE];
2363 BUILD_HEADER(GAME_QUERY);
2365 // go through the server list and query each of those as well
2366 s_moveup = Game_server_head;
2367 if(s_moveup != NULL){
2369 send_server_query(&s_moveup->server_addr);
2370 s_moveup = s_moveup->next;
2371 } while(s_moveup != Game_server_head);
2374 fill_net_addr(&addr, Psnet_my_addr.addr, DEFAULT_GAME_PORT);
2376 // send out a broadcast if our options allow us
2377 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2378 psnet_broadcast( &addr, data, packet_size);
2382 // send an individual query to an address to see if there is an active game
2383 void send_server_query(net_addr *addr)
2386 ubyte data[MAX_PACKET_SIZE];
2388 // build the header and send the data
2389 BUILD_HEADER(GAME_QUERY);
2390 psnet_send(addr, data, packet_size);
2393 // process a query from a client looking for active freespace games
2394 void process_game_query(ubyte* data, header* hinfo)
2399 offset = HEADER_LENGTH;
2403 // check to be sure that we don't capture our own broadcast message
2404 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2405 if ( psnet_same( &addr, &Psnet_my_addr) ){
2409 // if I am not a server of a game, don't send a reply!!!
2410 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2414 // if the game options are being selected, then ignore the request
2415 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2416 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2420 // send information about this active game
2421 send_game_active_packet(&addr);
2424 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2425 void send_netplayer_update_packet( net_player *pl )
2427 int packet_size,idx;
2428 ubyte data[MAX_PACKET_SIZE],val;
2430 BUILD_HEADER(NETPLAYER_UPDATE);
2432 // if I'm the server of the game, I should send an update for _all_players in the game
2433 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2434 for(idx=0;idx<MAX_PLAYERS;idx++){
2435 // only send info for connected players
2436 if(MULTI_CONNECTED(Net_players[idx])){
2441 // add the net player's information
2442 ADD_SHORT(Net_players[idx].player_id);
2443 ADD_INT(Net_players[idx].state);
2444 ADD_INT(Net_players[idx].p_info.ship_class);
2445 ADD_INT(Net_players[idx].tracker_player_id);
2447 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2455 // add the final stop byte
2459 // broadcast the packet
2460 if(!(Game_mode & GM_IN_MISSION)){
2462 multi_io_send_to_all_reliable(data, packet_size);
2464 multi_io_send_reliable(pl, data, packet_size);
2468 multi_io_send_to_all(data, packet_size);
2470 multi_io_send(pl, data, packet_size);
2478 // add my current state in the netgame to this packet
2479 ADD_SHORT(Net_player->player_id);
2480 ADD_INT(Net_player->state);
2481 ADD_INT(Net_player->p_info.ship_class);
2482 ADD_INT(Multi_tracker_id);
2484 // add if I have a CD or not
2492 // add a final stop byte
2496 // send the packet to the server
2497 SDL_assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2498 if(!(Game_mode & GM_IN_MISSION)){
2499 multi_io_send_reliable(Net_player, data, packet_size);
2501 multi_io_send(Net_player, data, packet_size);
2506 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2507 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2509 int offset, player_num;
2515 offset = HEADER_LENGTH;
2517 // get the first stop byte
2520 while(stop != 0xff){
2521 // look the player up
2522 GET_SHORT(player_id);
2523 player_num = find_player_id(player_id);
2524 // if we couldn't find him, read in the bogus data
2525 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2526 GET_INT(bogus.state);
2527 GET_INT(bogus.p_info.ship_class);
2528 GET_INT(bogus.tracker_player_id);
2532 // otherwise read in the data correctly
2535 GET_INT(Net_players[player_num].p_info.ship_class);
2536 GET_INT(Net_players[player_num].tracker_player_id);
2539 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2541 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2544 // if he's changing state to joined, send a team update
2545 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2546 multi_team_send_update();
2550 Net_players[player_num].state = new_state;
2553 // get the next stop byte
2559 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2560 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2561 send_netplayer_update_packet(NULL);
2564 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2565 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2566 switch(Net_players[player_num].state){
2567 case NETPLAYER_STATE_STD_HOST_SETUP:
2568 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2571 case NETPLAYER_STATE_HOST_SETUP:
2572 // check for race conditions
2573 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2574 Netgame.game_state = NETGAME_STATE_FORMING;
2581 #define EXTRA_DEATH_VAPORIZED (1<<0)
2582 #define EXTRA_DEATH_WASHED (1<<1)
2583 // send a packet indicating a ship has been killed
2584 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2586 int packet_size, model;
2587 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2588 ushort debris_signature;
2592 // only sendable from the master
2593 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2596 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2598 extra_death_info = 0;
2600 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2603 if ( Ships[objp->instance].wash_killed ) {
2604 extra_death_info |= EXTRA_DEATH_WASHED;
2607 // find out the next network signature that will be used for the debris pieces.
2608 model = Ships[objp->instance].modelnum;
2609 pm = model_get(model);
2610 debris_signature = 0;
2611 if ( pm && !vaporized ) {
2612 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2613 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2614 Ships[objp->instance].arrival_distance = debris_signature;
2617 BUILD_HEADER(SHIP_KILL);
2618 ADD_USHORT(objp->net_signature);
2620 // ships which are initially killed get the rest of the data sent. self destructed ships and
2621 if ( other_objp == NULL ) {
2626 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2628 ADD_USHORT( other_objp->net_signature );
2631 ADD_USHORT( debris_signature );
2632 ADD_FLOAT( percent_killed );
2633 sd = (ubyte)self_destruct;
2635 ADD_DATA( extra_death_info );
2637 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2639 if ( objp->flags & OF_PLAYER_SHIP ) {
2643 pnum = multi_find_player_by_object( objp );
2646 ADD_DATA( was_player );
2648 SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2649 temp = (char)Net_players[pnum].player->killer_objtype;
2652 SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2653 temp = (char)Net_players[pnum].player->killer_species;
2656 SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2657 temp = (char)Net_players[pnum].player->killer_weapon_index;
2660 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2662 ADD_DATA( was_player );
2665 ADD_DATA( was_player );
2668 // send the packet reliably!!!
2669 multi_io_send_to_all_reliable(data, packet_size);
2672 // process a packet indicating that a ship has been killed
2673 void process_ship_kill_packet( ubyte *data, header *hinfo )
2676 ushort ship_sig, other_sig, debris_sig;
2677 object *sobjp, *oobjp;
2678 float percent_killed;
2679 ubyte was_player, extra_death_info, sd;
2680 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2682 offset = HEADER_LENGTH;
2683 GET_USHORT(ship_sig);
2685 GET_USHORT( other_sig );
2686 GET_USHORT( debris_sig );
2687 GET_FLOAT( percent_killed );
2689 GET_DATA( extra_death_info );
2690 GET_DATA( was_player );
2693 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2694 if ( was_player != 0 ) {
2695 GET_DATA( killer_objtype );
2696 GET_DATA( killer_species );
2697 GET_DATA( killer_weapon_index );
2698 GET_STRING( killer_name );
2703 sobjp = multi_get_network_object( ship_sig );
2705 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2706 // another message from the server that this happened!
2707 if ( sobjp == NULL ) {
2708 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2712 // set this ship's hull value to 0
2713 sobjp->hull_strength = 0.0f;
2715 // maybe set vaporized
2716 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2717 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2720 // maybe set wash_killed
2721 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2722 Ships[sobjp->instance].wash_killed = 1;
2725 oobjp = multi_get_network_object( other_sig );
2727 if ( was_player != 0 ) {
2730 pnum = multi_find_player_by_object( sobjp );
2732 Net_players[pnum].player->killer_objtype = killer_objtype;
2733 Net_players[pnum].player->killer_species = killer_species;
2734 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2735 SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2739 // check to see if I need to respawn myself
2740 multi_respawn_check(sobjp);
2742 // store the debris signature in the arrival distance which will never get used for player ships
2743 Ships[sobjp->instance].arrival_distance = debris_sig;
2745 // set this bit so that we don't accidentally start switching targets when we die
2746 if(sobjp == Player_obj){
2747 Game_mode |= GM_DEAD_DIED;
2750 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2752 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2753 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2754 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2756 extern void ship_destroyed( int shipnum );
2757 ship_destroyed( sobjp->instance );
2758 sobjp->flags |= OF_SHOULD_BE_DEAD;
2759 obj_delete( OBJ_INDEX(sobjp) );
2763 // send a packet indicating a ship should be created
2764 void send_ship_create_packet( object *objp, int is_support )
2767 ubyte data[MAX_PACKET_SIZE];
2769 // We will pass the ship to create by name.
2770 BUILD_HEADER(SHIP_CREATE);
2771 ADD_USHORT(objp->net_signature);
2772 ADD_INT( is_support );
2774 add_vector_data(data, &packet_size, objp->pos);
2777 // broadcast the packet
2778 multi_io_send_to_all_reliable(data, packet_size);
2781 // process a packet indicating a ship should be created
2782 void process_ship_create_packet( ubyte *data, header *hinfo )
2784 int offset, objnum, is_support;
2787 vector pos = ZERO_VECTOR;
2789 SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2790 offset = HEADER_LENGTH;
2791 GET_USHORT(signature);
2792 GET_INT( is_support );
2794 get_vector_data(data, &offset, pos);
2799 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2800 if ( !is_support ) {
2801 objp = mission_parse_get_arrival_ship( signature );
2802 if ( objp != NULL ) {
2803 parse_create_object(objp);
2805 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2808 SDL_assert( Arriving_support_ship );
2809 if(Arriving_support_ship == NULL){
2812 Arriving_support_ship->pos = pos;
2813 Arriving_support_ship->net_signature = signature;
2814 objnum = parse_create_object( Arriving_support_ship );
2815 SDL_assert( objnum != -1 );
2817 mission_parse_support_arrived( objnum );
2822 // send a packet indicating a wing of ships should be created
2823 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2825 int packet_size, index, ship_instance;
2826 ubyte data[MAX_PACKET_SIZE];
2830 // for creating wing -- we just send the index into the wing array of this wing.
2831 // all players load the same mission, and so their array's should all match. We also
2832 // need to send the signature of the first ship that was created. We can find this by
2833 // looking num_to_create places back in the ship_index field in the wing structure.
2835 index = WING_INDEX(wingp);
2836 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2837 signature = Objects[Ships[ship_instance].objnum].net_signature;
2839 BUILD_HEADER( WING_CREATE );
2841 ADD_INT(num_to_create);
2842 ADD_USHORT(signature);
2843 ADD_INT(pre_create_count);
2844 val = wingp->current_wave - 1;
2847 multi_io_send_to_all_reliable(data, packet_size);
2850 // process a packet saying that a wing should be created
2851 void process_wing_create_packet( ubyte *data, header *hinfo )
2853 int offset, index, num_to_create;
2855 int total_arrived_count, current_wave;
2857 offset = HEADER_LENGTH;
2859 GET_INT(num_to_create);
2860 GET_USHORT(signature);
2861 GET_INT(total_arrived_count);
2862 GET_INT(current_wave);
2866 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2867 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2868 nprintf(("Network", "invalid index %d for wing create packet\n"));
2871 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2872 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2877 Wings[index].current_count = 0;
2878 Wings[index].total_arrived_count = total_arrived_count;
2879 Wings[index].current_wave = current_wave;
2881 // set the network signature that was passed. The client should create ships in the same order
2882 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2883 // need to set some timestamps and cues correctly to be sure that these things get created on
2884 // the clients correctly
2885 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2886 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2889 // packet indicating a ship is departing
2890 void send_ship_depart_packet( object *objp )
2892 ubyte data[MAX_PACKET_SIZE];
2896 signature = objp->net_signature;
2898 BUILD_HEADER(SHIP_DEPART);
2899 ADD_USHORT( signature );
2901 multi_io_send_to_all_reliable(data, packet_size);
2904 // process a packet indicating a ship is departing
2905 void process_ship_depart_packet( ubyte *data, header *hinfo )
2911 offset = HEADER_LENGTH;
2912 GET_USHORT( signature );
2915 // find the object which is departing
2916 objp = multi_get_network_object( signature );
2917 if ( objp == NULL ) {
2918 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2922 // start warping him out
2923 shipfx_warpout_start( objp );
2926 // packet to tell clients cargo of a ship was revealed to all
2927 void send_cargo_revealed_packet( ship *shipp )
2929 ubyte data[MAX_PACKET_SIZE];
2932 // build the header and add the data
2933 BUILD_HEADER(CARGO_REVEALED);
2934 ADD_USHORT( Objects[shipp->objnum].net_signature );
2936 // server sends to all players
2937 if(MULTIPLAYER_MASTER){
2938 multi_io_send_to_all_reliable(data, packet_size);
2940 // clients just send to the server
2942 multi_io_send_reliable(Net_player, data, packet_size);
2946 // process a cargo revealed packet
2947 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2953 offset = HEADER_LENGTH;
2954 GET_USHORT(signature);
2957 // get a ship pointer and call the ship function to reveal the cargo
2958 objp = multi_get_network_object( signature );
2959 if ( objp == NULL ) {
2960 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2964 // SDL_assert( objp->type == OBJ_SHIP );
2965 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2969 // this will take care of re-routing to all other clients
2970 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2972 // server should rebroadcast
2973 if(MULTIPLAYER_MASTER){
2974 send_cargo_revealed_packet(&Ships[objp->instance]);
2978 // defines used for secondary fire packet
2979 #define SFPF_ALLOW_SWARM (1<<7)
2980 #define SFPF_DUAL_FIRE (1<<6)
2981 #define SFPF_TARGET_LOCKED (1<<5)
2983 // send a packet indicating a secondary weapon was fired
2984 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2986 int packet_size, net_player_num;
2987 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2989 ushort target_signature;
2993 // SDL_assert ( starting_count < UCHAR_MAX );
2995 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
2996 // we might send the info to the other player different than the one who fired
2997 objp = &Objects[shipp->objnum];
2998 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2999 if ( num_fired == 0 ) {
3004 aip = &Ai_info[shipp->ai_index];
3006 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3007 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3009 // build up the header portion
3010 BUILD_HEADER( SECONDARY_FIRED_AI );
3012 ADD_USHORT( Objects[shipp->objnum].net_signature );
3013 ADD_USHORT( starting_sig );
3015 // add a couple of bits for swarm missiles and dual fire secondary weaspons
3018 sinfo = current_bank;
3021 sinfo |= SFPF_ALLOW_SWARM;
3024 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3025 sinfo |= SFPF_DUAL_FIRE;
3028 if ( aip->current_target_is_locked ){
3029 sinfo |= SFPF_TARGET_LOCKED;
3034 // add the ship's target and any targeted subsystem
3035 target_signature = 0;
3037 if ( aip->target_objnum != -1) {
3038 target_signature = Objects[aip->target_objnum].net_signature;
3039 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3042 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3043 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
3044 t_subsys = (char)s_index;
3047 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3048 SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3053 ADD_USHORT( target_signature );
3054 ADD_DATA( t_subsys );
3056 // just send this packet to everyone, then bail if an AI ship fired.
3057 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3058 multi_io_send_to_all(data, packet_size);
3062 net_player_num = multi_find_player_by_object( objp );
3064 // getting here means a player fired. Send the current packet to all players except the player
3065 // who fired. If nothing got fired, then don't send to the other players -- we will just send
3066 // a packet to the player who will find out that he didn't fire anything
3067 if ( num_fired > 0 ) {
3068 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3071 // if I (the master) fired, then return
3072 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3076 // now build up the packet to send to the player who actually fired.
3077 BUILD_HEADER( SECONDARY_FIRED_PLR );
3078 ADD_USHORT(starting_sig);
3081 // add the targeting information so that the player's weapons will always home on the correct
3083 ADD_USHORT( target_signature );
3084 ADD_DATA( t_subsys );
3086 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3089 /// process a packet indicating a secondary weapon was fired
3090 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3092 int offset, allow_swarm, target_objnum_save;
3093 ushort net_signature, starting_sig, target_signature;
3094 ubyte sinfo, current_bank;
3095 object* objp, *target_objp;
3099 ship_subsys *targeted_subsys_save;
3101 offset = HEADER_LENGTH; // size of the header
3103 // if from_player is false, it means that the secondary weapon info in this packet was
3104 // fired by an ai object (or another player). from_player == 1 means tha me (the person
3105 // receiving this packet) fired the secondary weapon
3106 if ( !from_player ) {
3107 GET_USHORT( net_signature );
3108 GET_USHORT( starting_sig );
3109 GET_DATA( sinfo ); // are we firing swarm missiles
3111 GET_USHORT( target_signature );
3112 GET_DATA( t_subsys );
3116 // find the object (based on network signatures) for the object that fired
3117 objp = multi_get_network_object( net_signature );
3118 if ( objp == NULL ) {
3119 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3123 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3124 // of the next fire time of this bank to 0 so we can fire right away
3125 shipp = &Ships[objp->instance];
3128 GET_USHORT( starting_sig );
3131 GET_USHORT( target_signature );
3132 GET_DATA( t_subsys );
3136 // get the object and ship
3138 shipp = Player_ship;
3141 // check the allow swarm bit
3143 if ( sinfo & SFPF_ALLOW_SWARM ){
3147 // set the dual fire properties of the ship
3148 if ( sinfo & SFPF_DUAL_FIRE ){
3149 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3151 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3154 // determine whether current target is locked
3155 SDL_assert( shipp->ai_index != -1 );
3156 aip = &Ai_info[shipp->ai_index];
3157 if ( sinfo & SFPF_TARGET_LOCKED ) {
3158 aip->current_target_is_locked = 1;
3160 aip->current_target_is_locked = 0;
3163 // find out the current bank
3164 current_bank = (ubyte)(sinfo & 0x3);
3165 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3166 shipp->weapons.current_secondary_bank = current_bank;
3168 // make it so we can fire this ship's secondary bank immediately!!!
3169 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3170 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3172 // set this ship's target and subsystem information. We will save and restore target and
3173 // targeted subsystem so that we do not accidentally change targets for this player or
3174 // any AI ships on his system.
3175 target_objnum_save = aip->target_objnum;
3176 targeted_subsys_save = aip->targeted_subsys;
3178 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3179 aip->target_objnum = -1;
3180 aip->targeted_subsys = NULL;
3182 target_objp = multi_get_network_object( target_signature );
3183 if ( target_objp != NULL ) {
3184 aip->target_objnum = OBJ_INDEX(target_objp);
3186 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3187 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3191 if ( starting_sig != 0 ){
3192 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3194 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3197 ship_fire_secondary( objp, allow_swarm );
3199 // restore targeted object and targeted subsystem
3200 aip->target_objnum = target_objnum_save;
3201 aip->targeted_subsys = targeted_subsys_save;
3204 // send a packet indicating a countermeasure was fired
3205 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3207 ubyte data[MAX_PACKET_SIZE];
3212 SDL_assert ( cmeasure_count < UCHAR_MAX );
3213 BUILD_HEADER(COUNTERMEASURE_FIRED);
3214 ADD_USHORT( objp->net_signature );
3215 ADD_INT( rand_val );
3217 multi_io_send_to_all(data, packet_size);
3220 // process a packet indicating a countermeasure was fired
3221 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3223 int offset, rand_val;
3229 offset = HEADER_LENGTH;
3231 GET_USHORT( signature );
3232 GET_INT( rand_val );
3235 objp = multi_get_network_object( signature );
3236 if ( objp == NULL ) {
3237 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3240 if(objp->type != OBJ_SHIP){
3243 // SDL_assert ( objp->type == OBJ_SHIP );
3245 // make it so ship can fire right away!
3246 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3247 if ( objp == Player_obj ){
3248 nprintf(("network", "firing countermeasure from my ship\n"));
3251 ship_launch_countermeasure( objp, rand_val );
3254 // send a packet indicating that a turret has been fired
3255 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3258 ushort pnet_signature;
3259 ubyte data[MAX_PACKET_SIZE], cindex;
3266 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3270 // local setup -- be sure we are actually passing a weapon!!!!
3271 objp = &Objects[weapon_objnum];
3272 SDL_assert ( objp->type == OBJ_WEAPON );
3273 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3277 pnet_signature = Objects[ship_objnum].net_signature;
3279 SDL_assert( subsys_index < UCHAR_MAX );
3280 cindex = (ubyte)subsys_index;
3282 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3287 // build the fire turret packet.
3288 BUILD_HEADER(FIRE_TURRET_WEAPON);
3289 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3290 ADD_DATA( has_sig );
3291 ADD_USHORT( pnet_signature );
3293 ADD_USHORT( objp->net_signature );
3296 val = (short)ssp->submodel_info_1.angs.h;
3298 val = (short)ssp->submodel_info_2.angs.p;
3301 multi_io_send_to_all(data, packet_size);
3303 multi_rate_add(1, "tur", packet_size);
3306 // process a packet indicating a turret has been fired
3307 void process_turret_fired_packet( ubyte *data, header *hinfo )
3309 int offset, weapon_objnum, wid;
3310 ushort pnet_signature, wnet_signature;
3319 short pitch, heading;
3321 // get the data for the turret fired packet
3322 offset = HEADER_LENGTH;
3323 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3324 GET_DATA( has_sig );
3325 GET_USHORT( pnet_signature );
3327 GET_USHORT( wnet_signature );
3331 GET_DATA( turret_index );
3332 GET_SHORT( heading );
3334 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3337 objp = multi_get_network_object( pnet_signature );
3338 if ( objp == NULL ) {
3339 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3343 // if this isn't a ship, do nothing
3344 if ( objp->type != OBJ_SHIP ){
3348 // make an orientation matrix from the o_fvec
3349 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3351 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3352 // hack, but should be suitable.
3353 shipp = &Ships[objp->instance];
3354 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3358 wid = ssp->system_info->turret_weapon_type;
3360 // bash the position and orientation of the turret
3361 ssp->submodel_info_1.angs.h = (float)heading;
3362 ssp->submodel_info_2.angs.p = (float)pitch;
3364 // get the world position of the weapon
3365 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3367 // create the weapon object
3368 if(wnet_signature != 0){
3369 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3371 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3372 if (weapon_objnum != -1) {
3373 if ( Weapon_info[wid].launch_snd != -1 ) {
3374 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3379 // send a mission log item packet
3380 void send_mission_log_packet( int num )
3383 ubyte data[MAX_PACKET_SIZE];
3388 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3390 // get the data from the log
3391 entry = &log_entries[num];
3392 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3393 sindex = (ushort)entry->index;
3395 BUILD_HEADER(MISSION_LOG_ENTRY);
3397 ADD_INT(entry->flags);
3399 ADD_DATA(entry->timestamp);
3400 ADD_STRING(entry->pname);
3401 ADD_STRING(entry->sname);
3403 // broadcast the packet to all players
3404 multi_io_send_to_all_reliable(data, packet_size);
3407 // process a mission log item packet
3408 void process_mission_log_packet( ubyte *data, header *hinfo )
3413 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3416 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3418 offset = HEADER_LENGTH;
3422 GET_DATA(timestamp);
3428 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3431 // send a mission message packet
3432 void send_mission_message_packet( int id, const char *who_from, int priority, int timing, int source, int builtin_type, int multi_target, int multi_team_filter)
3435 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3437 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3438 SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3439 SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3441 up = (ubyte) priority;
3442 us = (ubyte) source;
3443 utime = (ubyte)timing;
3445 BUILD_HEADER(MISSION_MESSAGE);
3447 ADD_STRING(who_from);
3451 ADD_INT(builtin_type);
3452 ADD_INT(multi_team_filter);
3454 if (multi_target == -1){
3455 multi_io_send_to_all_reliable(data, packet_size);
3457 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3461 // process a mission message packet
3462 void process_mission_message_packet( ubyte *data, header *hinfo )
3464 int offset, id, builtin_type;
3465 ubyte priority, source, utiming;
3466 char who_from[NAME_LENGTH];
3467 int multi_team_filter;
3469 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3471 offset = HEADER_LENGTH;
3473 GET_STRING(who_from);
3477 GET_INT(builtin_type);
3478 GET_INT(multi_team_filter);
3482 // filter out builtin ones in TvT
3483 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3487 // maybe filter this out
3488 if(!message_filter_multi(id)){
3489 // send the message as if it came from an sexpression
3490 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3494 // just send them a pong back as fast as possible
3495 void process_ping_packet(ubyte *data, header *hinfo)
3500 offset = HEADER_LENGTH;
3503 // get the address to return the pong to
3504 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3510 // right now it just routes the pong through to the standalone gui, which is the only
3511 // system which uses ping and pong right now.
3512 void process_pong_packet(ubyte *data, header *hinfo)
3518 offset = HEADER_LENGTH;
3520 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3524 // if we're connected , see who sent us this pong
3525 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3526 lookup = find_player_id(hinfo->id);
3531 p = &Net_players[lookup];
3533 // evaluate the ping
3534 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3536 // put in calls to any functions which may want to know about the ping times from
3538 if(Game_mode & GM_STANDALONE_SERVER){
3539 std_update_player_ping(p);
3543 // mark his socket as still alive (extra precaution)
3544 psnet_mark_received(Net_players[lookup].reliable_socket);
3547 // otherwise, do any special processing
3549 // if we're in the join game state, see if this pong came from a server on our
3551 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3552 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3557 // send a ping packet
3558 void send_ping(net_addr *addr)
3560 unsigned char data[8];
3563 // build the header and send the packet
3564 BUILD_HEADER( PING );
3565 psnet_send(addr, &data[0], packet_size);
3568 // send a pong packet
3569 void send_pong(net_addr *addr)
3571 unsigned char data[8];
3574 // build the header and send the packet
3576 psnet_send(addr, &data[0], packet_size);
3579 // sent from host to master. give me the list of missions you have.
3580 // this will be used only in a standalone mode
3581 void send_mission_list_request( int what )
3583 ubyte data[MAX_PACKET_SIZE];
3586 // build the header and ask for a list of missions or campaigns (depending
3587 // on the 'what' flag).
3588 BUILD_HEADER(MISSION_REQUEST);
3590 multi_io_send_reliable(Net_player, data, packet_size);
3593 // maximum number of bytes that we can send in a mission items packet.
3594 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3596 // defines used to tell what type of packets are being sent
3597 #define MISSION_LIST_ITEMS 1
3598 #define CAMPAIGN_LIST_ITEMS 2
3600 // send an individual mission file item
3601 void send_mission_items( net_player *pl )
3603 ubyte data[MAX_PACKET_SIZE];
3608 BUILD_HEADER(MISSION_ITEM);
3610 // send the list of missions and campaigns avilable on the server. Stop when
3611 // reaching a certain maximum
3612 type = MISSION_LIST_ITEMS;
3614 for (i = 0; i < Multi_create_mission_count; i++ ) {
3618 ADD_STRING( Multi_create_mission_list[i].filename );
3619 ADD_STRING( Multi_create_mission_list[i].name );
3620 ADD_INT( Multi_create_mission_list[i].flags );
3621 ADD_DATA( Multi_create_mission_list[i].max_players );
3622 ADD_UINT( Multi_create_mission_list[i].respawn );
3625 ADD_DATA( Multi_create_mission_list[i].valid_status );
3627 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3630 multi_io_send_reliable(pl, data, packet_size);
3631 BUILD_HEADER( MISSION_ITEM );
3637 multi_io_send_reliable(pl, data, packet_size);
3639 // send the campaign information
3640 type = CAMPAIGN_LIST_ITEMS;
3641 BUILD_HEADER(MISSION_ITEM);
3643 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3647 ADD_STRING( Multi_create_campaign_list[i].filename );
3648 ADD_STRING( Multi_create_campaign_list[i].name );
3649 ADD_INT( Multi_create_campaign_list[i].flags );
3650 ADD_DATA( Multi_create_campaign_list[i].max_players );
3652 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3655 multi_io_send_reliable(pl, data, packet_size);
3656 BUILD_HEADER( MISSION_ITEM );
3662 multi_io_send_reliable(pl, data, packet_size);
3665 // process a request for a list of missions
3666 void process_mission_request_packet(ubyte *data, header *hinfo)
3668 int player_num,offset;
3670 offset = HEADER_LENGTH;
3673 // fill in the address information of where this came from
3674 player_num = find_player_id(hinfo->id);
3675 if(player_num == -1){
3676 nprintf(("Network","Could not find player to send mission list items to!\n"));
3680 send_mission_items( &Net_players[player_num] );
3683 // process an individual mission file item
3684 void process_mission_item_packet(ubyte *data,header *hinfo)
3687 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3688 ubyte stop, type,max_players;
3691 SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3692 offset = HEADER_LENGTH;
3697 GET_STRING( filename );
3700 GET_DATA( max_players );
3702 // missions also have respawns and a crc32 associated with them
3703 if(type == MISSION_LIST_ITEMS){
3707 GET_DATA(valid_status);
3709 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3710 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3711 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3712 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3713 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3714 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3717 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3719 Multi_create_mission_count++;
3721 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3722 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3723 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3724 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3725 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3726 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3727 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3728 Multi_create_campaign_count++;
3737 // this will cause whatever list to get resorted (although they should be appearing in order)
3738 multi_create_setup_list_data(-1);
3741 // send a request to the server to pause or unpause the game
3742 void send_multi_pause_packet(int pause)
3744 ubyte data[MAX_PACKET_SIZE];
3746 int packet_size = 0;
3748 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3751 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3752 val = (ubyte) pause;
3754 // add the pause info
3757 // send the request to the server
3758 multi_io_send_reliable(Net_player, data, packet_size);
3761 // process a pause update packet (pause, unpause, etc)
3762 void process_multi_pause_packet(ubyte *data, header *hinfo)
3768 offset = HEADER_LENGTH;
3774 // get who sent the packet
3775 player_index = find_player_id(hinfo->id);
3776 // if we don't know who sent the packet, don't do anything
3777 if(player_index == -1){
3781 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3782 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3785 // send a game information update
3786 void send_game_info_packet()
3789 ubyte data[MAX_PACKET_SIZE], paused;
3791 // set the paused variable
3792 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3794 BUILD_HEADER(GAME_INFO);
3795 ADD_INT( Missiontime );
3798 multi_io_send_to_all(data, packet_size);
3801 // process a game information update
3802 void process_game_info_packet( ubyte *data, header *hinfo )
3808 offset = HEADER_LENGTH;
3810 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3811 // time, set our time to server time (should take ping time into account!!!)
3812 GET_DATA( mission_time );
3817 // send an ingame nak packet
3818 void send_ingame_nak(int state, net_player *p)
3820 ubyte data[MAX_PACKET_SIZE];
3821 int packet_size = 0;
3823 BUILD_HEADER(INGAME_NAK);
3827 multi_io_send_reliable(p, data, packet_size);
3830 // process an ingame nak packet
3831 void process_ingame_nak(ubyte *data, header *hinfo)
3833 int offset,state,pid;
3835 offset = HEADER_LENGTH;
3839 pid = find_player_id(hinfo->id);
3845 case ACK_FILE_ACCEPTED :
3846 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3847 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3848 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3853 // send a packet telling players to end the mission
3854 void send_endgame_packet(net_player *pl)
3856 ubyte data[MAX_PACKET_SIZE];
3857 int packet_size = 0;
3859 BUILD_HEADER(MISSION_END);
3861 // sending to a specific player?
3863 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3864 multi_io_send_reliable(pl, data, packet_size);
3868 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3869 // send all player stats here
3870 multi_broadcast_stats(STATS_MISSION);
3872 // if in dogfight mode, send all dogfight stats as well
3873 ml_string("Before dogfight stats!");
3874 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3875 ml_string("Sending dogfight stats!");
3877 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3879 ml_string("After dogfight stats!");
3881 // tell everyone to leave the game
3882 multi_io_send_to_all_reliable(data, packet_size);
3884 multi_io_send_reliable(Net_player, data, packet_size);
3888 // process a packet indicating we should end the current mission
3889 void process_endgame_packet(ubyte *data, header *hinfo)
3894 offset = HEADER_LENGTH;
3898 ml_string("Receiving endgame packet");
3900 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3901 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3902 // determine who this came from and make sure he is allowed to end the game
3903 player_num = find_player_id(hinfo->id);
3904 SDL_assert(player_num != -1);
3909 // if the player is allowed to end the mission
3910 if(!multi_can_end_mission(&Net_players[player_num])){
3914 // act as if we hit alt+j locally
3915 multi_handle_end_mission_request();
3917 // all clients process immediately
3919 // ingame joiners should quit when they receive an endgame packet since the game is over
3920 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3921 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3925 // do any special processing for being in a state other than the gameplay state
3926 multi_handle_state_special();
3928 // make sure we're not already in the debrief state
3929 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3930 multi_warpout_all_players();
3935 // send a position/orientation update for myself (if I'm an observer)
3936 void send_observer_update_packet()
3938 ubyte data[MAX_PACKET_SIZE];
3939 int packet_size = 0;
3943 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3944 // to send any update packets to anyone.
3945 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3949 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3953 BUILD_HEADER(OBSERVER_UPDATE);
3955 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3957 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3960 // add targeting infomation
3961 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3962 target_sig = Objects[Player_ai->target_objnum].net_signature;
3966 ADD_USHORT(target_sig);
3968 multi_io_send(Net_player, data, packet_size);
3971 // process a position/orientation update from an observer
3972 void process_observer_update_packet(ubyte *data, header *hinfo)
3978 physics_info bogus_pi;
3981 offset = HEADER_LENGTH;
3983 obs_num = find_player_id(hinfo->id);
3985 memset(&bogus_pi,0,sizeof(physics_info));
3986 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3988 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3991 // targeting information
3992 GET_USHORT(target_sig);
3995 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
3999 // set targeting info
4000 if(target_sig == 0){
4001 Net_players[obs_num].s_info.target_objnum = -1;
4003 target_obj = multi_get_network_object(target_sig);
4004 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4007 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4008 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4009 Net_players[obs_num].s_info.eye_pos = g_vec;
4010 Net_players[obs_num].s_info.eye_orient = g_mat;
4013 void send_netplayer_slot_packet()
4015 ubyte data[MAX_PACKET_SIZE];
4016 int packet_size = 0, idx;
4021 BUILD_HEADER(NETPLAYER_SLOTS_P);
4022 for(idx=0;idx<MAX_PLAYERS;idx++){
4023 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4025 ADD_SHORT(Net_players[idx].player_id);
4026 ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4027 ADD_INT(Net_players[idx].p_info.ship_class);
4028 ADD_INT(Net_players[idx].p_info.ship_index);
4034 // standalone case or not
4035 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
4036 multi_io_send_to_all_reliable(data, packet_size);
4038 multi_io_send_reliable(Net_player, data, packet_size);
4042 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4045 int player_num,ship_class,ship_index;
4051 offset = HEADER_LENGTH;
4053 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4054 multi_untag_player_ships();
4058 GET_SHORT(player_id);
4059 GET_USHORT(net_sig);
4060 GET_INT(ship_class);
4061 GET_INT(ship_index);
4062 player_num = find_player_id(player_id);
4064 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4066 // call the function in multiutil.cpp to set up the player object stuff
4067 // being careful not to muck with the standalone object
4068 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4069 objp = multi_get_network_object(net_sig);
4070 SDL_assert(objp != NULL);
4071 multi_assign_player_ship( player_num, objp, ship_class );
4072 Net_players[player_num].p_info.ship_index = ship_index;
4073 objp->flags &= ~(OF_COULD_BE_PLAYER);
4074 objp->flags |= OF_PLAYER_SHIP;
4081 // standalone should forward the packet and wait for a response
4082 if(Game_mode & GM_STANDALONE_SERVER){
4083 send_netplayer_slot_packet();
4086 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4087 send_netplayer_update_packet();
4090 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4091 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4092 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4093 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4095 ubyte data[MAX_PACKET_SIZE], utmp;
4098 BUILD_HEADER(SHIP_WSTATE_CHANGE);
4099 ADD_USHORT( Objects[shipp->objnum].net_signature );
4100 utmp = (ubyte)(what);
4102 utmp = (ubyte)(new_bank);
4104 utmp = (ubyte)(link_status);
4107 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4108 multi_io_send_to_all_reliable(data, packet_size);
4111 void process_ship_weapon_change( ubyte *data, header *hinfo )
4115 ubyte what, new_bank, link_status;
4119 offset = HEADER_LENGTH;
4120 GET_USHORT( signature );
4122 GET_DATA( new_bank );
4123 GET_DATA( link_status );
4126 objp = multi_get_network_object( signature );
4127 if ( objp == NULL ) {
4128 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4131 // SDL_assert( objp->type == OBJ_SHIP );
4132 if(objp->type != OBJ_SHIP){
4136 // if this is my data, do nothing since I already have my own data
4137 if ( objp == Player_obj ){
4141 // now, get the ship and set the new bank and link modes based on the 'what' value
4142 shipp = &Ships[objp->instance];
4143 if ( what == MULTI_PRIMARY_CHANGED ) {
4144 shipp->weapons.current_primary_bank = new_bank;
4146 shipp->flags |= SF_PRIMARY_LINKED;
4148 shipp->flags &= ~SF_PRIMARY_LINKED;
4151 shipp->weapons.current_secondary_bank = new_bank;
4153 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4155 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4160 // ship status change procedure
4161 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4163 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4164 // for added redundancy.
4165 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4166 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4167 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4168 // back to the client. Also sends multiple times for redundancy
4169 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4170 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4171 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4173 #define SHIP_STATUS_REPEAT 2
4174 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4177 ubyte data[MAX_PACKET_SIZE];
4178 int packet_size = 0;
4184 BUILD_HEADER(SHIP_STATUS_CHANGE);
4186 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4187 temp = bi->status[idx];
4191 // server should send reliably (response packet)
4192 if(MULTIPLAYER_MASTER){
4193 multi_io_send_reliable(pl, data, packet_size);
4195 multi_io_send(pl, data, packet_size);
4199 void process_ship_status_packet(ubyte *data, header *hinfo)
4203 int player_num,unique_id;
4207 offset = HEADER_LENGTH;
4209 // zero out the button info structure for good measure
4210 memset(&bi,0,sizeof(button_info));
4212 // read the button-info
4215 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4217 bi.status[idx] = i_tmp;
4222 // this will be handled differently client and server side. Duh.
4223 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4224 // find which net-player has sent us butotn information
4225 player_num = find_player_id(hinfo->id);
4226 SDL_assert(player_num >= 0);
4231 // don't process critical button information for observers
4232 // its a new button_info for this guy. apply and ack
4233 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4234 // mark that he's pressed this button
4235 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4237 // send a return packet
4238 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4240 // apply the button presses to his ship as normal
4241 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4243 // else ignore it as a repeat from the same guy
4244 } else { // CLIENT SIDE
4245 // this is the return from the server, so we should now apply them locally
4246 // if(lookup_ship_status(Net_player,unique_id,1)){
4247 multi_apply_ship_status(Net_player, &bi, 1);
4252 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4253 // for clients. Left all details to this function instead of higher level messaging
4255 void send_player_order_packet(int type, int index, int cmd)
4257 ubyte data[MAX_PACKET_SIZE];
4259 ushort target_signature;
4261 int packet_size = 0;
4263 BUILD_HEADER(PLAYER_ORDER_PACKET);
4266 ADD_DATA(val); // ship order or wing order, or message all fighters
4268 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4269 if ( val != SQUAD_MSG_ALL ){
4270 ADD_INT(index); // net signature of target ship
4273 ADD_INT(cmd); // the command itself
4276 target_signature = 0;
4277 if ( Player_ai->target_objnum != -1 ){
4278 target_signature = Objects[Player_ai->target_objnum].net_signature;
4281 ADD_USHORT( target_signature );
4284 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4287 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4288 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
4289 t_subsys = (char)s_index;
4293 multi_io_send_reliable(Net_player, data, packet_size);
4296 // brief explanation :
4297 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4298 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4299 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4300 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4301 void process_player_order_packet(ubyte *data, header *hinfo)
4303 int offset, player_num, command, index = 0, tobjnum_save;
4304 ushort target_signature;
4305 char t_subsys, type;
4306 object *objp, *target_objp;
4309 ship_subsys *tsubsys_save, *targeted_subsys;
4311 SDL_assert(MULTIPLAYER_MASTER);
4313 // packet values - its easier to read all of these in first
4315 offset = HEADER_LENGTH;
4318 if ( type != SQUAD_MSG_ALL ){
4323 GET_USHORT( target_signature );
4324 GET_DATA( t_subsys );
4328 player_num = find_player_id(hinfo->id);
4329 if(player_num == -1){
4330 nprintf(("Network","Received player order packet from unknown player\n"));
4334 objp = &Objects[Net_players[player_num].player->objnum];
4335 if ( objp->type != OBJ_SHIP ) {
4336 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4340 // HACK HACK HACK HACK HACK HACK
4341 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4342 // the data is BOGUS. All people should be able to to these things as well.
4343 if(command == REARM_REPAIR_ME_ITEM){
4344 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4346 } else if(command == ABORT_REARM_REPAIR_ITEM){
4347 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4351 // if this player is not allowed to do messaging, quit here
4352 if( !multi_can_message(&Net_players[player_num]) ){
4353 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4357 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4358 // then call them in.
4359 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4360 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4361 hud_squadmsg_call_reinforcement(index, player_num);
4365 // set the player's ai information here
4366 shipp = &Ships[objp->instance];
4367 aip = &Ai_info[shipp->ai_index];
4369 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4370 target_objp = multi_get_network_object( target_signature );
4371 if ( target_objp == NULL ) {
4375 targeted_subsys = NULL;
4376 if ( t_subsys != -1 ) {
4377 SDL_assert( target_objp != NULL );
4378 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4381 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4383 tobjnum_save = aip->target_objnum;
4384 tsubsys_save = aip->targeted_subsys;
4386 if ( target_objp ) {
4387 aip->target_objnum = OBJ_INDEX(target_objp);
4389 aip->target_objnum = -1;
4392 aip->targeted_subsys = targeted_subsys;
4394 if ( type == SQUAD_MSG_SHIP ) {
4395 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4396 } else if ( type == SQUAD_MSG_WING ) {
4397 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4398 } else if ( type == SQUAD_MSG_ALL ) {
4399 hud_squadmsg_send_to_all_fighters( command, player_num );
4402 SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4403 aip->target_objnum = tobjnum_save;
4404 aip->targeted_subsys = tsubsys_save;
4407 // FILE SIGNATURE stuff :
4408 // there are 2 cases for file signature sending which are handled very differently
4409 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4410 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4411 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4412 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4413 // would have to keep track of up to potentially 14 other ack handles (ouch).
4414 void send_file_sig_packet(ushort sum_sig,int length_sig)
4416 ubyte data[MAX_PACKET_SIZE];
4417 int packet_size = 0;
4419 BUILD_HEADER(FILE_SIG_INFO);
4420 ADD_USHORT(sum_sig);
4421 ADD_INT(length_sig);
4423 multi_io_send_reliable(Net_player, data, packet_size);
4426 void process_file_sig_packet(ubyte *data, header *hinfo)
4431 offset = HEADER_LENGTH;
4433 // should only be received on the server-side
4434 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4436 GET_USHORT(sum_sig);
4437 GET_INT(length_sig);
4439 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4442 void send_file_sig_request(char *file_name)
4444 ubyte data[MAX_PACKET_SIZE];
4445 int packet_size = 0;
4447 BUILD_HEADER(FILE_SIG_REQUEST);
4448 ADD_STRING(file_name);
4450 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4452 multi_io_send_to_all_reliable(data, packet_size);
4455 void process_file_sig_request(ubyte *data, header *hinfo)
4457 int offset = HEADER_LENGTH;
4459 // get the mission name
4460 GET_STRING(Netgame.mission_name);
4463 // set the current mission filename
4464 SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4467 multi_get_mission_checksum(Game_current_mission_filename);
4469 if(!multi_endgame_ending()){
4470 // reply to the server
4471 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4475 // functions to deal with subsystems getting whacked
4476 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4478 ubyte data[MAX_PACKET_SIZE];
4481 vector tmp, local_hitpos;
4484 SDL_assert ( index < UCHAR_MAX );
4485 uindex = (ubyte)(index);
4487 objp = &Objects[shipp->objnum];
4489 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4490 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4492 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4493 ADD_USHORT( Objects[shipp->objnum].net_signature );
4495 // ADD_DATA( local_hitpos );
4496 add_vector_data(data, &packet_size, local_hitpos);
4498 multi_io_send_to_all_reliable(data, packet_size);
4501 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4507 vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4509 offset = HEADER_LENGTH;
4511 GET_USHORT( signature );
4513 // GET_DATA( local_hit_pos );
4514 get_vector_data(data, &offset, local_hit_pos);
4516 // get the network object. process it if we find it.
4517 objp = multi_get_network_object( signature );
4518 if ( objp != NULL ) {
4520 ship_subsys *subsysp;
4522 // be sure we have a ship!!!
4523 // SDL_assert ( objp->type == OBJ_SHIP );
4524 if(objp->type != OBJ_SHIP){
4529 shipp = &Ships[objp->instance];
4531 // call to get the pointer to the subsystem we should be working on
4532 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4533 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4534 vm_vec_add2( &world_hit_pos, &objp->pos );
4536 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4537 if ( objp == Player_obj ) {
4538 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4546 // packet to tell clients cargo of a ship was revealed to all
4547 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4549 ubyte data[MAX_PACKET_SIZE], uindex;
4552 SDL_assert ( index < UCHAR_MAX );
4553 uindex = (ubyte)(index);
4555 // build the header and add the data
4556 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4557 ADD_USHORT( Objects[shipp->objnum].net_signature );
4560 // server sends to all players
4561 if(MULTIPLAYER_MASTER){
4562 multi_io_send_to_all_reliable(data, packet_size);
4564 // clients just send to the server
4566 multi_io_send_reliable(Net_player, data, packet_size);
4570 // process a subsystem cargo revealed packet
4571 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4578 ship_subsys *subsysp;
4580 offset = HEADER_LENGTH;
4581 GET_USHORT( signature );
4585 // get a ship pointer and call the ship function to reveal the cargo
4586 objp = multi_get_network_object( signature );
4587 if ( objp == NULL ) {
4588 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4592 // SDL_assert( objp->type == OBJ_SHIP );
4593 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4597 shipp = &Ships[objp->instance];
4599 // call to get the pointer to the subsystem we should be working on
4600 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4601 if (subsysp == NULL) {
4602 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4606 // this will take care of re-routing to all other clients
4607 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4608 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4610 // server should rebroadcast
4611 if(MULTIPLAYER_MASTER){
4612 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4616 void send_netplayer_load_packet(net_player *pl)
4618 ubyte data[MAX_PACKET_SIZE];
4619 int packet_size = 0;
4621 BUILD_HEADER(LOAD_MISSION_NOW);
4622 ADD_STRING(Netgame.mission_name);
4625 multi_io_send_to_all_reliable(data, packet_size);
4627 multi_io_send_reliable(pl, data, packet_size);
4631 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4634 int offset = HEADER_LENGTH;
4639 SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4640 SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4641 if(!Multi_mission_loaded){
4643 // MWA 2/3/98 -- ingame join changes!!!
4644 // everyone can go through the same mission loading path here!!!!
4645 nprintf(("Network","Loading mission..."));
4647 // notify everyone that I'm loading the mission
4648 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4649 send_netplayer_update_packet();
4651 // do the load itself
4652 game_start_mission();
4654 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4655 // code will remark the correct player ships
4656 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4657 multi_untag_player_ships();
4660 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4661 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4662 send_netplayer_update_packet();
4664 Multi_mission_loaded = 1;
4665 nprintf(("Network","Finished loading mission\n"));
4669 void send_jump_into_mission_packet(net_player *pl)
4671 ubyte data[MAX_PACKET_SIZE];
4672 int packet_size = 0;
4674 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4676 BUILD_HEADER(JUMP_INTO_GAME);
4678 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4679 // and possible other things.
4681 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4682 ADD_INT(Netgame.game_state);
4688 multi_io_send_to_all_reliable(data, packet_size);
4690 // send to a specific player
4692 multi_io_send_reliable(pl, data, packet_size);
4696 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4698 int offset = HEADER_LENGTH;
4701 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4702 // the game could be paused, so ingame joiner needs to deal with it.
4703 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4705 Netgame.game_state = state;
4710 // handle any special processing for being in a weird substate
4711 multi_handle_state_special();
4713 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4714 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4715 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4716 multi_ingame_observer_finish();
4718 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4719 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4720 send_netplayer_update_packet();
4723 // start the mission!!
4724 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4725 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4726 gameseq_post_event(GS_EVENT_ENTER_GAME);
4727 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4728 send_netplayer_update_packet();
4732 extern time_t Player_multi_died_check;
4733 Player_multi_died_check = -1;
4735 // recalc all object pairs now
4736 extern void obj_reset_all_collisions();
4737 obj_reset_all_collisions();
4739 // display some cool text
4740 multi_common_add_text(XSTR("Received mission start\n",720),1);
4743 ml_string(NOX("Client received mission start from server - entering mission"));
4748 const char *repair_text[] = {
4750 "REPAIR_INFO_BEGIN",
4752 "REPAIR_INFO_UPDATE",
4753 "REPAIR_INFO_QUEUE",
4754 "REPAIR_INFO_ABORT",
4755 "REPAIR_INFO_BROKEN",
4756 "REPAIR_INFO_WARP_ADD",
4757 "REPAIR_INFO_WARP_REMOVE",
4758 "REPAIR_INFO_ONWAY",
4759 "REPAIR_INFO_KILLED",
4760 "REPAIR_INFO_COMPLETE",
4765 // the following two routines deal with updating and sending information regarding players
4766 // rearming and repairing during the game. The process function calls the routines to deal with
4767 // setting flags and other interesting things.
4768 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4770 int packet_size = 0;
4771 ushort repaired_signature, repair_signature;
4772 ubyte data[MAX_PACKET_SIZE];
4775 // use the network signature of the destination object if there is one, -1 otherwise.
4776 // client will piece it all together
4777 repaired_signature = repaired_objp->net_signature;
4779 // the repair ship may be NULL here since it might have been destroyed
4780 repair_signature = 0;
4782 repair_signature = repair_objp->net_signature;
4785 BUILD_HEADER(CLIENT_REPAIR_INFO);
4788 ADD_USHORT( repaired_signature );
4789 ADD_USHORT( repair_signature );
4791 multi_io_send_to_all_reliable(data, packet_size);
4793 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));
4796 void process_repair_info_packet(ubyte *data, header *hinfo)
4798 int offset = HEADER_LENGTH;
4799 ushort repaired_signature, repair_signature;
4800 object *repaired_objp, *repair_objp;
4804 GET_USHORT( repaired_signature );
4805 GET_USHORT( repair_signature );
4808 repaired_objp = multi_get_network_object( repaired_signature );
4809 repair_objp = multi_get_network_object( repair_signature );
4811 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));
4813 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4817 if ( repaired_objp == NULL ) {
4818 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4822 // the hope is to simply call the routine in the ai code to set/unset flags
4823 // based on the code value and everything else should happen..I hope....
4824 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4826 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4828 // set the dock flags when repair begins. Prevents problem in lagging docking
4829 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4831 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4832 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4833 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4836 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4838 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4839 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4842 if ( code == REPAIR_INFO_WARP_ADD ){
4843 mission_warp_in_support_ship( repaired_objp );
4845 mission_remove_scheduled_repair( repaired_objp );
4850 // sends information updating clients on certain AI information that clients will
4851 // need to know about to keep HUD information up to date. objp is the object that we
4852 // are updating, and what is the type of stuff that we are updating.
4853 void send_ai_info_update_packet( object *objp, char what )
4856 ushort other_signature;
4857 ubyte data[MAX_PACKET_SIZE];
4859 ubyte dock_index, dockee_index;
4861 // SDL_assert( objp->type == OBJ_SHIP );
4862 if(objp->type != OBJ_SHIP){
4865 aip = &Ai_info[Ships[objp->instance].ai_index];
4868 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4871 BUILD_HEADER( AI_INFO_UPDATE );
4872 ADD_USHORT( objp->net_signature );
4875 // depending on the "what" value, we will send different information
4879 case AI_UPDATE_DOCK:
4880 // for docking ships, add the signature of the ship that we are docking with.
4881 SDL_assert( aip->dock_objnum != -1 );
4882 other_signature = Objects[aip->dock_objnum].net_signature;
4883 dock_index = (ubyte)(aip->dock_index);
4884 dockee_index = (ubyte)(aip->dockee_index);
4885 ADD_USHORT( other_signature );
4886 ADD_DATA(dock_index);
4887 ADD_DATA(dockee_index);
4890 case AI_UPDATE_UNDOCK:
4891 // for undocking ships, check the dock_objnum since we might or might not have it
4892 // depending on whether or not a ship was destroyed while we were docked.
4893 other_signature = 0;
4894 if ( aip->dock_objnum != -1 )
4895 other_signature = Objects[aip->dock_objnum].net_signature;
4896 ADD_USHORT( other_signature );
4900 case AI_UPDATE_ORDERS: {
4903 // for orders, we only need to send a little bit of information here. Be sure that the
4904 // first order for this ship is active
4905 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4906 ADD_INT( aip->goals[0].ai_mode );
4907 ADD_INT( aip->goals[0].ai_submode );
4909 if ( aip->goals[0].ship_name != NULL )
4910 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4912 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4913 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4914 if ( shipnum != -1 ) {
4915 SDL_assert( Ships[shipnum].objnum != -1 );
4916 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4918 other_signature = 0;
4920 ADD_USHORT( other_signature );
4922 // for docking, add the dock and dockee index
4923 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4924 SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4925 SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4926 dock_index = (ubyte)aip->goals[0].docker.index;
4927 dockee_index = (ubyte)aip->goals[0].dockee.index;
4928 ADD_DATA( dock_index );
4929 ADD_DATA( dockee_index );
4938 multi_rate_add(1, "aiu", packet_size);
4939 multi_io_send_to_all_reliable(data, packet_size);
4942 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4943 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4944 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4946 int offset = HEADER_LENGTH;
4948 ushort net_signature, other_net_signature;
4949 object *objp, *other_objp;
4952 ubyte dock_index = 0, dockee_index = 0;
4954 GET_USHORT( net_signature ); // signature of the object that we are dealing with.
4955 GET_DATA( code ); // code of what we are doing.
4956 objp = multi_get_network_object( net_signature );
4958 nprintf(("Network", "Couldn't find object for ai update\n"));
4962 case AI_UPDATE_DOCK:
4963 GET_USHORT( other_net_signature );
4964 GET_DATA( dock_index );
4965 GET_DATA( dockee_index );
4966 other_objp = multi_get_network_object( other_net_signature );
4967 if ( !other_objp ) {
4968 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4971 // if we don't have an object to work with, break out of loop
4972 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4976 SDL_assert( other_objp->type == OBJ_SHIP );
4977 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4978 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4980 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4981 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4983 ai_do_objects_docked_stuff( objp, other_objp );
4986 case AI_UPDATE_UNDOCK:
4987 GET_USHORT( other_net_signature );
4988 other_objp = multi_get_network_object( other_net_signature );
4990 // if we don't have an object to work with, break out of loop
4994 ai_do_objects_undocked_stuff( objp, other_objp );
4997 case AI_UPDATE_ORDERS:
5000 GET_USHORT( other_net_signature );
5001 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5002 GET_DATA(dock_index);
5003 GET_DATA(dockee_index);
5006 // be sure that we have a ship object!!!
5007 if ( !objp || (objp->type != OBJ_SHIP) )
5010 // set up the information in the first goal element of the object in question
5011 aip = &Ai_info[Ships[objp->instance].ai_index];
5012 aip->active_goal = 0;
5013 aip->goals[0].ai_mode = mode;
5014 aip->goals[0].ai_submode = submode;
5016 // for docking, add the dock and dockee index
5017 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5018 aip->dock_index = dock_index;
5019 aip->dockee_index = dockee_index;
5022 // get a shipname if we can.
5023 other_objp = multi_get_network_object( other_net_signature );
5024 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5025 // get a pointer to the shipname in question. Use the ship_name value in the
5026 // ship. We are only using this for HUD display, so I think that using this
5027 // method will be fine.
5028 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5030 // special case for destroy subsystem -- get the ai_info pointer to our target ship
5031 // so that we can properly set up what subsystem this ship is attacking.
5032 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5033 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5035 // if docking -- set the dock index and dockee index of this other ship
5036 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5037 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5038 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5045 Int3(); // this Int3() should be temporary
5046 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5052 // tell the standalone to move into the MISSION_SYNC_STATE
5053 void send_mission_sync_packet(int mode,int start_campaign)
5055 ubyte data[MAX_PACKET_SIZE],is_campaign;
5056 int packet_size = 0;
5058 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5060 // build the header and add the sync mode (pre or post briefing)
5061 BUILD_HEADER(MISSION_SYNC_DATA);
5064 // if this is a campaign game
5065 if(mode == MULTI_SYNC_PRE_BRIEFING){
5066 if(Game_mode & GM_CAMPAIGN_MODE){
5067 // add a byte indicating campaign mode
5069 ADD_DATA(is_campaign);
5071 // add a byte indicating if we should be starting a campaign or continuing it
5072 is_campaign = (ubyte)start_campaign;
5073 ADD_DATA(is_campaign);
5075 // add the campaign filename
5076 ADD_STRING(Netgame.campaign_name);
5078 // otherwise if this is a single mission
5080 // add a byte indicating single mission mode
5082 ADD_DATA(is_campaign);
5084 // add the mission filename
5085 ADD_STRING(Game_current_mission_filename);
5088 multi_io_send_reliable(Net_player, data, packet_size);
5091 // move into the MISSION_SYNC state when this is received
5092 // this packet is sent only from a game host to a standalone
5093 void process_mission_sync_packet(ubyte *data, header *hinfo)
5096 ubyte campaign_flag;
5097 int offset = HEADER_LENGTH;
5099 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5101 // if this is a team vs team situation, lock the players send a final team update
5102 if(Netgame.type_flags & NG_TYPE_TEAM){
5103 multi_team_host_lock_all();
5104 multi_team_send_update();
5107 // get the sync mode (pre or post briefing)
5110 if(mode == MULTI_SYNC_PRE_BRIEFING){
5111 // get the flag indicating if this is a single mission or a campaign mode
5112 GET_DATA(campaign_flag);
5114 // get the flag indicating whether we should be starting a new campaign
5115 GET_DATA(campaign_flag);
5117 // get the campaign filename
5118 GET_STRING(Netgame.campaign_name);
5120 // either start a new campaign or continue on to the next mission in the current campaign
5122 multi_campaign_start(Netgame.campaign_name);
5124 multi_campaign_next_mission();
5127 // make sure we remove the campaign mode flag
5128 Game_mode &= ~(GM_CAMPAIGN_MODE);
5130 // get the single mission filename
5131 GET_STRING(Game_current_mission_filename);
5132 SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5137 // set the correct mode and m ove into the state
5138 Multi_sync_mode = mode;
5139 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5142 // tell a player to merge his mission stats into his alltime stats
5143 void send_store_stats_packet(int accept)
5146 int packet_size = 0;
5148 BUILD_HEADER(STORE_MISSION_STATS);
5150 // add whether we're accepting or tossing
5151 val = (ubyte)accept;
5154 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5155 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5156 multi_io_send_to_all_reliable(data, packet_size);
5158 multi_io_send_reliable(Net_player, data, packet_size);
5162 void process_store_stats_packet(ubyte *data, header *hinfo)
5164 int offset = HEADER_LENGTH;
5170 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5171 if(Game_mode & GM_STANDALONE_SERVER){
5172 // rebroadcast the packet to all others in the game
5173 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5174 multi_io_send_to_all_reliable(data, offset);
5177 // all players should mark the stats as being accepted in the debriefing
5178 multi_debrief_stats_accept();
5180 // all players should mark the stats as being "tossed" in the debriefing
5181 multi_debrief_stats_toss();
5186 void send_debris_update_packet(object *objp,int code)
5188 ubyte data[MAX_PACKET_SIZE];
5190 int packet_size = 0;
5192 BUILD_HEADER(DEBRIS_UPDATE);
5193 ADD_USHORT(objp->net_signature);
5197 // add any extra relevant data
5199 case DEBRIS_UPDATE_UPDATE:
5200 // ADD_DATA(objp->pos); // add position
5201 add_vector_data(data, &packet_size, objp->pos);
5202 ADD_ORIENT(objp->orient); // add orientation
5203 // ADD_DATA(objp->phys_info.vel); // add velocity
5204 add_vector_data(data, &packet_size, objp->phys_info.vel);
5205 // ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5206 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5209 multi_io_send_to_all(data, packet_size);
5212 void process_debris_update_packet(ubyte *data, header *hinfo)
5216 object bogus_object;
5218 int offset = HEADER_LENGTH;
5220 GET_USHORT(net_sig);
5224 objp = multi_get_network_object(net_sig);
5226 objp = &bogus_object;
5230 // update the object
5231 case DEBRIS_UPDATE_UPDATE:
5232 //GET_DATA(objp->pos);
5233 get_vector_data( data, &offset, objp->pos );
5235 GET_ORIENT(objp->orient);
5236 GET_DATA(objp->phys_info.vel);
5237 GET_DATA(objp->phys_info.rotvel);
5239 // simply remove it (no explosion)
5240 case DEBRIS_UPDATE_REMOVE:
5241 if(objp != &bogus_object){
5242 SDL_assert(objp->type == OBJ_DEBRIS);
5243 obj_delete(OBJ_INDEX(objp));
5247 case DEBRIS_UPDATE_NUKE:
5248 if(objp != &bogus_object)
5249 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5257 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)
5259 ubyte data[MAX_PACKET_SIZE];
5261 int packet_size = 0;
5263 BUILD_HEADER(WSS_REQUEST_PACKET);
5265 // add the request information
5266 ADD_SHORT(player_id);
5268 ADD_INT(from_index);
5271 ADD_INT(wl_ship_slot); // only used in weapons loadout
5272 ADD_INT(ship_class);
5275 // a standard request
5277 multi_io_send_reliable(Net_player, data, packet_size);
5279 // being routed through the standalone to the host of the game
5281 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5282 multi_io_send_reliable(p, data, packet_size);
5286 void process_wss_request_packet(ubyte *data, header *hinfo)
5288 int offset = HEADER_LENGTH;
5289 int from_slot,from_index;
5290 int to_slot,to_index;
5292 int wl_ship_slot,ship_class;
5296 // determine who this request is from
5297 GET_SHORT(player_id);
5298 player_num = find_player_id(player_id);
5300 // read in the request data
5302 GET_INT(from_index);
5305 GET_INT(wl_ship_slot); // only used in weapons loadout
5306 GET_INT(ship_class); // only used in multi team select
5310 SDL_assert(player_num != -1);
5311 if(player_num == -1){
5315 // if we're the standalone, we have to route this packet to the host of the game
5316 if(Game_mode & GM_STANDALONE_SERVER){
5317 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5319 // otherwise we're the host and should process the request
5322 case WSS_WEAPON_SELECT :
5323 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5325 case WSS_SHIP_SELECT :
5326 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5334 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5336 ubyte data[MAX_PACKET_SIZE],team;
5337 int packet_size = 0;
5339 SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5341 BUILD_HEADER(WSS_UPDATE_PACKET);
5343 // add the team/pool # this is for
5344 team = (ubyte)team_num;
5347 // add the data block size
5350 // add the data itself
5351 memcpy(data + packet_size,wss_data,size);
5352 packet_size += size;
5354 // if we're also the master of the game (not on a standalone)
5355 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5356 multi_io_send_to_all_reliable(data, packet_size);
5358 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5360 multi_io_send_reliable(Net_player, data, packet_size);
5364 void process_wss_update_packet(ubyte *data, header *hinfo)
5367 int size,player_index,idx;
5368 int offset = HEADER_LENGTH;
5370 // get the team/pool #
5373 // get the data size
5376 // if we're the standalone, then we should be routing this data to all the other clients
5377 if(Game_mode & GM_STANDALONE_SERVER){
5382 // determine where this came from
5383 player_index = find_player_id(hinfo->id);
5384 SDL_assert(player_index != -1);
5385 if(player_index < 0){
5389 // route the packet (don't resend it to the host)
5390 for(idx=0;idx<MAX_PLAYERS;idx++){
5391 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5392 multi_io_send_reliable(&Net_players[idx], data, offset);
5396 // set the proper pool pointers
5397 ss_set_team_pointers((int)team);
5399 // read in the block of data, and apply it to the weapons/ship pools
5400 offset += restore_wss_data(data + offset);
5403 // set the pool pointers back to my own team
5404 ss_set_team_pointers(Net_player->p_info.team);
5406 // sync the interface if this was for my own team
5407 if((int)team == Net_player->p_info.team){
5408 multi_ts_sync_interface();
5415 // function to send firing information from the client to the server once they reach
5416 // the final sync screen.
5417 void send_firing_info_packet()
5419 ubyte data[MAX_PACKET_SIZE];
5421 ubyte plinked, sdual;
5423 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5425 BUILD_HEADER(FIRING_INFO);
5426 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5427 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5428 ADD_DATA( plinked );
5431 multi_io_send_reliable(Net_player, data, packet_size);
5434 void process_firing_info_packet( ubyte *data, header *hinfo )
5436 int offset, player_num;
5437 ubyte plinked, sdual;
5440 // only the master of the game should be dealing with these packets
5441 SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5443 offset = HEADER_LENGTH;
5444 GET_DATA( plinked );
5448 player_num = find_player_id(hinfo->id);
5450 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5454 // get the ship pointer for this player and set the flags accordingly.
5455 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5457 shipp->flags |= SF_PRIMARY_LINKED;
5459 shipp->flags &= ~SF_PRIMARY_LINKED;
5462 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5464 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5467 // packet to deal with changing status of mission goals. used to be sent every so often from server
5468 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5469 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5470 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5471 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5473 ubyte data[MAX_PACKET_SIZE];
5476 BUILD_HEADER(MISSION_GOAL_INFO);
5479 ADD_INT(new_status);
5482 multi_io_send_to_all_reliable(data, packet_size);
5485 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5487 int offset, goal_num, new_status, valid;
5489 offset = HEADER_LENGTH;
5491 GET_INT(new_status);
5495 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5496 if ( new_status != -1 ){
5497 mission_goal_status_change( goal_num, new_status );
5499 mission_goal_validation_change( goal_num, valid );
5503 void send_player_settings_packet(net_player *p)
5505 ubyte data[MAX_PACKET_SIZE];
5508 int packet_size = 0;
5511 BUILD_HEADER(PLAYER_SETTINGS);
5513 // add all the data for all the players
5515 for(idx=0;idx<MAX_PLAYERS;idx++){
5516 if(MULTI_CONNECTED(Net_players[idx])){
5518 ADD_SHORT(Net_players[idx].player_id);
5520 // break the p_info structure by member, so we don't overwrite any absolute pointers
5521 // ADD_DATA(Net_players[idx].p_info);
5522 ADD_INT(Net_players[idx].p_info.team);
5523 ADD_INT(Net_players[idx].p_info.ship_index);
5524 ADD_INT(Net_players[idx].p_info.ship_class);
5527 // add the stop byte
5531 // either broadcast the data or send to a specific player
5533 multi_io_send_to_all_reliable(data, packet_size);
5535 multi_io_send_reliable(p, data, packet_size);
5539 void process_player_settings_packet(ubyte *data, header *hinfo)
5541 int offset,player_num;
5542 net_player_info bogus,*ptr;
5546 offset = HEADER_LENGTH;
5548 // read in the data for all the players
5550 while(stop != 0xff){
5551 // lookup the player
5552 GET_SHORT(player_id);
5553 player_num = find_player_id(player_id);
5555 // make sure this is a valid player
5556 if(player_num == -1){
5559 ptr = &Net_players[player_num].p_info;
5563 GET_INT(ptr->ship_index);
5564 GET_INT(ptr->ship_class);
5571 // update the server with my new state
5572 // MWA -- 3/31/98 -- check for in mission instead of state.
5573 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5574 if( !(Game_mode & GM_IN_MISSION) ) {
5575 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5576 send_netplayer_update_packet();
5580 // display some cool text
5581 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5584 void send_deny_packet(net_addr *addr, int code)
5587 int packet_size = 0;
5589 // build the header and add the rejection code
5595 psnet_send(addr, data, packet_size);
5598 void process_deny_packet(ubyte *data, header *hinfo)
5602 // get the denial code
5603 offset = HEADER_LENGTH;
5607 // if there is already a dialog active, do nothing - who cares at this point.
5612 // display the appropriate dialog
5614 case JOIN_DENY_JR_STATE :
5615 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));
5617 case JOIN_DENY_JR_TRACKER_INVAL :
5618 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));
5620 case JOIN_DENY_JR_PASSWD :
5621 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5623 case JOIN_DENY_JR_CLOSED :
5624 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));
5626 case JOIN_DENY_JR_TEMP_CLOSED :
5627 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));
5629 case JOIN_DENY_JR_RANK_HIGH :
5630 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));
5632 case JOIN_DENY_JR_RANK_LOW :
5633 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));
5635 case JOIN_DENY_JR_DUP :
5636 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5638 case JOIN_DENY_JR_FULL :
5639 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5641 case JOIN_DENY_JR_BANNED :
5642 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5644 case JOIN_DENY_JR_NOOBS :
5645 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5647 case JOIN_DENY_JR_INGAME_JOIN :
5648 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));
5650 case JOIN_DENY_JR_BAD_VERSION :
5651 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));
5653 case JOIN_DENY_JR_TYPE :
5654 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5658 // call this so that the join request timestamp automatically expires when we hear back from the server
5659 multi_join_reset_join_stamp();
5662 // this packet will consist of
5663 // 1.) netplayer ship classes (85 bytes max)
5664 // 2.) ship weapon state data (241 bytes max)
5665 // 3.) player settings et. al. (133 bytes max)
5666 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5667 void send_post_sync_data_packet(net_player *p, int std_request)
5669 ubyte data[MAX_PACKET_SIZE], val;
5674 ushort sval, ship_ets;
5675 int idx, player_index;
5676 int packet_size = 0;
5680 BUILD_HEADER(POST_SYNC_DATA);
5682 // some header information for standalone packet routing purposes
5683 val = (ubyte)std_request;
5686 // the standalone has two situations
5687 // 1.) sending a request to the host to distribute this block of data
5688 // 2.) having recevied this block of data from the host, it redistributes it
5689 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5690 // case 1, send the request
5691 multi_io_send_reliable(Netgame.host, data, packet_size);
5694 // case 2 for the standalone is below (as normal)
5696 // otherwise build the data now
5698 // add all deleted ships
5699 val = (ubyte)Multi_ts_num_deleted;
5701 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5702 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5708 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5709 shipp = &Ships[Objects[so->objnum].instance];
5711 // don't process non player wing ships
5712 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5718 // # of ships - used multiple times in the packet
5719 val = (ubyte)ship_count;
5722 // add ship class information (85 bytes max)
5723 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5724 shipp = &Ships[Objects[so->objnum].instance];
5726 // don't process non player wing ships
5727 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5730 // add the net signature of the object for look up
5731 ADD_USHORT( Objects[so->objnum].net_signature );
5733 // add the ship info index
5734 val = (ubyte)(shipp->ship_info_index);
5737 // add the ships's team select index
5738 val = (ubyte)shipp->ts_index;
5742 // add weapon state information for all starting ships (241 bytes max)
5743 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5744 shipp = &Ships[Objects[so->objnum].instance];
5746 // don't process non player wing ships
5747 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5750 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5752 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5753 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5754 if(player_index == -1){
5757 pl = &Net_players[player_index];
5761 // add the net signature and other weapon information
5762 ADD_USHORT( Objects[so->objnum].net_signature );
5764 // add number of primary and secondary banks
5765 bval = (char)(shipp->weapons.num_primary_banks);
5767 bval = (char)(shipp->weapons.num_secondary_banks);
5770 // add weapon bank status
5771 bval = (char)(shipp->weapons.current_primary_bank);
5773 pl->s_info.cur_primary_bank = bval;
5775 // SDL_assert(bval != -1);
5778 bval = (char)(shipp->weapons.current_secondary_bank);
5780 pl->s_info.cur_secondary_bank = bval;
5782 // SDL_assert(bval != -1);
5785 // primary weapon info
5786 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5788 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5791 // secondary weapon info
5792 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5794 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5795 ADD_SHORT(val_short);
5796 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5798 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5799 ADD_SHORT(val_short);
5800 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5802 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5803 ADD_SHORT(val_short);
5805 // send primary and secondary weapon link status
5807 if(shipp->flags & SF_PRIMARY_LINKED){
5809 pl->s_info.cur_link_status |= (1<<0);
5813 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5815 pl->s_info.cur_link_status |= (1<<1);
5819 // if this is a player ship add (1<<2)
5820 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5825 // add a ship ets value
5828 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5830 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5832 ship_ets |= ((ushort)shipp->engine_recharge_index);
5833 ADD_USHORT(ship_ets);
5837 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5838 // or if I'm the server as well as the host, I should be sending this to all players
5839 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5840 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5843 multi_io_send_to_all_reliable(data, packet_size);
5845 // send to a specific player
5847 multi_io_send_reliable(p, data, packet_size);
5850 multi_io_send_reliable(Net_player, data, packet_size);
5857 multi_io_send_to_all_reliable(data, packet_size);
5859 // send to a specific player
5861 multi_io_send_reliable(p, data, packet_size);
5866 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5868 ubyte val, sinfo_index, ts_index;
5870 ushort net_sig, ship_ets, sval;
5874 int offset = HEADER_LENGTH;
5878 // packet routing information
5881 // 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
5882 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5885 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5886 multi_ts_create_wings();
5888 // send to the standalone through my socket
5889 send_post_sync_data_packet(Net_player);
5895 // add all deleted ships
5897 Multi_ts_num_deleted = (int)val;
5898 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5899 // get the ship's objnum
5902 objp = multi_get_network_object(sval);
5904 // delete the ship appropriately
5905 // mark the object as having been deleted
5906 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5909 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5910 obj_delete(Multi_ts_deleted_objnums[idx]);
5911 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5913 Multi_ts_num_deleted--;
5914 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5922 // process ship class information
5923 for(idx=0; idx<ship_count; idx++){
5924 // get the object's net signature
5925 GET_USHORT(net_sig);
5926 GET_DATA(sinfo_index);
5929 // attempt to get the object
5930 objp = multi_get_network_object(net_sig);
5932 // make sure we found a ship
5933 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5935 // set the ship to be the right class
5936 change_ship_type(objp->instance,(int)sinfo_index);
5938 // set the ship's team select index
5939 Ships[objp->instance].ts_index = (int)ts_index;
5942 // process ship weapon state info
5943 for(idx=0; idx<ship_count; idx++){
5944 // get the object's net signature
5945 GET_USHORT(net_sig);
5947 // attempt to get the object
5948 objp = multi_get_network_object(net_sig);
5950 // make sure we found a ship
5951 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5953 // get a pointer to the ship
5954 shipp = &Ships[objp->instance];
5956 // get number of primary and secondary banks;
5958 SDL_assert( b != -1 );
5959 shipp->weapons.num_primary_banks = (int)b;
5962 SDL_assert( b != -1 );
5963 shipp->weapons.num_secondary_banks = (int)b;
5965 // get bank selection info
5970 shipp->weapons.current_primary_bank = (int)b;
5976 shipp->weapons.current_secondary_bank = (int)b;
5978 // primary weapon info
5980 shipp->weapons.primary_bank_weapons[0] = (int)b;
5983 shipp->weapons.primary_bank_weapons[1] = (int)b;
5985 // secondary weapon info
5987 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5988 GET_SHORT(val_short);
5989 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5992 shipp->weapons.secondary_bank_weapons[1] = (int)b;
5993 GET_SHORT(val_short);
5994 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
5997 shipp->weapons.secondary_bank_weapons[2] = (int)b;
5998 GET_SHORT(val_short);
5999 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6006 shipp->flags |= SF_PRIMARY_LINKED;
6009 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
6011 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6012 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6014 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6016 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6020 GET_USHORT(ship_ets);
6022 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6024 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6026 shipp->engine_recharge_index = (ship_ets & 0x000f);
6031 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6032 send_netplayer_update_packet();
6034 // the standalone server will receive this packet from the host of the game, to be applied locally and
6035 // also to be rebroadcast.
6036 if(Game_mode & GM_STANDALONE_SERVER){
6037 // update player ets settings
6038 for(idx=0;idx<MAX_PLAYERS;idx++){
6039 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6040 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6044 send_post_sync_data_packet(NULL,0);
6048 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6050 ubyte data[MAX_PACKET_SIZE],val;
6053 int packet_size = 0;
6056 BUILD_HEADER(WSS_SLOTS_DATA);
6058 // some header information for standalone packet routing purposes
6059 val = (ubyte)std_request;
6063 val = (ubyte)team_num;
6066 // add whether this is the final packet or not
6070 // the standalone has two situations
6071 // 1.) sending a request to the host to distribute this block of data
6072 // 2.) having recevied this block of data from the host, it redistributes it
6073 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6074 // case 1, send the request
6075 multi_io_send_reliable(Netgame.host, data, packet_size);
6078 // case 2 for the standalone is below (as normal)
6080 // add all the slots
6081 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6082 // add the ship class
6083 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6087 for(i = 0;i<MAX_WL_WEAPONS;i++){
6088 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6092 // add the weapon counts
6093 for(i = 0;i<MAX_WL_WEAPONS;i++){
6094 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6095 ADD_SHORT(val_short);
6099 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6100 // or if I'm the server as well as the host, I should be sending this to all players
6101 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6102 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6105 multi_io_send_to_all_reliable(data, packet_size);
6107 // send to a specific player
6109 multi_io_send_reliable(p, data, packet_size);
6112 multi_io_send_reliable(Net_player, data, packet_size);
6119 multi_io_send_to_all_reliable(data, packet_size);
6121 // send to a specific player
6123 multi_io_send_reliable(p, data, packet_size);
6128 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6130 ubyte val,team_num,final;
6132 int offset = HEADER_LENGTH;
6135 // packet routing information
6141 // get whether this is the final packet or not
6144 // 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
6145 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6148 // send to the standalone through my socket
6149 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6153 // read in all the slot data
6154 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6155 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6157 // get the ship class
6159 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6162 for(i = 0;i<MAX_WL_WEAPONS;i++){
6164 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6166 // check for signed/unsigned problems
6167 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6168 Wss_slots_teams[team_num][idx].wep[i] = -1;
6172 // get the weapon counts
6173 for(i = 0;i<MAX_WL_WEAPONS;i++){
6174 GET_SHORT(val_short);
6175 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6180 // update my netplayer state if this is the final packet
6182 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6183 send_netplayer_update_packet();
6186 // the standalone server will receive this packet from the host of the game, to be applied locally and
6187 // also to be rebroadcast.
6188 if(Game_mode & GM_STANDALONE_SERVER){
6189 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6191 // add some mission sync text
6192 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6196 #define OBJ_VISIBILITY_DOT 0.6f
6198 // send and receive packets for shield explosion information
6199 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6202 ubyte data[MAX_PACKET_SIZE], utri_num;
6205 // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6207 SDL_assert( tri_num < UCHAR_MAX );
6208 utri_num = (ubyte)tri_num;
6210 // for each player, determine if this object is behind the player -- if so, don't
6212 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6213 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6215 vector eye_to_obj_vec, diff, eye_pos;
6218 eye_pos = Net_players[i].s_info.eye_pos;
6219 eye_orient = Net_players[i].s_info.eye_orient;
6221 // check for same vectors
6222 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6223 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6227 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6228 dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6230 if ( dot < OBJ_VISIBILITY_DOT ){
6234 BUILD_HEADER(SHIELD_EXPLOSION);
6236 ADD_USHORT( Objects[objnum].net_signature );
6239 multi_io_send(&Net_players[i], data, packet_size);
6244 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6246 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6253 // get the shield hit data
6254 offset = HEADER_LENGTH;
6255 GET_USHORT(signature);
6257 //GET_DATA(hit_pos);
6260 // find the object with this signature. If found, then do a shield explosion
6261 objp = multi_get_network_object( signature );
6264 shield_info *shieldp;
6269 // given the tri num, find the local position which is the average of the
6270 // three vertices of the triangle affected. Use this average point as the hit
6272 // SDL_assert( objp->type == OBJ_SHIP );
6273 if(objp->type != OBJ_SHIP){
6277 pm = model_get(Ships[objp->instance].modelnum);
6278 shieldp = &pm->shield;
6279 SDL_assert( utri_num < shieldp->ntris );
6280 stri = shieldp->tris[utri_num];
6281 vm_vec_zero(&hit_pos);
6282 for ( i = 0; i < 3; i++ ) {
6283 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6285 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6286 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6290 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6293 ubyte data[MAX_PACKET_SIZE], val;
6295 int packet_size = 0;
6300 sc = &pl->player->stats;
6303 BUILD_HEADER(PLAYER_STATS);
6305 // add the player id
6306 ADD_SHORT(pl->player_id);
6308 // add the byte indicating whether these stats are all-time or not
6309 val = (ubyte)stats_code;
6312 // kill information - alltime
6316 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6317 u_tmp = sc->kills[idx];
6320 // medal information
6321 for(idx=0;idx<NUM_MEDALS;idx++){
6322 i_tmp = sc->medals[idx];
6328 ADD_INT(sc->assists);
6329 ADD_INT(sc->kill_count);
6330 ADD_INT(sc->kill_count_ok);
6331 ADD_UINT(sc->p_shots_fired);
6332 ADD_UINT(sc->s_shots_fired);
6333 ADD_UINT(sc->p_shots_hit);
6334 ADD_UINT(sc->s_shots_hit);
6335 ADD_UINT(sc->p_bonehead_hits);
6336 ADD_UINT(sc->s_bonehead_hits);
6337 ADD_INT(sc->bonehead_kills);
6339 ADD_UINT(sc->missions_flown);
6340 ADD_UINT(sc->flight_time);
6341 ADD_INT(sc->last_flown);
6342 ADD_INT(sc->last_backup);
6347 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6348 u_tmp = sc->m_okKills[idx];
6352 ADD_INT(sc->m_score);
6353 ADD_INT(sc->m_assists);
6354 ADD_INT(sc->m_kill_count);
6355 ADD_INT(sc->m_kill_count_ok);
6356 ADD_UINT(sc->mp_shots_fired);
6357 ADD_UINT(sc->ms_shots_fired);
6358 ADD_UINT(sc->mp_shots_hit);
6359 ADD_UINT(sc->ms_shots_hit);
6360 ADD_UINT(sc->mp_bonehead_hits);
6361 ADD_UINT(sc->ms_bonehead_hits);
6362 ADD_INT(sc->m_bonehead_kills);
6363 ADD_INT(sc->m_player_deaths);
6364 ADD_INT(sc->m_medal_earned);
6367 case STATS_MISSION_KILLS:
6368 ADD_INT(sc->m_kill_count);
6369 ADD_INT(sc->m_kill_count_ok);
6370 ADD_INT(sc->m_assists);
6373 case STATS_DOGFIGHT_KILLS:
6374 for(idx=0; idx<MAX_PLAYERS; idx++){
6376 u_tmp = sc->m_dogfight_kills[idx];
6382 ADD_INT(sc->m_kill_count);
6383 ADD_INT(sc->m_kill_count_ok);
6384 ADD_INT(sc->m_assists);
6388 SDL_assert(packet_size < MAX_PACKET_SIZE);
6390 // if we're a client, always send the data to the server
6391 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6392 multi_io_send_reliable(Net_player, data, packet_size);
6394 // otherwise do server specific stuff
6396 // send to a specific target
6398 multi_io_send_reliable(target, data, packet_size);
6400 // otherwise, send to everyone
6402 multi_io_send_to_all_reliable(data, packet_size);
6407 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6411 scoring_struct *sc,bogus;
6413 int offset = HEADER_LENGTH;
6417 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6419 // get the player who these stats are for
6420 GET_SHORT(player_id);
6421 player_num = find_player_id(player_id);
6422 if (player_num == -1) {
6423 nprintf(("Network", "Couldn't find player for stats update!\n"));
6424 ml_string("Couldn't find player for stats update!\n");
6429 sc = &Net_players[player_num].player->stats;
6432 // get the stats code
6436 ml_string("Received STATS_ALLTIME\n");
6439 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6441 sc->kills[idx] = u_tmp;
6444 // read in the stats
6445 for (idx=0; idx<NUM_MEDALS; idx++) {
6447 sc->medals[idx] = i_tmp;
6452 GET_INT(sc->assists);
6453 GET_INT(sc->kill_count);
6454 GET_INT(sc->kill_count_ok);
6455 GET_UINT(sc->p_shots_fired);
6456 GET_UINT(sc->s_shots_fired);
6457 GET_UINT(sc->p_shots_hit);
6458 GET_UINT(sc->s_shots_hit);
6459 GET_UINT(sc->p_bonehead_hits);
6460 GET_UINT(sc->s_bonehead_hits);
6461 GET_INT(sc->bonehead_kills);
6463 GET_UINT(sc->missions_flown);
6464 GET_UINT(sc->flight_time);
6465 GET_INT(sc->last_flown);
6466 GET_INT(sc->last_backup);
6470 ml_string("Received STATS_MISSION\n");
6472 // kills - mission OK
6473 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6475 sc->m_okKills[idx] = u_tmp;
6478 GET_INT(sc->m_score);
6479 GET_INT(sc->m_assists);
6480 GET_INT(sc->m_kill_count);
6481 GET_INT(sc->m_kill_count_ok);
6482 GET_UINT(sc->mp_shots_fired);
6483 GET_UINT(sc->ms_shots_fired);
6484 GET_UINT(sc->mp_shots_hit);
6485 GET_UINT(sc->ms_shots_hit);
6486 GET_UINT(sc->mp_bonehead_hits);
6487 GET_UINT(sc->ms_bonehead_hits);
6488 GET_INT(sc->m_bonehead_kills);
6489 GET_INT(sc->m_player_deaths);
6490 GET_INT(sc->m_medal_earned);
6493 case STATS_MISSION_KILLS:
6494 ml_string("Received STATS_MISSION_KILLS\n");
6496 GET_INT(sc->m_kill_count);
6497 GET_INT(sc->m_kill_count_ok);
6498 GET_INT(sc->m_assists);
6501 case STATS_DOGFIGHT_KILLS:
6502 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6503 if(player_num >= 0){
6504 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6506 for(idx=0; idx<MAX_PLAYERS; idx++){
6509 sc->m_dogfight_kills[idx] = u_tmp;
6510 if(player_num >= 0){
6511 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6515 GET_INT(sc->m_kill_count);
6516 GET_INT(sc->m_kill_count_ok);
6517 GET_INT(sc->m_assists);
6522 // if I'm the server of the game, I should always rebroadcast these stats
6523 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6524 // make sure these are alltime stats
6525 SDL_assert(val == STATS_ALLTIME);
6527 multi_broadcast_stats(STATS_ALLTIME);
6531 // called to create asteroid stuff
6532 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6535 ubyte data[MAX_PACKET_SIZE];
6536 ubyte packet_type, atype;
6540 if (relvec != NULL )
6543 BUILD_HEADER( ASTEROID_INFO );
6544 packet_type = ASTEROID_CREATE;
6546 SDL_assert( asteroid_type < UCHAR_MAX );
6547 atype = (ubyte)asteroid_type;
6549 ADD_DATA( packet_type );
6550 ADD_USHORT( parent_objp->net_signature );
6551 ADD_USHORT( new_objp->net_signature );
6554 add_vector_data( data, &packet_size, vec );
6556 multi_io_send_to_all(data, packet_size);
6559 void send_asteroid_throw( object *objp )
6562 ubyte data[MAX_PACKET_SIZE], packet_type;
6564 BUILD_HEADER( ASTEROID_INFO );
6566 // this packet type is an asteroid throw
6567 packet_type = ASTEROID_THROW;
6568 ADD_DATA( packet_type );
6569 ADD_USHORT( objp->net_signature );
6570 //ADD_DATA( objp->pos );
6571 add_vector_data( data, &packet_size, objp->pos );
6572 //ADD_DATA( objp->phys_info.vel );
6573 add_vector_data( data, &packet_size, objp->phys_info.vel );
6575 multi_io_send_to_all(data, packet_size);
6578 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6581 ubyte data[MAX_PACKET_SIZE], packet_type;
6585 if ( hitpos != NULL )
6588 // build up an asteroid hit packet
6589 BUILD_HEADER( ASTEROID_INFO );
6590 packet_type = ASTEROID_HIT;
6591 ADD_DATA( packet_type );
6592 ADD_USHORT( objp->net_signature );
6594 if(other_objp == NULL){
6595 ushort invalid_sig = 0xffff;
6596 ADD_USHORT(invalid_sig);
6598 ADD_USHORT( other_objp->net_signature );
6601 add_vector_data( data, &packet_size, vec );
6602 ADD_FLOAT( damage );
6604 multi_io_send_to_all(data, packet_size);
6607 void process_asteroid_info( ubyte *data, header *hinfo )
6612 offset = HEADER_LENGTH;
6613 GET_DATA( packet_type );
6615 // based on the packet type, do something interesting with an asteroid!
6616 switch( packet_type ) {
6618 case ASTEROID_CREATE: {
6619 ushort psignature, signature;
6621 vector relvec = ZERO_VECTOR;
6622 object *parent_objp;
6624 GET_USHORT( psignature );
6625 GET_USHORT( signature );
6627 //GET_DATA( relvec );
6628 get_vector_data( data, &offset, relvec );
6630 // after getting the values, set the next network signature, and call the create sub function
6631 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6632 parent_objp = multi_get_network_object( psignature );
6633 if ( parent_objp ) {
6634 asteroid_sub_create( parent_objp, atype, &relvec );
6636 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6643 // asteroid throw packet -- asteroid has wrapped bounds
6644 case ASTEROID_THROW: {
6646 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6649 GET_USHORT( signature );
6651 get_vector_data( data, &offset, pos );
6653 get_vector_data( data, &offset, vel );
6654 objp = multi_get_network_object( signature );
6656 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6660 objp->phys_info.vel = vel;
6661 objp->phys_info.desired_vel = vel;
6665 case ASTEROID_HIT: {
6666 ushort signature, osignature;
6667 object *objp, *other_objp;
6668 vector hitpos = ZERO_VECTOR;
6671 GET_USHORT( signature );
6672 GET_USHORT( osignature );
6673 //GET_DATA( hitpos );
6674 get_vector_data( data, &offset, hitpos );
6675 GET_FLOAT( damage );
6677 objp = multi_get_network_object( signature );
6678 if(osignature == 0xffff){
6681 other_objp = multi_get_network_object( osignature );
6684 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6688 if ( IS_VEC_NULL(&hitpos) ){
6689 asteroid_hit( objp, other_objp, NULL, damage );
6691 asteroid_hit( objp, other_objp, &hitpos, damage );
6694 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6695 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6696 weapon_hit( other_objp, objp, &hitpos );
6709 void send_host_restr_packet(const char *callsign, int code, int mode)
6711 ubyte data[MAX_PACKET_SIZE],val;
6712 int packet_size = 0;
6714 // build the header and add the opcode
6715 BUILD_HEADER(HOST_RESTR_QUERY);
6722 ADD_STRING(callsign);
6724 // if I'm the standalone server, I should be sending this to the game host
6725 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6726 multi_io_send_reliable(Netgame.host, data, packet_size);
6728 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6730 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6731 multi_io_send_reliable(Net_player, data, packet_size);
6735 void process_host_restr_packet(ubyte *data, header *hinfo)
6739 int offset = HEADER_LENGTH;
6741 // get the opcode and the callsign
6744 GET_STRING(callsign);
6747 // do code specific operations
6749 // query to the host from standalone
6751 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6753 // set the join mode
6754 Multi_join_restr_mode = mode;
6756 // set the timestamp
6757 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6759 // notify the host of the event
6760 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6761 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6764 // affirmative reply from the host to the standalone
6766 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6768 // let the player join if the timestamp has not already elapsed on the server
6769 if(Multi_restr_query_timestamp != -1){
6770 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6776 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6777 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6778 Multi_restr_query_timestamp = -1;
6783 void send_netgame_end_error_packet(int notify_code,int err_code)
6787 int packet_size = 0;
6789 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6790 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6792 // build the header and add the notification and error codes
6793 BUILD_HEADER(NETGAME_END_ERROR);
6794 code = (char)notify_code;
6796 code = (char)err_code;
6800 multi_io_send_to_all_reliable(data, packet_size);
6803 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6805 int offset = HEADER_LENGTH;
6806 char notify_code,error_code;
6808 // get the error and notification codes
6809 GET_DATA(notify_code);
6810 GET_DATA(error_code);
6814 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6817 // sends info that a countermeasure succeeded.
6818 void send_countermeasure_success_packet( int objnum )
6820 int pnum, packet_size;
6821 ubyte data[MAX_PACKET_SIZE];
6823 pnum = multi_find_player_by_object( &Objects[objnum] );
6825 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6829 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6830 multi_io_send(&Net_players[pnum], data, packet_size);
6833 // start the flashing of my hud gauge
6834 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6838 offset = HEADER_LENGTH;
6841 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6842 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6845 #define UPDATE_IS_PAUSED (1<<0)
6846 #define UPDATE_HULL_INFO (1<<1)
6848 void send_client_update_packet(net_player *pl)
6850 ubyte data[MAX_PACKET_SIZE],val;
6851 int packet_size = 0;
6854 BUILD_HEADER(CLIENT_UPDATE);
6858 // add the pause status
6859 if ( Multi_pause_status ) {
6860 val |= UPDATE_IS_PAUSED;
6861 } 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) ) {
6862 val |= UPDATE_HULL_INFO;
6863 SDL_assert( Player_ship ); // I"d better have one of these!!!!
6868 // if paused, add the net address of the guy who paused
6869 if(val & UPDATE_IS_PAUSED){
6870 SDL_assert(Multi_pause_pauser != NULL);
6871 ADD_SHORT(Multi_pause_pauser->player_id);
6874 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6875 if ( val & UPDATE_HULL_INFO ) {
6877 ubyte percent, ns, threats;
6880 ship_subsys *subsysp;
6883 // get the object for the player
6884 SDL_assert( pl->player->objnum != -1 );
6886 objp = &Objects[pl->player->objnum];
6888 SDL_assert ( objp->type == OBJ_SHIP );
6889 shipp = &Ships[objp->instance];
6890 sip = &Ship_info[shipp->ship_info_index];
6892 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6893 // percentage value since that should be close enough
6894 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6898 percent = (ubyte)temp;
6900 ADD_DATA( percent );
6902 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6903 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6904 ADD_DATA( percent );
6907 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6908 // both machines. Added as percent since that number <= 100
6910 // also write out the number of subsystems. We do this because the client might not know
6911 // about the object he is getting data for. (i.e. he killed the object already).
6912 ns = (ubyte)sip->n_subsystems;
6915 // now the subsystems.
6916 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6917 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6918 ADD_DATA( percent );
6921 // compute the threats for this player. Only compute the threats if this player is actually
6922 // playing (i.e. he has a ship)
6923 hud_update_reticle( pl->player );
6924 threats = (ubyte)pl->player->threat_flags;
6925 ADD_DATA( threats );
6927 // add his energy level for guns
6928 ADD_FLOAT(shipp->weapon_energy);
6930 // add his secondary bank ammo
6931 ADD_INT(shipp->weapons.num_secondary_banks);
6932 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6933 ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6938 ADD_INT(pl->sv_last_pl);
6940 // send the packet reliably to the player
6941 multi_io_send(pl, data, packet_size);
6944 void process_client_update_packet(ubyte *data, header *hinfo)
6949 int is_paused, have_hull_info;
6952 float weapon_energy;
6953 int offset = HEADER_LENGTH;
6955 // get the header byte containing useful information
6958 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6959 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6961 // if we are paused, get who paused
6964 player_index = find_player_id(pauser);
6965 if(player_index != -1){
6966 Multi_pause_pauser = &Net_players[player_index];
6968 Multi_pause_pauser = NULL;
6972 // if we have hull information, then read it in.
6973 if ( have_hull_info ) {
6977 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6979 ship_subsys *subsysp;
6983 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6984 // percentage value since that should be close enough
6985 GET_DATA( hull_percent );
6987 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6989 shield_percent[i] = ub_tmp;
6992 // get the data for the subsystems
6993 GET_DATA( n_subsystems );
6994 for ( i = 0; i < n_subsystems; i++ ){
6996 subsystem_percent[i] = ub_tmp;
6999 GET_DATA( threats );
7001 // add his energy level for guns
7002 GET_FLOAT(weapon_energy);
7004 // add his secondary bank ammo
7005 GET_INT(ammo_count);
7006 for(i=0; i<ammo_count; i++){
7010 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
7011 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7012 // UDP client update packets. Only read this info if I have a ship.
7013 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
7014 shipp = Player_ship;
7016 sip = &Ship_info[shipp->ship_info_index];
7018 val = hull_percent * sip->initial_hull_strength / 100.0f;
7019 objp->hull_strength = val;
7021 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7022 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7023 objp->shields[i] = val;
7026 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
7027 // then don't read these in.
7028 if ( n_subsystems == sip->n_subsystems ) {
7030 n_subsystems = 0; // reuse this variable
7031 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7034 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7035 subsysp->current_hits = val;
7037 // add the value just generated (it was zero'ed above) into the array of generic system types
7038 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
7039 SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7040 shipp->subsys_info[subsys_type].current_hits += val;
7044 ship_recalc_subsys_strength( shipp );
7046 shipp->weapon_energy = weapon_energy;
7047 for(i=0; i<ammo_count; i++){
7048 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7051 // update my threat flags.
7052 // temporarily commented out until tested.
7053 Net_player->player->threat_flags = threats;
7060 if(Net_player != NULL){
7061 Net_player->cl_last_pl = pl;
7065 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7066 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7068 multi_pause_pause();
7070 multi_pause_unpause();
7075 void send_countdown_packet(int time)
7079 int packet_size = 0;
7081 // build the header and add the time
7082 BUILD_HEADER(COUNTDOWN);
7086 // if we're the server, we should broadcast to everyone
7087 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
7088 multi_io_send_to_all_reliable(data, packet_size);
7090 // otherwise we'de better be a host sending to the standalone
7092 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7093 multi_io_send_reliable(Net_player, data, packet_size);
7097 void process_countdown_packet(ubyte *data, header *hinfo)
7099 int offset = HEADER_LENGTH;
7106 // if we're not in the post sync data screen, ignore it
7107 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7111 // if we're the standalone, this should be a -1 telling us to start the countdown
7112 if(Game_mode & GM_STANDALONE_SERVER){
7113 SDL_assert((int)time == -1);
7115 // start the countdown
7116 multi_sync_start_countdown();
7118 // otherwise if we're clients, just bash the countdown
7120 Multi_sync_countdown = (int)time;
7124 // packets for debriefing information
7125 void send_debrief_info( int stage_count[], int *stages[] )
7127 ubyte data[MAX_PACKET_SIZE];
7128 int packet_size, i, j;
7131 BUILD_HEADER(DEBRIEF_INFO);
7133 // add the data for the teams
7134 for ( i = 0; i < Num_teams; i++ ) {
7137 count = stage_count[i];
7139 for ( j = 0; j < count; j++ ) {
7140 i_tmp = stages[i][j];
7145 multi_io_send_to_all_reliable(data, packet_size);
7148 // process a debrief info packet from the server
7149 void process_debrief_info( ubyte *data, header *hinfo )
7152 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7155 offset = HEADER_LENGTH;
7156 for ( i = 0; i < Num_teams; i++ ) {
7160 stage_counts[i] = count;
7161 stages[i] = active_stages[i];
7162 for ( j = 0; j < count; j++ ) {
7164 active_stages[i][j] = i_tmp;
7169 // now that we have the stage data for the debriefing stages, call debrief function with the
7170 // data so that clients can now see the debriefing stuff. Do it only for my team.
7171 SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7172 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7175 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7176 // sends homing_object and homing_subsystem to all clients.
7177 void send_homing_weapon_info( int weapon_num )
7179 ubyte data[MAX_PACKET_SIZE];
7182 object *homing_object;
7183 ushort homing_signature;
7186 wp = &Weapons[weapon_num];
7188 // be sure that this weapon object is a homing object.
7189 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7192 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7193 // homing signature.
7194 homing_signature = 0;
7195 homing_object = wp->homing_object;
7196 if ( homing_object != NULL ) {
7197 homing_signature = homing_object->net_signature;
7199 // get the subsystem index.
7201 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7204 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7205 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
7206 t_subsys = (char)s_index;
7210 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7211 ADD_USHORT( Objects[wp->objnum].net_signature );
7212 ADD_USHORT( homing_signature );
7213 ADD_DATA( t_subsys );
7215 multi_io_send_to_all(data, packet_size);
7218 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7219 // packet contains information for multiple weapons (like hornets).
7220 void process_homing_weapon_info( ubyte *data, header *hinfo )
7223 ushort weapon_signature, homing_signature;
7225 object *homing_object, *weapon_objp;
7228 offset = HEADER_LENGTH;
7230 // get the data for the packet
7231 GET_USHORT( weapon_signature );
7232 GET_USHORT( homing_signature );
7233 GET_DATA( h_subsys );
7236 // deal with changing this weapons homing information
7237 weapon_objp = multi_get_network_object( weapon_signature );
7238 if ( weapon_objp == NULL ) {
7239 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7242 SDL_assert( weapon_objp->type == OBJ_WEAPON );
7243 wp = &Weapons[weapon_objp->instance];
7245 // be sure that we can find these weapons and
7246 homing_object = multi_get_network_object( homing_signature );
7247 if ( homing_object == NULL ) {
7248 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7252 if ( homing_object->type == OBJ_WEAPON ) {
7253 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7256 wp->homing_object = homing_object;
7257 wp->homing_subsys = NULL;
7258 wp->target_num = OBJ_INDEX(homing_object);
7259 wp->target_sig = homing_object->signature;
7260 if ( h_subsys != -1 ) {
7261 SDL_assert( homing_object->type == OBJ_SHIP );
7262 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7265 if ( homing_object->type == OBJ_SHIP ) {
7266 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7270 void send_emp_effect(ushort net_sig, float intensity, float time)
7275 SDL_assert(MULTIPLAYER_MASTER);
7277 // build the packet and add the opcode
7278 BUILD_HEADER(EMP_EFFECT);
7279 ADD_USHORT(net_sig);
7280 ADD_FLOAT(intensity);
7283 // send it to the player
7284 multi_io_send_to_all(data, packet_size);
7287 void process_emp_effect(ubyte *data, header *hinfo)
7289 float intensity, time;
7292 int offset = HEADER_LENGTH;
7294 // read in the EMP effect data
7295 GET_USHORT(net_sig);
7296 GET_FLOAT(intensity);
7300 // try and find the object
7301 objp = multi_get_network_object(net_sig);
7302 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7303 // if i'm not an observer and I have a valid ship, play the EMP effect
7304 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7305 emp_start_local(intensity, time);
7308 // start the effect for the ship itself
7309 emp_start_ship(objp, intensity, time);
7313 // tells whether or not reinforcements are available
7314 void send_reinforcement_avail( int rnum )
7319 BUILD_HEADER(REINFORCEMENT_AVAIL);
7321 multi_io_send_to_all_reliable(data, packet_size);
7324 void process_reinforcement_avail( ubyte *data, header *hinfo )
7329 offset = HEADER_LENGTH;
7333 // sanity check for a valid reinforcement number
7334 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7335 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7339 void send_change_iff_packet(ushort net_signature, int new_team)
7341 ubyte data[MAX_PACKET_SIZE];
7342 int packet_size = 0;
7344 if(Net_player == NULL){
7347 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7351 // build the packet and add the data
7352 BUILD_HEADER(CHANGE_IFF);
7353 ADD_USHORT(net_signature);
7356 // send to all players
7357 multi_io_send_to_all_reliable(data, packet_size);
7360 void process_change_iff_packet( ubyte *data, header *hinfo)
7362 int offset = HEADER_LENGTH;
7363 ushort net_signature;
7368 GET_USHORT(net_signature);
7372 // lookup the object
7373 objp = multi_get_network_object(net_signature);
7374 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7375 Ships[objp->instance].team = new_team;
7379 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7381 int packet_size, objnum;
7382 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7385 net_player *ignore = NULL;
7387 // sanity checking for now
7388 SDL_assert ( banks_fired <= 3 );
7390 // get an object pointer for this ship.
7391 objnum = shipp->objnum;
7392 objp = &Objects[objnum];
7394 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7395 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7399 // just in case nothing got fired
7400 if(banks_fired <= 0){
7404 // ubanks_fired = (ubyte)banks_fired;
7405 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7406 // SDL_assert( current_bank <= 3 );
7408 // insert the current primary bank into this byte
7409 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7411 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7412 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7413 // ubanks_fired |= (1<<7);
7416 // determine if its a player ship and don't send to him if we're in "client firing" mode
7417 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7418 if(MULTIPLAYER_MASTER){
7419 np_index = multi_find_player_by_net_signature(objp->net_signature);
7420 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7421 ignore = &Net_players[np_index];
7425 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7426 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7427 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7428 // and server in sync w.r.t. weapon energy for player ship
7429 BUILD_HEADER( PRIMARY_FIRED_NEW );
7430 ADD_USHORT(objp->net_signature);
7431 // ADD_DATA(ubanks_fired);
7433 // if I'm a server, broadcast to all players
7434 if(MULTIPLAYER_MASTER){
7435 multi_io_send_to_all(data, packet_size, ignore);
7438 multi_rate_add(1, "wfi", packet_size);
7440 // otherwise just send to the server
7442 multi_io_send(Net_player, data, packet_size);
7446 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7448 int offset; // linked;
7449 // ubyte banks_fired, current_bank;
7454 // read all packet info
7455 offset = HEADER_LENGTH;
7456 GET_USHORT(shooter_sig);
7457 // GET_DATA(banks_fired);
7460 // find the object this fired packet is operating on
7461 objp = multi_get_network_object( shooter_sig );
7462 if ( objp == NULL ) {
7463 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7466 // if this object is not actually a valid ship, don't do anything
7467 if(objp->type != OBJ_SHIP){
7470 if(objp->instance < 0){
7473 // shipp = &Ships[objp->instance];
7475 // get the link status of the primary banks
7477 // if ( banks_fired & (1<<7) ) {
7479 // banks_fired ^= (1<<7);
7482 // get the current primary bank
7483 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7484 // current_bank &= 0x3;
7485 // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7486 // shipp->weapons.current_primary_bank = current_bank;
7488 // strip off all remaining bits and just keep which banks were actually fired.
7489 // banks_fired &= 0x3;
7491 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7494 // shipp->flags &= ~SF_PRIMARY_LINKED;
7496 // shipp->flags |= SF_PRIMARY_LINKED;
7499 // if we're in client firing mode, ignore ones for myself
7500 if((Player_obj != NULL) && (Player_obj == objp)){
7504 ship_fire_primary( objp, 0, 1 );
7507 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7509 ubyte data[MAX_PACKET_SIZE];
7512 net_player *ignore = NULL;
7514 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7515 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7519 SDL_assert ( cmeasure_count < UCHAR_MAX );
7520 BUILD_HEADER(COUNTERMEASURE_NEW);
7521 ADD_USHORT( objp->net_signature );
7522 ADD_INT( rand_val );
7524 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7526 // determine if its a player ship and don't send to him if we're in "client firing" mode
7527 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7528 if(MULTIPLAYER_MASTER){
7529 np_index = multi_find_player_by_net_signature(objp->net_signature);
7530 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7531 ignore = &Net_players[np_index];
7535 // if I'm the server, send to all players
7536 if(MULTIPLAYER_MASTER){
7537 multi_io_send_to_all(data, packet_size, ignore);
7539 // otherwise send to the server
7541 multi_io_send(Net_player, data, packet_size);
7545 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7552 offset = HEADER_LENGTH;
7553 GET_USHORT( signature );
7554 GET_INT( rand_val );
7557 objp = multi_get_network_object( signature );
7558 if ( objp == NULL ) {
7559 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7562 if(objp->type != OBJ_SHIP){
7566 // if we're in client firing mode, ignore ones for myself
7567 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7568 if((Player_obj != NULL) && (Player_obj == objp)){
7572 // make it so ship can fire right away!
7573 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7574 if ( objp == Player_obj ){
7575 nprintf(("network", "firing countermeasure from my ship\n"));
7577 ship_launch_countermeasure( objp, rand_val );
7580 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7582 ubyte data[MAX_PACKET_SIZE];
7583 int packet_size = 0;
7588 // only the server should ever be doing this
7589 SDL_assert(MULTIPLAYER_MASTER);
7591 // setup outgoing data
7592 SDL_assert(shooter != NULL);
7593 SDL_assert(turret != NULL);
7594 SDL_assert(target != NULL);
7595 SDL_assert(override != NULL);
7596 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7599 u_beam_info = (ubyte)beam_info_index;
7600 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7601 SDL_assert(subsys_index >= 0);
7602 if(subsys_index < 0){
7606 // swap the beam_info override info into little endian byte order
7607 b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7608 b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7609 b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7611 b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7612 b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7613 b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7615 b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7616 b_info.shot_count = override->shot_count;
7618 for (int i = 0; i < b_info.shot_count; i++) {
7619 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7623 BUILD_HEADER(BEAM_FIRED);
7624 ADD_USHORT(shooter->net_signature);
7625 ADD_DATA(subsys_index);
7626 ADD_USHORT(target->net_signature);
7627 ADD_DATA(u_beam_info);
7628 ADD_DATA(b_info); // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7630 // send to all clients
7631 multi_io_send_to_all_reliable(data, packet_size);
7634 void process_beam_fired_packet(ubyte *data, header *hinfo)
7637 ushort shooter_sig, target_sig;
7641 beam_fire_info fire_info;
7643 // only clients should ever get this
7644 SDL_assert(MULTIPLAYER_CLIENT);
7646 // read in packet data
7647 offset = HEADER_LENGTH;
7648 GET_USHORT(shooter_sig);
7649 GET_DATA(subsys_index);
7650 GET_USHORT(target_sig);
7651 GET_DATA(u_beam_info);
7656 // swap the beam_info override info into native byte order
7657 b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7658 b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7659 b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7660 b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7661 b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7662 b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7663 b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7665 for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7666 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7669 // lookup all relevant data
7670 fire_info.beam_info_index = (int)u_beam_info;
7671 fire_info.shooter = NULL;
7672 fire_info.target = NULL;
7673 fire_info.turret = NULL;
7674 fire_info.target_subsys = NULL;
7675 fire_info.beam_info_override = NULL;
7676 fire_info.shooter = multi_get_network_object(shooter_sig);
7677 fire_info.target = multi_get_network_object(target_sig);
7678 fire_info.beam_info_override = &b_info;
7679 fire_info.accuracy = 1.0f;
7680 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)){
7681 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7684 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7685 if(fire_info.turret == NULL){
7686 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7691 beam_fire(&fire_info);
7694 void send_sw_query_packet(ubyte code, char *txt)
7696 ubyte data[MAX_PACKET_SIZE];
7697 int packet_size = 0;
7699 // build the packet and add the code
7700 BUILD_HEADER(SW_STD_QUERY);
7702 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7706 // if I'm the host, send to standalone
7707 if(MULTIPLAYER_HOST){
7708 SDL_assert(!MULTIPLAYER_MASTER);
7709 SDL_assert(code == SW_STD_START);
7710 multi_io_send_reliable(Net_player, data, packet_size);
7712 // otherwise standalone sends back to host
7714 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7715 SDL_assert(code != SW_STD_START);
7716 SDL_assert(Netgame.host != NULL);
7717 if(Netgame.host != NULL){
7718 multi_io_send_reliable(Netgame.host, data, packet_size);
7723 void process_sw_query_packet(ubyte *data, header *hinfo)
7727 void send_event_update_packet(int event)
7729 ubyte data[MAX_PACKET_SIZE];
7730 ushort u_event = (ushort)event;
7731 int packet_size = 0;
7733 // build the header and add the event
7734 BUILD_HEADER(EVENT_UPDATE);
7735 ADD_USHORT(u_event);
7736 ADD_INT(Mission_events[event].flags);
7737 ADD_INT(Mission_events[event].formula);
7738 ADD_INT(Mission_events[event].result);
7739 ADD_INT(Mission_events[event].count);
7741 // send to all players
7742 multi_io_send_to_all_reliable(data, packet_size);
7745 void process_event_update_packet(ubyte *data, header *hinfo)
7747 int offset = HEADER_LENGTH;
7752 GET_USHORT(u_event);
7753 store_flags = Mission_events[u_event].flags;
7754 GET_INT(Mission_events[u_event].flags);
7755 GET_INT(Mission_events[u_event].formula);
7756 GET_INT(Mission_events[u_event].result);
7757 GET_INT(Mission_events[u_event].count);
7760 // went from non directive special to directive special
7761 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7762 mission_event_set_directive_special(u_event);
7764 // if we went directive special to non directive special
7765 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7766 mission_event_unset_directive_special(u_event);
7770 // weapon detonate packet
7771 void send_weapon_detonate_packet(object *objp)
7773 ubyte data[MAX_PACKET_SIZE];
7774 int packet_size = 0;
7777 SDL_assert(MULTIPLAYER_MASTER);
7778 if(!MULTIPLAYER_MASTER){
7781 SDL_assert(objp != NULL);
7786 // build the header and add the data
7787 BUILD_HEADER(WEAPON_DET);
7788 ADD_USHORT(objp->net_signature);
7790 // send to all players
7791 multi_io_send_to_all(data, packet_size);
7794 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7797 int offset = HEADER_LENGTH;
7798 object *objp = NULL;
7800 // get the weapon signature
7801 GET_USHORT(net_sig);
7804 // lookup the weapon
7805 objp = multi_get_network_object(net_sig);
7806 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7807 weapon_detonate(objp);
7811 // flak fired packet
7812 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7815 ushort pnet_signature;
7816 ubyte data[MAX_PACKET_SIZE], cindex;
7822 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7826 // local setup -- be sure we are actually passing a weapon!!!!
7827 objp = &Objects[weapon_objnum];
7828 SDL_assert ( objp->type == OBJ_WEAPON );
7829 pnet_signature = Objects[ship_objnum].net_signature;
7831 SDL_assert( subsys_index < UCHAR_MAX );
7832 cindex = (ubyte)subsys_index;
7834 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7839 // build the fire turret packet.
7840 BUILD_HEADER(FLAK_FIRED);
7841 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7842 ADD_USHORT( pnet_signature );
7844 val = (short)ssp->submodel_info_1.angs.h;
7846 val = (short)ssp->submodel_info_2.angs.p;
7848 ADD_FLOAT( flak_range );
7850 multi_io_send_to_all(data, packet_size);
7852 multi_rate_add(1, "flk", packet_size);
7855 void process_flak_fired_packet(ubyte *data, header *hinfo)
7857 int offset, weapon_objnum, wid;
7858 ushort pnet_signature;
7866 short pitch, heading;
7869 // get the data for the turret fired packet
7870 offset = HEADER_LENGTH;
7871 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7872 GET_USHORT( pnet_signature );
7873 GET_DATA( turret_index );
7874 GET_SHORT( heading );
7876 GET_FLOAT( flak_range );
7877 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7880 objp = multi_get_network_object( pnet_signature );
7881 if ( objp == NULL ) {
7882 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7886 // if this isn't a ship, do nothing
7887 if ( objp->type != OBJ_SHIP ){
7891 // make an orientation matrix from the o_fvec
7892 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7894 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7895 // hack, but should be suitable.
7896 shipp = &Ships[objp->instance];
7897 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7901 wid = ssp->system_info->turret_weapon_type;
7902 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7906 // bash the position and orientation of the turret
7907 ssp->submodel_info_1.angs.h = (float)heading;
7908 ssp->submodel_info_2.angs.p = (float)pitch;
7910 // get the world position of the weapon
7911 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7913 // create the weapon object
7914 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7915 if (weapon_objnum != -1) {
7916 if ( Weapon_info[wid].launch_snd != -1 ) {
7917 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7920 // create a muzzle flash from a flak gun based upon firing position and weapon type
7921 flak_muzzle_flash(&pos, &dir, wid);
7923 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7924 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7928 #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);
7929 #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);
7931 // player pain packet
7932 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7934 ubyte data[MAX_PACKET_SIZE];
7937 int packet_size = 0;
7939 SDL_assert(MULTIPLAYER_MASTER);
7940 if(!MULTIPLAYER_MASTER){
7943 SDL_assert(pl != NULL);
7948 // build the packet and add the code
7949 BUILD_HEADER(NETPLAYER_PAIN);
7950 windex = (ubyte)weapon_info_index;
7952 udamage = (ushort)damage;
7953 ADD_USHORT(udamage);
7954 //ADD_DATA((*force));
7955 add_vector_data( data, &packet_size, *force );
7956 //ADD_DATA((*hitpos));
7957 add_vector_data( data, &packet_size, *hitpos );
7959 // send to the player
7960 multi_io_send(pl, data, packet_size);
7962 multi_rate_add(1, "pai", packet_size);
7965 void process_player_pain_packet(ubyte *data, header *hinfo)
7970 vector force = ZERO_VECTOR;
7971 vector local_hit_pos = ZERO_VECTOR;
7974 // get the data for the pain packet
7975 offset = HEADER_LENGTH;
7977 GET_USHORT(udamage);
7979 get_vector_data( data, &offset, force );
7980 //GET_DATA(local_hit_pos);
7981 get_vector_data( data, &offset, local_hit_pos );
7984 mprintf(("PAIN!\n"));
7986 // get weapon info pointer
7987 //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)); // always true
7988 if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7991 wip = &Weapon_info[windex];
7993 // play the weapon hit sound
7994 SDL_assert(Player_obj != NULL);
7995 if(Player_obj == NULL){
7998 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
8000 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
8001 ship_hit_pain((float)udamage);
8004 ship_apply_whack(&force, &local_hit_pos, Player_obj);
8008 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8010 ubyte data[MAX_PACKET_SIZE];
8012 int packet_size = 0;
8014 // build the header and add the data
8015 BUILD_HEADER(LIGHTNING_PACKET);
8016 val = (char)bolt_type;
8018 //ADD_DATA((*start));
8019 add_vector_data( data, &packet_size, *start );
8020 //ADD_DATA((*strike));
8021 add_vector_data( data, &packet_size, *strike );
8023 // send to everyone unreliable for now
8024 multi_io_send_to_all(data, packet_size);
8027 void process_lightning_packet(ubyte *data, header *hinfo)
8031 vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8034 offset = HEADER_LENGTH;
8035 GET_DATA(bolt_type);
8037 get_vector_data(data, &offset, start);
8038 // GET_DATA(strike);
8039 get_vector_data(data, &offset, strike);
8048 nebl_bolt(bolt_type, &start, &strike);
8051 void send_bytes_recvd_packet(net_player *pl)
8053 // only clients should ever be doing this
8058 ubyte data[MAX_PACKET_SIZE];
8059 int packet_size = 0;
8060 BUILD_HEADER(BYTES_SENT);
8061 ADD_INT(pl->cl_bytes_recvd);
8063 // send to the server
8064 multi_io_send_reliable(pl, data, packet_size);
8067 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8071 net_player *pl = NULL;
8072 int offset = HEADER_LENGTH;
8078 if(Net_player == NULL){
8081 if(!MULTIPLAYER_MASTER){
8085 // make sure we know what player sent this
8086 pid = find_player_id(hinfo->id);
8087 if((pid < 0) || (pid >= MAX_PLAYERS)){
8090 pl = &Net_players[pid];
8093 pl->cl_bytes_recvd = bytes;
8097 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8100 pl->sv_bytes_sent = 0;
8104 void send_host_captain_change_packet(short player_id, int captain_change)
8106 ubyte data[MAX_PACKET_SIZE];
8107 int packet_size = 0;
8110 BUILD_HEADER(TRANSFER_HOST);
8111 ADD_SHORT(player_id);
8112 ADD_INT(captain_change);
8115 multi_io_send_to_all_reliable(data, packet_size);
8118 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8120 int offset = HEADER_LENGTH;
8121 int idx, found_player, captain_change;
8124 // get the player id
8125 GET_SHORT(player_id);
8126 GET_INT(captain_change);
8132 for(idx=0; idx<MAX_PLAYERS; idx++){
8133 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8134 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8139 // unflag all old players
8140 for(idx=0; idx<MAX_PLAYERS; idx++){
8141 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8146 for(idx=0; idx<MAX_PLAYERS; idx++){
8147 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8148 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8150 // spew to the HUD config
8151 if(Net_players[idx].player != NULL){
8152 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8162 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8167 void send_self_destruct_packet()
8169 ubyte data[MAX_PACKET_SIZE];
8170 int packet_size = 0;
8173 if(Net_player == NULL){
8177 // if i'm the server, I shouldn't be here
8178 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8179 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8183 // only if this is valid
8184 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8189 if((Player_ship == NULL) || (Player_obj == NULL)){
8194 BUILD_HEADER(SELF_DESTRUCT);
8195 ADD_USHORT(Player_obj->net_signature);
8197 // send to the server
8198 multi_io_send_reliable(Net_player, data, packet_size);
8201 void process_self_destruct_packet(ubyte *data, header *hinfo)
8203 int offset = HEADER_LENGTH;
8207 // get the net signature
8208 GET_USHORT(net_sig);
8212 np_index = find_player_id(hinfo->id);
8216 if(MULTI_OBSERVER(Net_players[np_index])){
8219 if(Net_players[np_index].player == NULL){
8222 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8225 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8228 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8231 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8236 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);