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->net_id, 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,sizeof(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 memcpy(new_addr.net_id, Psnet_my_addr.net_id, 4);
1365 if(new_flags & NETINFO_FLAG_OBSERVER){
1366 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1367 Net_players[new_player_num].flags |= new_flags;
1369 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1370 Net_players[new_player_num].flags |= new_flags;
1373 // copy in the filename
1374 if(strlen(new_player_image) > 0){
1375 SDL_strlcpy(Net_players[new_player_num].player->image_filename, new_player_image, MAX_FILENAME_LEN);
1377 SDL_strlcpy(Net_players[new_player_num].player->image_filename, "", MAX_FILENAME_LEN);
1379 // copy his pilot squad filename
1380 Net_players[new_player_num].player->insignia_texture = -1;
1381 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1383 // copy in his pxo squad name
1384 SDL_strlcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad, LOGIN_LEN);
1386 // since we just created the player, set the last_heard_time here.
1387 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1389 Net_players[new_player_num].p_info.team = team;
1391 Net_players[new_player_num].player_id = new_id;
1393 // zero out this players ping
1394 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1396 // add a chat message
1397 if(Net_players[new_player_num].player->callsign != NULL){
1398 SDL_snprintf(notify_string,sizeof(notify_string),XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1399 multi_display_chat_msg(notify_string,0,0);
1404 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1406 // let the current ui screen know someone joined
1407 switch(gameseq_get_state()){
1408 case GS_STATE_MULTI_HOST_SETUP :
1409 multi_create_handle_join(&Net_players[new_player_num]);
1411 case GS_STATE_MULTI_CLIENT_SETUP :
1412 multi_jw_handle_join(&Net_players[new_player_num]);
1417 #define PLAYER_DATA_SLOP 100
1419 void send_accept_player_data( net_player *npp, int is_ingame )
1423 ubyte data[MAX_PACKET_SIZE], stop;
1425 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1427 // add in the netplayer data for all players
1429 for (i=0; i<MAX_PLAYERS; i++) {
1430 // skip non connected players
1431 if ( !MULTI_CONNECTED(Net_players[i]) ){
1435 // skip this new player's entry
1436 if ( npp->player_id == Net_players[i].player_id ){
1440 // add the stop byte
1443 // add the player's number
1446 // add the player's address
1447 // ADD_DATA(Net_players[i].p_info.addr);
1448 add_net_addr(data, &packet_size, Net_players[i].p_info.addr);
1451 ADD_SHORT(Net_players[i].player_id);
1454 ADD_STRING(Net_players[i].player->callsign);
1456 // add his image filename
1457 ADD_STRING(Net_players[i].player->image_filename);
1459 // add his squad filename
1460 ADD_STRING(Net_players[i].player->squad_filename);
1462 // add his PXO squad name
1463 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1466 ADD_INT(Net_players[i].flags);
1468 // add his object's net sig
1470 ADD_USHORT( Objects[Net_players[i].player->objnum].net_signature );
1473 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1474 stop = APD_END_PACKET;
1476 multi_io_send_reliable( npp, data, packet_size );
1477 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1483 // add the stop byte
1484 stop = APD_END_DATA;
1486 multi_io_send_reliable(npp, data, packet_size);
1489 // send an accept packet to a client in response to a request to join the game
1490 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1493 ubyte data[MAX_PACKET_SIZE],val;
1494 char notify_string[256];
1497 SDL_assert(new_player_num >= 0);
1499 // setup his "reliable" socket
1500 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1502 // build the packet header
1504 BUILD_HEADER(ACCEPT);
1506 // add the accept code
1509 // add code specific accept data
1510 if (code & ACCEPT_INGAME) {
1511 // the game filename
1512 ADD_STRING(Game_current_mission_filename);
1514 // if he is joining on a specific team, mark it here
1515 if(ingame_join_team != -1){
1518 val = (ubyte)ingame_join_team;
1526 if (code & ACCEPT_OBSERVER) {
1527 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1530 if (code & ACCEPT_HOST) {
1531 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1534 if (code & ACCEPT_CLIENT) {
1535 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1538 // add the current skill level setting on the host
1539 ADD_INT(Game_skill_level);
1541 // add this guys player num
1542 ADD_INT(new_player_num);
1544 // add his player id
1545 ADD_SHORT(Net_players[new_player_num].player_id);
1547 // add netgame type flags
1548 ADD_INT(Netgame.type_flags);
1551 // char buffer[100];
1552 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1555 // actually send the packet
1556 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1558 // if he's not an observer, inform all the other players in the game about him
1559 // inform the other players in the game about this new player
1560 for (i=0; i<MAX_PLAYERS; i++) {
1561 // skip unconnected players as well as this new guy himself
1562 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])) {
1566 // send the new packet
1567 send_new_player_packet(new_player_num,&Net_players[i]);
1570 // add a chat message
1571 if(Net_players[new_player_num].player->callsign != NULL){
1572 SDL_snprintf(notify_string,sizeof(notify_string),XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1573 multi_display_chat_msg(notify_string, 0, 0);
1576 // handle any team vs. team details
1577 if (!(code & ACCEPT_OBSERVER)) {
1578 multi_team_handle_join(&Net_players[new_player_num]);
1582 if(Net_players[new_player_num].tracker_player_id >= 0){
1583 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);
1585 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1590 // process the player data from the server
1591 void process_accept_player_data( ubyte *data, header *hinfo )
1593 int offset, player_num, player_slot_num, new_flags;
1594 char name[CALLSIGN_LEN + 1] = "";
1595 char image_name[MAX_FILENAME_LEN + 1] = "";
1596 char squad_name[MAX_FILENAME_LEN + 1] = "";
1597 char pxo_squad_name[LOGIN_LEN+1] = "";
1601 ushort ig_signature;
1603 offset = HEADER_LENGTH;
1606 while ( stop == APD_NEXT ) {
1607 player_slot_num = multi_find_open_player_slot();
1608 SDL_assert(player_slot_num != -1);
1610 // get the player's number
1611 GET_INT(player_num);
1613 // add the player's address
1614 memset(&addr, 0, sizeof(net_addr));
1615 get_net_addr(data, &offset, addr);
1617 // get the player's id#
1618 GET_SHORT(player_id);
1623 // add his image filename
1624 GET_STRING(image_name);
1626 // get his squad logo filename
1627 GET_STRING(squad_name);
1629 // get his PXO squad name
1630 GET_STRING(pxo_squad_name);
1635 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1636 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1641 // the error handling here is less than stellar. We should probably put up a popup and go
1642 // back to the main menu. But then again, this should never ever happen!
1643 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1648 // copy his image filename
1649 SDL_strlcpy(Net_players[player_num].player->image_filename, image_name, MAX_FILENAME_LEN);
1651 // copy his pilot squad filename
1652 Net_players[player_num].player->insignia_texture = -1;
1653 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1655 // copy his pxo squad name
1656 SDL_strlcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name, LOGIN_LEN);
1658 // set his player id#
1659 Net_players[player_num].player_id = player_id;
1661 // mark him as being connected
1662 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1663 Net_players[player_num].flags |= new_flags;
1665 // set the server pointer
1666 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1667 Netgame.server = &Net_players[player_num];
1668 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1670 // also - always set the server address to be where this data came from, NOT from
1671 // the data in the packet
1672 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->net_id, hinfo->port);
1675 // set the host pointer
1676 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1677 Netgame.host = &Net_players[player_num];
1680 // read in the player's object net signature and store as his objnum for now
1681 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1682 GET_USHORT( ig_signature );
1683 Net_players[player_num].player->objnum = ig_signature;
1686 // get the stop byte
1691 if ( stop == APD_END_DATA ) {
1692 // if joining a game automatically, set the connect address to NULl so we don't try and
1693 // do this next time we enter a game
1694 if (Cmdline_connect_addr != NULL) {
1695 Cmdline_connect_addr = NULL;
1698 // send my stats to the server if I'm not in observer mode
1699 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1700 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1703 // if i'm being accepted as a host, then move into the host setup state
1704 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1705 // set my permission bits
1706 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1707 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1709 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1712 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1713 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1715 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1716 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1717 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1721 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1722 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1725 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1726 // flag myself as being an ingame joiner
1727 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1729 // move myself into the ingame join mission sync state
1730 Multi_sync_mode = MULTI_SYNC_INGAME;
1731 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1734 // update my options on the server
1735 multi_options_update_local();
1737 // if we're in PXO mode, mark it down in our player struct
1738 if(MULTI_IS_TRACKER_GAME){
1739 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1740 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1745 // process an accept packet from the server
1746 extern int Select_default_ship;
1748 void process_accept_packet(ubyte* data, header* hinfo)
1750 int code, my_player_num, offset;
1754 // get the accept code
1755 offset = HEADER_LENGTH;
1759 // read in the accept code specific data
1761 if (code & ACCEPT_INGAME) {
1762 // the game filename
1763 GET_STRING(Game_current_mission_filename);
1764 Select_default_ship = 0;
1766 // determine if I'm being placed on a team
1773 if (code & ACCEPT_OBSERVER) {
1774 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1777 if (code & ACCEPT_HOST) {
1778 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1781 if (code & ACCEPT_CLIENT) {
1782 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1785 // fill in the netgame server address
1786 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->net_id, hinfo->port );
1788 // get the skill level setting
1789 GET_INT(Game_skill_level);
1791 // get my netplayer number
1792 GET_INT(my_player_num);
1795 GET_SHORT(player_id);
1797 // get netgame type flags
1798 GET_INT(Netgame.type_flags);
1800 // setup the Net_players structure for myself first
1801 Net_player = &Net_players[my_player_num];
1802 Net_player->flags = 0;
1803 Net_player->tracker_player_id = Multi_tracker_id;
1804 Net_player->player_id = player_id;
1805 Net_player->s_info.xfer_handle = -1;
1806 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1807 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1808 multi_options_local_load(&Net_player->p_info.options, Net_player);
1810 Net_player->p_info.team = team;
1813 // determine if I have a CD
1815 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1818 // set accept code in netplayer for this guy
1819 if ( code & ACCEPT_INGAME ){
1820 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1822 if ( code & ACCEPT_OBSERVER ){
1823 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1825 if ( code & ACCEPT_HOST ){
1826 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1828 if ( code & ACCEPT_CLIENT ){
1829 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1832 // if I have hacked data
1833 if(game_hacked_data()){
1834 Net_player->flags |= NETINFO_FLAG_HAXOR;
1837 // if we're supposed to flush our local data cache, do so now
1838 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1839 multi_flush_multidata_cache();
1842 Net_player->sv_bytes_sent = 0;
1843 Net_player->sv_last_pl = -1;
1844 Net_player->cl_bytes_recvd = 0;
1845 Net_player->cl_last_pl = -1;
1847 // intiialize endgame stuff
1848 multi_endgame_init();
1852 // make a call to psnet to initialize and try to connect with the server.
1853 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1854 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1855 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1859 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1860 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1862 ubyte data[MAX_PACKET_SIZE];
1864 int packet_size = 0;
1866 BUILD_HEADER(LEAVE_GAME);
1868 // add a flag indicating whether he was kicked or not
1869 val = (char)kicked_reason;
1872 if (player_id < 0) {
1873 ADD_SHORT(Net_player->player_id);
1875 // inform the host that we are leaving the game
1876 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1877 multi_io_send_to_all_reliable(data, packet_size);
1879 multi_io_send_reliable(Net_player, data, packet_size);
1882 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1883 // so he has to tell everyone that this guy left
1885 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1887 // a couple of important checks
1888 SDL_assert(player_id != Net_player->player_id);
1889 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1891 // add the id of the guy to be kicked
1892 ADD_SHORT(player_id);
1894 // broadcast to everyone
1895 if (target == NULL) {
1896 multi_io_send_to_all_reliable(data, packet_size);
1898 multi_io_send_reliable(target, data, packet_size);
1903 // process a notification the a player has left the game
1904 void process_leave_game_packet(ubyte* data, header* hinfo)
1912 offset = HEADER_LENGTH;
1914 // get whether he was kicked
1915 GET_DATA(kicked_reason);
1917 // get the address of the guy who is to leave
1918 GET_SHORT(deader_id);
1921 // determine who is dropping and printf out a notification
1922 player_num = find_player_id(deader_id);
1923 if (player_num == -1) {
1924 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1928 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1931 // a hook to display that a player was kicked
1932 if (kicked_reason >= 0){
1933 // if it was me that was kicked, leave the game
1934 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1937 switch(kicked_reason){
1938 case KICK_REASON_BAD_XFER:
1939 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1941 case KICK_REASON_CANT_XFER:
1942 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1944 case KICK_REASON_INGAME_ENDED:
1945 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1948 notify_code = MULTI_END_NOTIFY_KICKED;
1952 multi_quit_game(PROMPT_NONE, notify_code);
1955 // otherwise indicate someone was kicked
1957 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1959 // display the result
1960 memset(str, 0, 512);
1961 multi_kick_get_text(&Net_players[player_num], kicked_reason, str, sizeof(str));
1962 multi_display_chat_msg(str, player_num, 0);
1966 // first of all, if we're the master, we should be rebroadcasting this packet
1967 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1970 SDL_snprintf(msg, sizeof(msg), XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1972 if (!(Game_mode & GM_STANDALONE_SERVER)){
1973 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1976 send_hud_msg_to_all(msg);
1977 multi_io_send_to_all_reliable(data, offset);
1980 // leave the game if the host and/or master has dropped
1982 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1983 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1986 ml_string(NOX("Host and/or server has left the game"));
1988 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1989 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1990 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1993 delete_player(player_num);
1996 delete_player(player_num);
1998 // OSAPI GUI stuff (if standalone)
1999 if (Game_mode & GM_STANDALONE_SERVER) {
2000 // returns true if we should reset the standalone
2001 if (std_remove_player(&Net_players[player_num])) {
2002 nprintf(("Network", "Should reset!!\n"));
2006 // update these gui vals
2007 std_connect_set_host_connect_status();
2008 std_connect_set_connect_count();
2012 // send information about this currently active game to the specified address
2013 void send_game_active_packet(net_addr* addr)
2017 ubyte data[MAX_PACKET_SIZE],val;
2019 // build the header and add the data
2020 BUILD_HEADER(GAME_ACTIVE);
2022 // add the server version and compatible version #
2023 val = MULTI_FS_SERVER_VERSION;
2025 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2028 ADD_STRING(Netgame.name);
2029 ADD_STRING(Netgame.mission_name);
2030 ADD_STRING(Netgame.title);
2031 val = (ubyte)multi_num_players();
2034 // add the proper flags
2036 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2037 flags |= AG_FLAG_PASSWD;
2040 // proper netgame type flags
2041 if(Netgame.type_flags & NG_TYPE_TEAM){
2042 flags |= AG_FLAG_TEAMS;
2043 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2044 flags |= AG_FLAG_DOGFIGHT;
2046 flags |= AG_FLAG_COOP;
2049 // proper netgame state flags
2050 switch(Netgame.game_state){
2051 case NETGAME_STATE_FORMING:
2052 flags |= AG_FLAG_FORMING;
2055 case NETGAME_STATE_BRIEFING:
2056 case NETGAME_STATE_MISSION_SYNC:
2057 case NETGAME_STATE_HOST_SETUP:
2058 flags |= AG_FLAG_BRIEFING;
2061 case NETGAME_STATE_IN_MISSION:
2062 flags |= AG_FLAG_IN_MISSION;
2065 case NETGAME_STATE_PAUSED:
2066 flags |= AG_FLAG_PAUSE;
2069 case NETGAME_STATE_ENDGAME:
2070 case NETGAME_STATE_DEBRIEF:
2071 flags |= AG_FLAG_DEBRIEF;
2075 // if this is a standalone
2076 if(Game_mode & GM_STANDALONE_SERVER){
2077 flags |= AG_FLAG_STANDALONE;
2080 // if we're in campaign mode
2081 if(Netgame.campaign_mode == MP_CAMPAIGN){
2082 flags |= AG_FLAG_CAMPAIGN;
2085 // add the data about the connection speed of the host machine
2086 SDL_assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2087 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2092 psnet_send(addr, data, packet_size);
2095 // process information about an active game
2096 void process_game_active_packet(ubyte* data, header* hinfo)
2101 int modes_compatible;
2103 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->net_id, hinfo->port);
2105 // read this game into a temporary structure
2106 offset = HEADER_LENGTH;
2108 // get the server version and compatible version
2109 GET_DATA(ag.version);
2110 GET_DATA(ag.comp_version);
2112 GET_STRING(ag.name);
2113 GET_STRING(ag.mission_name);
2114 GET_STRING(ag.title);
2116 ag.num_players = val;
2117 GET_USHORT(ag.flags);
2121 modes_compatible = 1;
2123 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2124 modes_compatible = 0;
2126 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2127 modes_compatible = 0;
2131 // if this is a compatible version, and our modes are compatible, register it
2132 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2133 multi_update_active_games(&ag);
2137 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2138 // is used to change the current mission, current state, etc.
2139 void send_netgame_update_packet(net_player *pl)
2143 ubyte data[MAX_PACKET_SIZE];
2146 BUILD_HEADER(GAME_UPDATE);
2148 // with new mission description field, this becomes way to large
2149 // so we must add every element piece by piece except the
2150 ADD_STRING(Netgame.name);
2151 ADD_STRING(Netgame.mission_name);
2152 ADD_STRING(Netgame.title);
2153 ADD_STRING(Netgame.campaign_name);
2154 ADD_INT(Netgame.campaign_mode);
2155 ADD_INT(Netgame.max_players);
2156 ADD_INT(Netgame.security);
2157 ADD_UINT(Netgame.respawn);
2158 ADD_INT(Netgame.flags);
2159 ADD_INT(Netgame.type_flags);
2160 ADD_INT(Netgame.version_info);
2161 ADD_DATA(Netgame.debug_flags);
2163 // only the server should ever send the netgame state (standalone situation)
2164 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2165 ADD_INT(Netgame.game_state);
2168 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2169 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2171 multi_io_send_to_all_reliable(data, packet_size);
2173 for(idx=0; idx<MAX_PLAYERS; idx++){
2174 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2175 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2179 multi_io_send_reliable(pl, data, packet_size);
2180 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2183 SDL_assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2184 multi_io_send_reliable(Net_player, data, packet_size);
2187 // host should always send a netgame options update as well
2188 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2189 multi_options_update_netgame();
2193 // process information about the netgame sent from the server/host
2194 void process_netgame_update_packet( ubyte *data, header *hinfo )
2196 int offset;//,old_flags;
2199 SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
2200 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2202 // read in the netgame information
2203 offset = HEADER_LENGTH;
2204 GET_STRING(Netgame.name);
2205 GET_STRING(Netgame.mission_name);
2206 GET_STRING(Netgame.title);
2207 GET_STRING(Netgame.campaign_name);
2208 GET_INT(Netgame.campaign_mode);
2209 GET_INT(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2210 GET_INT(Netgame.security);
2211 GET_UINT(Netgame.respawn);
2213 // be sure not to blast the quitting flag because of the "one frame extra" problem
2214 // old_flags = Netgame.flags;
2215 GET_INT(Netgame.flags);
2216 GET_INT(Netgame.type_flags);
2217 GET_INT(Netgame.version_info);
2218 GET_DATA(Netgame.debug_flags);
2225 // now compare the passed in game state to our current known state. If it has changed, then maybe
2226 // do something interesting.
2227 // move from the forming or debriefing state to the mission sync state
2228 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2229 // if coming from the forming state
2230 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2231 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2232 // do any special processing for forced state transitions
2233 multi_handle_state_special();
2235 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2236 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2237 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2239 // if coming from the debriefing state
2240 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2241 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2243 // do any special processing for forced state transitions
2244 multi_handle_state_special();
2246 multi_flush_mission_stuff();
2248 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2249 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2250 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2253 // move from mission sync to team select
2254 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2255 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2256 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2258 // do any special processing for forced state transitions
2259 multi_handle_state_special();
2261 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2262 gameseq_post_event(GS_EVENT_START_BRIEFING);
2265 // move from the debriefing to the create game screen
2266 else if ( ng_state == NETGAME_STATE_FORMING ){
2267 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2268 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2269 // do any special processing for forced state transitions
2270 multi_handle_state_special();
2272 multi_flush_mission_stuff();
2274 // move to the proper screen
2275 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2276 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2278 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2283 Netgame.game_state = ng_state;
2286 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2287 void send_netgame_descript_packet(net_addr *addr, int code)
2289 ubyte data[MAX_PACKET_SIZE],val;
2291 int packet_size = 0;
2294 BUILD_HEADER(UPDATE_DESCRIPT);
2300 // add as much of the description as we dare
2301 len = strlen(The_mission.mission_desc);
2302 if(len > MAX_PACKET_SIZE - 10){
2303 len = MAX_PACKET_SIZE - 10;
2305 memcpy(data+packet_size,The_mission.mission_desc,len);
2308 ADD_STRING(The_mission.mission_desc);
2312 SDL_assert(addr != NULL);
2314 psnet_send(addr, data, packet_size);
2318 // process an incoming netgame description packet
2319 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2323 char mission_desc[MISSION_DESC_LENGTH+2];
2326 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2328 // read this game into a temporary structure
2329 offset = HEADER_LENGTH;
2332 // if this is a request for mission description
2334 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2339 // send an update to this guy
2340 send_netgame_descript_packet(&addr, 1);
2342 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2343 GET_STRING(mission_desc);
2345 // only display if we're in the proper state
2346 state = gameseq_get_state();
2348 case GS_STATE_MULTI_JOIN_GAME:
2349 case GS_STATE_MULTI_CLIENT_SETUP:
2350 case GS_STATE_MULTI_HOST_SETUP:
2351 multi_common_set_text(mission_desc);
2359 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2360 void broadcast_game_query()
2364 server_item *s_moveup;
2365 ubyte data[MAX_PACKET_SIZE];
2367 BUILD_HEADER(GAME_QUERY);
2369 // go through the server list and query each of those as well
2370 s_moveup = Game_server_head;
2371 if(s_moveup != NULL){
2373 send_server_query(&s_moveup->server_addr);
2374 s_moveup = s_moveup->next;
2375 } while(s_moveup != Game_server_head);
2378 fill_net_addr(&addr, Psnet_my_addr.addr, Psnet_my_addr.net_id, DEFAULT_GAME_PORT);
2380 // send out a broadcast if our options allow us
2381 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2382 psnet_broadcast( &addr, data, packet_size);
2386 // send an individual query to an address to see if there is an active game
2387 void send_server_query(net_addr *addr)
2390 ubyte data[MAX_PACKET_SIZE];
2392 // build the header and send the data
2393 BUILD_HEADER(GAME_QUERY);
2394 psnet_send(addr, data, packet_size);
2397 // process a query from a client looking for active freespace games
2398 void process_game_query(ubyte* data, header* hinfo)
2403 offset = HEADER_LENGTH;
2407 // check to be sure that we don't capture our own broadcast message
2408 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2409 if ( psnet_same( &addr, &Psnet_my_addr) ){
2413 // if I am not a server of a game, don't send a reply!!!
2414 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2418 // if the game options are being selected, then ignore the request
2419 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2420 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2424 // send information about this active game
2425 send_game_active_packet(&addr);
2428 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2429 void send_netplayer_update_packet( net_player *pl )
2431 int packet_size,idx;
2432 ubyte data[MAX_PACKET_SIZE],val;
2434 BUILD_HEADER(NETPLAYER_UPDATE);
2436 // if I'm the server of the game, I should send an update for _all_players in the game
2437 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2438 for(idx=0;idx<MAX_PLAYERS;idx++){
2439 // only send info for connected players
2440 if(MULTI_CONNECTED(Net_players[idx])){
2445 // add the net player's information
2446 ADD_SHORT(Net_players[idx].player_id);
2447 ADD_INT(Net_players[idx].state);
2448 ADD_INT(Net_players[idx].p_info.ship_class);
2449 ADD_INT(Net_players[idx].tracker_player_id);
2451 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2459 // add the final stop byte
2463 // broadcast the packet
2464 if(!(Game_mode & GM_IN_MISSION)){
2466 multi_io_send_to_all_reliable(data, packet_size);
2468 multi_io_send_reliable(pl, data, packet_size);
2472 multi_io_send_to_all(data, packet_size);
2474 multi_io_send(pl, data, packet_size);
2482 // add my current state in the netgame to this packet
2483 ADD_SHORT(Net_player->player_id);
2484 ADD_INT(Net_player->state);
2485 ADD_INT(Net_player->p_info.ship_class);
2486 ADD_INT(Multi_tracker_id);
2488 // add if I have a CD or not
2496 // add a final stop byte
2500 // send the packet to the server
2501 SDL_assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2502 if(!(Game_mode & GM_IN_MISSION)){
2503 multi_io_send_reliable(Net_player, data, packet_size);
2505 multi_io_send(Net_player, data, packet_size);
2510 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2511 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2513 int offset, player_num;
2519 offset = HEADER_LENGTH;
2521 // get the first stop byte
2524 while(stop != 0xff){
2525 // look the player up
2526 GET_SHORT(player_id);
2527 player_num = find_player_id(player_id);
2528 // if we couldn't find him, read in the bogus data
2529 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2530 GET_INT(bogus.state);
2531 GET_INT(bogus.p_info.ship_class);
2532 GET_INT(bogus.tracker_player_id);
2536 // otherwise read in the data correctly
2539 GET_INT(Net_players[player_num].p_info.ship_class);
2540 GET_INT(Net_players[player_num].tracker_player_id);
2543 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2545 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2548 // if he's changing state to joined, send a team update
2549 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2550 multi_team_send_update();
2554 Net_players[player_num].state = new_state;
2557 // get the next stop byte
2563 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2564 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2565 send_netplayer_update_packet(NULL);
2568 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2569 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2570 switch(Net_players[player_num].state){
2571 case NETPLAYER_STATE_STD_HOST_SETUP:
2572 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2575 case NETPLAYER_STATE_HOST_SETUP:
2576 // check for race conditions
2577 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2578 Netgame.game_state = NETGAME_STATE_FORMING;
2585 #define EXTRA_DEATH_VAPORIZED (1<<0)
2586 #define EXTRA_DEATH_WASHED (1<<1)
2587 // send a packet indicating a ship has been killed
2588 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2590 int packet_size, model;
2591 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2592 ushort debris_signature;
2596 // only sendable from the master
2597 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2600 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2602 extra_death_info = 0;
2604 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2607 if ( Ships[objp->instance].wash_killed ) {
2608 extra_death_info |= EXTRA_DEATH_WASHED;
2611 // find out the next network signature that will be used for the debris pieces.
2612 model = Ships[objp->instance].modelnum;
2613 pm = model_get(model);
2614 debris_signature = 0;
2615 if ( pm && !vaporized ) {
2616 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2617 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2618 Ships[objp->instance].arrival_distance = debris_signature;
2621 BUILD_HEADER(SHIP_KILL);
2622 ADD_USHORT(objp->net_signature);
2624 // ships which are initially killed get the rest of the data sent. self destructed ships and
2625 if ( other_objp == NULL ) {
2630 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2632 ADD_USHORT( other_objp->net_signature );
2635 ADD_USHORT( debris_signature );
2636 ADD_FLOAT( percent_killed );
2637 sd = (ubyte)self_destruct;
2639 ADD_DATA( extra_death_info );
2641 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2643 if ( objp->flags & OF_PLAYER_SHIP ) {
2647 pnum = multi_find_player_by_object( objp );
2650 ADD_DATA( was_player );
2652 SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2653 temp = (char)Net_players[pnum].player->killer_objtype;
2656 SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2657 temp = (char)Net_players[pnum].player->killer_species;
2660 SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2661 temp = (char)Net_players[pnum].player->killer_weapon_index;
2664 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2666 ADD_DATA( was_player );
2669 ADD_DATA( was_player );
2672 // send the packet reliably!!!
2673 multi_io_send_to_all_reliable(data, packet_size);
2676 // process a packet indicating that a ship has been killed
2677 void process_ship_kill_packet( ubyte *data, header *hinfo )
2680 ushort ship_sig, other_sig, debris_sig;
2681 object *sobjp, *oobjp;
2682 float percent_killed;
2683 ubyte was_player, extra_death_info, sd;
2684 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2686 offset = HEADER_LENGTH;
2687 GET_USHORT(ship_sig);
2689 GET_USHORT( other_sig );
2690 GET_USHORT( debris_sig );
2691 GET_FLOAT( percent_killed );
2693 GET_DATA( extra_death_info );
2694 GET_DATA( was_player );
2697 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2698 if ( was_player != 0 ) {
2699 GET_DATA( killer_objtype );
2700 GET_DATA( killer_species );
2701 GET_DATA( killer_weapon_index );
2702 GET_STRING( killer_name );
2707 sobjp = multi_get_network_object( ship_sig );
2709 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2710 // another message from the server that this happened!
2711 if ( sobjp == NULL ) {
2712 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2716 // set this ship's hull value to 0
2717 sobjp->hull_strength = 0.0f;
2719 // maybe set vaporized
2720 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2721 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2724 // maybe set wash_killed
2725 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2726 Ships[sobjp->instance].wash_killed = 1;
2729 oobjp = multi_get_network_object( other_sig );
2731 if ( was_player != 0 ) {
2734 pnum = multi_find_player_by_object( sobjp );
2736 Net_players[pnum].player->killer_objtype = killer_objtype;
2737 Net_players[pnum].player->killer_species = killer_species;
2738 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2739 SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2743 // check to see if I need to respawn myself
2744 multi_respawn_check(sobjp);
2746 // store the debris signature in the arrival distance which will never get used for player ships
2747 Ships[sobjp->instance].arrival_distance = debris_sig;
2749 // set this bit so that we don't accidentally start switching targets when we die
2750 if(sobjp == Player_obj){
2751 Game_mode |= GM_DEAD_DIED;
2754 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2756 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2757 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2758 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2760 extern void ship_destroyed( int shipnum );
2761 ship_destroyed( sobjp->instance );
2762 sobjp->flags |= OF_SHOULD_BE_DEAD;
2763 obj_delete( OBJ_INDEX(sobjp) );
2767 // send a packet indicating a ship should be created
2768 void send_ship_create_packet( object *objp, int is_support )
2771 ubyte data[MAX_PACKET_SIZE];
2773 // We will pass the ship to create by name.
2774 BUILD_HEADER(SHIP_CREATE);
2775 ADD_USHORT(objp->net_signature);
2776 ADD_INT( is_support );
2778 add_vector_data(data, &packet_size, objp->pos);
2781 // broadcast the packet
2782 multi_io_send_to_all_reliable(data, packet_size);
2785 // process a packet indicating a ship should be created
2786 void process_ship_create_packet( ubyte *data, header *hinfo )
2788 int offset, objnum, is_support;
2791 vector pos = ZERO_VECTOR;
2793 SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2794 offset = HEADER_LENGTH;
2795 GET_USHORT(signature);
2796 GET_INT( is_support );
2798 get_vector_data(data, &offset, pos);
2803 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2804 if ( !is_support ) {
2805 objp = mission_parse_get_arrival_ship( signature );
2806 if ( objp != NULL ) {
2807 objnum = parse_create_object(objp);
2809 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2812 SDL_assert( Arriving_support_ship );
2813 if(Arriving_support_ship == NULL){
2816 Arriving_support_ship->pos = pos;
2817 Arriving_support_ship->net_signature = signature;
2818 objnum = parse_create_object( Arriving_support_ship );
2819 SDL_assert( objnum != -1 );
2821 mission_parse_support_arrived( objnum );
2826 // send a packet indicating a wing of ships should be created
2827 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2829 int packet_size, index, ship_instance;
2830 ubyte data[MAX_PACKET_SIZE];
2834 // for creating wing -- we just send the index into the wing array of this wing.
2835 // all players load the same mission, and so their array's should all match. We also
2836 // need to send the signature of the first ship that was created. We can find this by
2837 // looking num_to_create places back in the ship_index field in the wing structure.
2839 index = WING_INDEX(wingp);
2840 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2841 signature = Objects[Ships[ship_instance].objnum].net_signature;
2843 BUILD_HEADER( WING_CREATE );
2845 ADD_INT(num_to_create);
2846 ADD_USHORT(signature);
2847 ADD_INT(pre_create_count);
2848 val = wingp->current_wave - 1;
2851 multi_io_send_to_all_reliable(data, packet_size);
2854 // process a packet saying that a wing should be created
2855 void process_wing_create_packet( ubyte *data, header *hinfo )
2857 int offset, index, num_to_create;
2859 int total_arrived_count, current_wave;
2861 offset = HEADER_LENGTH;
2863 GET_INT(num_to_create);
2864 GET_USHORT(signature);
2865 GET_INT(total_arrived_count);
2866 GET_INT(current_wave);
2870 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2871 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2872 nprintf(("Network", "invalid index %d for wing create packet\n"));
2875 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2876 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2881 Wings[index].current_count = 0;
2882 Wings[index].total_arrived_count = total_arrived_count;
2883 Wings[index].current_wave = current_wave;
2885 // set the network signature that was passed. The client should create ships in the same order
2886 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2887 // need to set some timestamps and cues correctly to be sure that these things get created on
2888 // the clients correctly
2889 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2890 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2893 // packet indicating a ship is departing
2894 void send_ship_depart_packet( object *objp )
2896 ubyte data[MAX_PACKET_SIZE];
2900 signature = objp->net_signature;
2902 BUILD_HEADER(SHIP_DEPART);
2903 ADD_USHORT( signature );
2905 multi_io_send_to_all_reliable(data, packet_size);
2908 // process a packet indicating a ship is departing
2909 void process_ship_depart_packet( ubyte *data, header *hinfo )
2915 offset = HEADER_LENGTH;
2916 GET_USHORT( signature );
2919 // find the object which is departing
2920 objp = multi_get_network_object( signature );
2921 if ( objp == NULL ) {
2922 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2926 // start warping him out
2927 shipfx_warpout_start( objp );
2930 // packet to tell clients cargo of a ship was revealed to all
2931 void send_cargo_revealed_packet( ship *shipp )
2933 ubyte data[MAX_PACKET_SIZE];
2936 // build the header and add the data
2937 BUILD_HEADER(CARGO_REVEALED);
2938 ADD_USHORT( Objects[shipp->objnum].net_signature );
2940 // server sends to all players
2941 if(MULTIPLAYER_MASTER){
2942 multi_io_send_to_all_reliable(data, packet_size);
2944 // clients just send to the server
2946 multi_io_send_reliable(Net_player, data, packet_size);
2950 // process a cargo revealed packet
2951 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2957 offset = HEADER_LENGTH;
2958 GET_USHORT(signature);
2961 // get a ship pointer and call the ship function to reveal the cargo
2962 objp = multi_get_network_object( signature );
2963 if ( objp == NULL ) {
2964 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2968 // SDL_assert( objp->type == OBJ_SHIP );
2969 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2973 // this will take care of re-routing to all other clients
2974 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2976 // server should rebroadcast
2977 if(MULTIPLAYER_MASTER){
2978 send_cargo_revealed_packet(&Ships[objp->instance]);
2982 // defines used for secondary fire packet
2983 #define SFPF_ALLOW_SWARM (1<<7)
2984 #define SFPF_DUAL_FIRE (1<<6)
2985 #define SFPF_TARGET_LOCKED (1<<5)
2987 // send a packet indicating a secondary weapon was fired
2988 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2990 int packet_size, net_player_num;
2991 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2993 ushort target_signature;
2997 // SDL_assert ( starting_count < UCHAR_MAX );
2999 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
3000 // we might send the info to the other player different than the one who fired
3001 objp = &Objects[shipp->objnum];
3002 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3003 if ( num_fired == 0 ) {
3008 aip = &Ai_info[shipp->ai_index];
3010 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3011 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3013 // build up the header portion
3014 BUILD_HEADER( SECONDARY_FIRED_AI );
3016 ADD_USHORT( Objects[shipp->objnum].net_signature );
3017 ADD_USHORT( starting_sig );
3019 // add a couple of bits for swarm missiles and dual fire secondary weaspons
3022 sinfo = current_bank;
3025 sinfo |= SFPF_ALLOW_SWARM;
3028 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3029 sinfo |= SFPF_DUAL_FIRE;
3032 if ( aip->current_target_is_locked ){
3033 sinfo |= SFPF_TARGET_LOCKED;
3038 // add the ship's target and any targeted subsystem
3039 target_signature = 0;
3041 if ( aip->target_objnum != -1) {
3042 target_signature = Objects[aip->target_objnum].net_signature;
3043 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3046 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3047 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
3048 t_subsys = (char)s_index;
3051 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3052 SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3057 ADD_USHORT( target_signature );
3058 ADD_DATA( t_subsys );
3060 // just send this packet to everyone, then bail if an AI ship fired.
3061 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3062 multi_io_send_to_all(data, packet_size);
3066 net_player_num = multi_find_player_by_object( objp );
3068 // getting here means a player fired. Send the current packet to all players except the player
3069 // who fired. If nothing got fired, then don't send to the other players -- we will just send
3070 // a packet to the player who will find out that he didn't fire anything
3071 if ( num_fired > 0 ) {
3072 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3075 // if I (the master) fired, then return
3076 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3080 // now build up the packet to send to the player who actually fired.
3081 BUILD_HEADER( SECONDARY_FIRED_PLR );
3082 ADD_USHORT(starting_sig);
3085 // add the targeting information so that the player's weapons will always home on the correct
3087 ADD_USHORT( target_signature );
3088 ADD_DATA( t_subsys );
3090 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3093 /// process a packet indicating a secondary weapon was fired
3094 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3096 int offset, allow_swarm, target_objnum_save;
3097 ushort net_signature, starting_sig, target_signature;
3098 ubyte sinfo, current_bank;
3099 object* objp, *target_objp;
3103 ship_subsys *targeted_subsys_save;
3105 offset = HEADER_LENGTH; // size of the header
3107 // if from_player is false, it means that the secondary weapon info in this packet was
3108 // fired by an ai object (or another player). from_player == 1 means tha me (the person
3109 // receiving this packet) fired the secondary weapon
3110 if ( !from_player ) {
3111 GET_USHORT( net_signature );
3112 GET_USHORT( starting_sig );
3113 GET_DATA( sinfo ); // are we firing swarm missiles
3115 GET_USHORT( target_signature );
3116 GET_DATA( t_subsys );
3120 // find the object (based on network signatures) for the object that fired
3121 objp = multi_get_network_object( net_signature );
3122 if ( objp == NULL ) {
3123 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3127 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3128 // of the next fire time of this bank to 0 so we can fire right away
3129 shipp = &Ships[objp->instance];
3132 GET_USHORT( starting_sig );
3135 GET_USHORT( target_signature );
3136 GET_DATA( t_subsys );
3140 // get the object and ship
3142 shipp = Player_ship;
3145 // check the allow swarm bit
3147 if ( sinfo & SFPF_ALLOW_SWARM ){
3151 // set the dual fire properties of the ship
3152 if ( sinfo & SFPF_DUAL_FIRE ){
3153 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3155 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3158 // determine whether current target is locked
3159 SDL_assert( shipp->ai_index != -1 );
3160 aip = &Ai_info[shipp->ai_index];
3161 if ( sinfo & SFPF_TARGET_LOCKED ) {
3162 aip->current_target_is_locked = 1;
3164 aip->current_target_is_locked = 0;
3167 // find out the current bank
3168 current_bank = (ubyte)(sinfo & 0x3);
3169 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3170 shipp->weapons.current_secondary_bank = current_bank;
3172 // make it so we can fire this ship's secondary bank immediately!!!
3173 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3174 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3176 // set this ship's target and subsystem information. We will save and restore target and
3177 // targeted subsystem so that we do not accidentally change targets for this player or
3178 // any AI ships on his system.
3179 target_objnum_save = aip->target_objnum;
3180 targeted_subsys_save = aip->targeted_subsys;
3182 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3183 aip->target_objnum = -1;
3184 aip->targeted_subsys = NULL;
3186 target_objp = multi_get_network_object( target_signature );
3187 if ( target_objp != NULL ) {
3188 aip->target_objnum = OBJ_INDEX(target_objp);
3190 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3191 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3195 if ( starting_sig != 0 ){
3196 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3198 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3201 ship_fire_secondary( objp, allow_swarm );
3203 // restore targeted object and targeted subsystem
3204 aip->target_objnum = target_objnum_save;
3205 aip->targeted_subsys = targeted_subsys_save;
3208 // send a packet indicating a countermeasure was fired
3209 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3211 ubyte data[MAX_PACKET_SIZE];
3216 SDL_assert ( cmeasure_count < UCHAR_MAX );
3217 BUILD_HEADER(COUNTERMEASURE_FIRED);
3218 ADD_USHORT( objp->net_signature );
3219 ADD_INT( rand_val );
3221 multi_io_send_to_all(data, packet_size);
3224 // process a packet indicating a countermeasure was fired
3225 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3227 int offset, rand_val;
3233 offset = HEADER_LENGTH;
3235 GET_USHORT( signature );
3236 GET_INT( rand_val );
3239 objp = multi_get_network_object( signature );
3240 if ( objp == NULL ) {
3241 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3244 if(objp->type != OBJ_SHIP){
3247 // SDL_assert ( objp->type == OBJ_SHIP );
3249 // make it so ship can fire right away!
3250 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3251 if ( objp == Player_obj ){
3252 nprintf(("network", "firing countermeasure from my ship\n"));
3255 ship_launch_countermeasure( objp, rand_val );
3258 // send a packet indicating that a turret has been fired
3259 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3262 ushort pnet_signature;
3263 ubyte data[MAX_PACKET_SIZE], cindex;
3270 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3274 // local setup -- be sure we are actually passing a weapon!!!!
3275 objp = &Objects[weapon_objnum];
3276 SDL_assert ( objp->type == OBJ_WEAPON );
3277 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3281 pnet_signature = Objects[ship_objnum].net_signature;
3283 SDL_assert( subsys_index < UCHAR_MAX );
3284 cindex = (ubyte)subsys_index;
3286 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3291 // build the fire turret packet.
3292 BUILD_HEADER(FIRE_TURRET_WEAPON);
3293 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3294 ADD_DATA( has_sig );
3295 ADD_USHORT( pnet_signature );
3297 ADD_USHORT( objp->net_signature );
3300 val = (short)ssp->submodel_info_1.angs.h;
3302 val = (short)ssp->submodel_info_2.angs.p;
3305 multi_io_send_to_all(data, packet_size);
3307 multi_rate_add(1, "tur", packet_size);
3310 // process a packet indicating a turret has been fired
3311 void process_turret_fired_packet( ubyte *data, header *hinfo )
3313 int offset, weapon_objnum, wid;
3314 ushort pnet_signature, wnet_signature;
3323 short pitch, heading;
3325 // get the data for the turret fired packet
3326 offset = HEADER_LENGTH;
3327 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3328 GET_DATA( has_sig );
3329 GET_USHORT( pnet_signature );
3331 GET_USHORT( wnet_signature );
3335 GET_DATA( turret_index );
3336 GET_SHORT( heading );
3338 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3341 objp = multi_get_network_object( pnet_signature );
3342 if ( objp == NULL ) {
3343 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3347 // if this isn't a ship, do nothing
3348 if ( objp->type != OBJ_SHIP ){
3352 // make an orientation matrix from the o_fvec
3353 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3355 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3356 // hack, but should be suitable.
3357 shipp = &Ships[objp->instance];
3358 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3362 wid = ssp->system_info->turret_weapon_type;
3364 // bash the position and orientation of the turret
3365 ssp->submodel_info_1.angs.h = (float)heading;
3366 ssp->submodel_info_2.angs.p = (float)pitch;
3368 // get the world position of the weapon
3369 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3371 // create the weapon object
3372 if(wnet_signature != 0){
3373 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3375 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3376 if (weapon_objnum != -1) {
3377 if ( Weapon_info[wid].launch_snd != -1 ) {
3378 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3383 // send a mission log item packet
3384 void send_mission_log_packet( int num )
3387 ubyte data[MAX_PACKET_SIZE];
3392 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3394 // get the data from the log
3395 entry = &log_entries[num];
3396 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3397 sindex = (ushort)entry->index;
3399 BUILD_HEADER(MISSION_LOG_ENTRY);
3401 ADD_INT(entry->flags);
3403 ADD_DATA(entry->timestamp);
3404 ADD_STRING(entry->pname);
3405 ADD_STRING(entry->sname);
3407 // broadcast the packet to all players
3408 multi_io_send_to_all_reliable(data, packet_size);
3411 // process a mission log item packet
3412 void process_mission_log_packet( ubyte *data, header *hinfo )
3417 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3420 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3422 offset = HEADER_LENGTH;
3426 GET_DATA(timestamp);
3432 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3435 // send a mission message packet
3436 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)
3439 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3441 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3442 SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3443 SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3445 up = (ubyte) priority;
3446 us = (ubyte) source;
3447 utime = (ubyte)timing;
3449 BUILD_HEADER(MISSION_MESSAGE);
3451 ADD_STRING(who_from);
3455 ADD_INT(builtin_type);
3456 ADD_INT(multi_team_filter);
3458 if (multi_target == -1){
3459 multi_io_send_to_all_reliable(data, packet_size);
3461 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3465 // process a mission message packet
3466 void process_mission_message_packet( ubyte *data, header *hinfo )
3468 int offset, id, builtin_type;
3469 ubyte priority, source, utiming;
3470 char who_from[NAME_LENGTH];
3471 int multi_team_filter;
3473 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3475 offset = HEADER_LENGTH;
3477 GET_STRING(who_from);
3481 GET_INT(builtin_type);
3482 GET_INT(multi_team_filter);
3486 // filter out builtin ones in TvT
3487 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3491 // maybe filter this out
3492 if(!message_filter_multi(id)){
3493 // send the message as if it came from an sexpression
3494 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3498 // just send them a pong back as fast as possible
3499 void process_ping_packet(ubyte *data, header *hinfo)
3504 offset = HEADER_LENGTH;
3507 // get the address to return the pong to
3508 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3514 // right now it just routes the pong through to the standalone gui, which is the only
3515 // system which uses ping and pong right now.
3516 void process_pong_packet(ubyte *data, header *hinfo)
3522 offset = HEADER_LENGTH;
3524 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3528 // if we're connected , see who sent us this pong
3529 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3530 lookup = find_player_id(hinfo->id);
3535 p = &Net_players[lookup];
3537 // evaluate the ping
3538 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3540 // put in calls to any functions which may want to know about the ping times from
3542 if(Game_mode & GM_STANDALONE_SERVER){
3543 std_update_player_ping(p);
3546 // mark his socket as still alive (extra precaution)
3547 psnet_mark_received(Net_players[lookup].reliable_socket);
3549 // otherwise, do any special processing
3551 // if we're in the join game state, see if this pong came from a server on our
3553 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3554 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3559 // send a ping packet
3560 void send_ping(net_addr *addr)
3562 unsigned char data[8];
3565 // build the header and send the packet
3566 BUILD_HEADER( PING );
3567 psnet_send(addr, &data[0], packet_size);
3570 // send a pong packet
3571 void send_pong(net_addr *addr)
3573 unsigned char data[8];
3576 // build the header and send the packet
3578 psnet_send(addr, &data[0], packet_size);
3581 // sent from host to master. give me the list of missions you have.
3582 // this will be used only in a standalone mode
3583 void send_mission_list_request( int what )
3585 ubyte data[MAX_PACKET_SIZE];
3588 // build the header and ask for a list of missions or campaigns (depending
3589 // on the 'what' flag).
3590 BUILD_HEADER(MISSION_REQUEST);
3592 multi_io_send_reliable(Net_player, data, packet_size);
3595 // maximum number of bytes that we can send in a mission items packet.
3596 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3598 // defines used to tell what type of packets are being sent
3599 #define MISSION_LIST_ITEMS 1
3600 #define CAMPAIGN_LIST_ITEMS 2
3602 // send an individual mission file item
3603 void send_mission_items( net_player *pl )
3605 ubyte data[MAX_PACKET_SIZE];
3610 BUILD_HEADER(MISSION_ITEM);
3612 // send the list of missions and campaigns avilable on the server. Stop when
3613 // reaching a certain maximum
3614 type = MISSION_LIST_ITEMS;
3616 for (i = 0; i < Multi_create_mission_count; i++ ) {
3620 ADD_STRING( Multi_create_mission_list[i].filename );
3621 ADD_STRING( Multi_create_mission_list[i].name );
3622 ADD_INT( Multi_create_mission_list[i].flags );
3623 ADD_DATA( Multi_create_mission_list[i].max_players );
3624 ADD_UINT( Multi_create_mission_list[i].respawn );
3627 ADD_DATA( Multi_create_mission_list[i].valid_status );
3629 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3632 multi_io_send_reliable(pl, data, packet_size);
3633 BUILD_HEADER( MISSION_ITEM );
3639 multi_io_send_reliable(pl, data, packet_size);
3641 // send the campaign information
3642 type = CAMPAIGN_LIST_ITEMS;
3643 BUILD_HEADER(MISSION_ITEM);
3645 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3649 ADD_STRING( Multi_create_campaign_list[i].filename );
3650 ADD_STRING( Multi_create_campaign_list[i].name );
3651 ADD_INT( Multi_create_campaign_list[i].flags );
3652 ADD_DATA( Multi_create_campaign_list[i].max_players );
3654 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3657 multi_io_send_reliable(pl, data, packet_size);
3658 BUILD_HEADER( MISSION_ITEM );
3664 multi_io_send_reliable(pl, data, packet_size);
3667 // process a request for a list of missions
3668 void process_mission_request_packet(ubyte *data, header *hinfo)
3670 int player_num,offset;
3672 offset = HEADER_LENGTH;
3675 // fill in the address information of where this came from
3676 player_num = find_player_id(hinfo->id);
3677 if(player_num == -1){
3678 nprintf(("Network","Could not find player to send mission list items to!\n"));
3682 send_mission_items( &Net_players[player_num] );
3685 // process an individual mission file item
3686 void process_mission_item_packet(ubyte *data,header *hinfo)
3689 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3690 ubyte stop, type,max_players;
3693 SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3694 offset = HEADER_LENGTH;
3699 GET_STRING( filename );
3702 GET_DATA( max_players );
3704 // missions also have respawns and a crc32 associated with them
3705 if(type == MISSION_LIST_ITEMS){
3709 GET_DATA(valid_status);
3711 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3712 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3713 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3714 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3715 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3716 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3719 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3721 Multi_create_mission_count++;
3723 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3724 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3725 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3726 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3727 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3728 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3729 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3730 Multi_create_campaign_count++;
3739 // this will cause whatever list to get resorted (although they should be appearing in order)
3740 multi_create_setup_list_data(-1);
3743 // send a request to the server to pause or unpause the game
3744 void send_multi_pause_packet(int pause)
3746 ubyte data[MAX_PACKET_SIZE];
3748 int packet_size = 0;
3750 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3753 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3754 val = (ubyte) pause;
3756 // add the pause info
3759 // send the request to the server
3760 multi_io_send_reliable(Net_player, data, packet_size);
3763 // process a pause update packet (pause, unpause, etc)
3764 void process_multi_pause_packet(ubyte *data, header *hinfo)
3770 offset = HEADER_LENGTH;
3776 // get who sent the packet
3777 player_index = find_player_id(hinfo->id);
3778 // if we don't know who sent the packet, don't do anything
3779 if(player_index == -1){
3783 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3784 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3787 // send a game information update
3788 void send_game_info_packet()
3791 ubyte data[MAX_PACKET_SIZE], paused;
3793 // set the paused variable
3794 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3796 BUILD_HEADER(GAME_INFO);
3797 ADD_INT( Missiontime );
3800 multi_io_send_to_all(data, packet_size);
3803 // process a game information update
3804 void process_game_info_packet( ubyte *data, header *hinfo )
3810 offset = HEADER_LENGTH;
3812 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3813 // time, set our time to server time (should take ping time into account!!!)
3814 GET_DATA( mission_time );
3819 // send an ingame nak packet
3820 void send_ingame_nak(int state, net_player *p)
3822 ubyte data[MAX_PACKET_SIZE];
3825 BUILD_HEADER(INGAME_NAK);
3829 multi_io_send_reliable(p, data, packet_size);
3832 // process an ingame nak packet
3833 void process_ingame_nak(ubyte *data, header *hinfo)
3835 int offset,state,pid;
3838 offset = HEADER_LENGTH;
3842 pid = find_player_id(hinfo->id);
3846 pl = &Net_players[pid];
3849 case ACK_FILE_ACCEPTED :
3850 SDL_assert(pl->flags & NETINFO_FLAG_INGAME_JOIN);
3851 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3852 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3857 // send a packet telling players to end the mission
3858 void send_endgame_packet(net_player *pl)
3860 ubyte data[MAX_PACKET_SIZE];
3864 BUILD_HEADER(MISSION_END);
3866 // sending to a specific player?
3868 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3869 multi_io_send_reliable(pl, data, packet_size);
3873 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3874 // send all player stats here
3875 multi_broadcast_stats(STATS_MISSION);
3877 // if in dogfight mode, send all dogfight stats as well
3878 ml_string("Before dogfight stats!");
3879 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3880 ml_string("Sending dogfight stats!");
3882 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3884 ml_string("After dogfight stats!");
3886 // tell everyone to leave the game
3887 multi_io_send_to_all_reliable(data, packet_size);
3889 multi_io_send_reliable(Net_player, data, packet_size);
3893 // process a packet indicating we should end the current mission
3894 void process_endgame_packet(ubyte *data, header *hinfo)
3899 offset = HEADER_LENGTH;
3903 ml_string("Receiving endgame packet");
3905 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3906 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3907 // determine who this came from and make sure he is allowed to end the game
3908 player_num = find_player_id(hinfo->id);
3909 SDL_assert(player_num != -1);
3914 // if the player is allowed to end the mission
3915 if(!multi_can_end_mission(&Net_players[player_num])){
3919 // act as if we hit alt+j locally
3920 multi_handle_end_mission_request();
3922 // all clients process immediately
3924 // ingame joiners should quit when they receive an endgame packet since the game is over
3925 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3926 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3930 // do any special processing for being in a state other than the gameplay state
3931 multi_handle_state_special();
3933 // make sure we're not already in the debrief state
3934 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3935 multi_warpout_all_players();
3940 // send a position/orientation update for myself (if I'm an observer)
3941 void send_observer_update_packet()
3943 ubyte data[MAX_PACKET_SIZE];
3948 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3949 // to send any update packets to anyone.
3950 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3954 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3960 BUILD_HEADER(OBSERVER_UPDATE);
3962 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3964 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3967 // add targeting infomation
3968 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3969 target_sig = Objects[Player_ai->target_objnum].net_signature;
3973 ADD_USHORT(target_sig);
3975 multi_io_send(Net_player, data, packet_size);
3978 // process a position/orientation update from an observer
3979 void process_observer_update_packet(ubyte *data, header *hinfo)
3985 physics_info bogus_pi;
3988 offset = HEADER_LENGTH;
3990 obs_num = find_player_id(hinfo->id);
3992 memset(&bogus_pi,0,sizeof(physics_info));
3993 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3995 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3998 // targeting information
3999 GET_USHORT(target_sig);
4002 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
4006 // set targeting info
4007 if(target_sig == 0){
4008 Net_players[obs_num].s_info.target_objnum = -1;
4010 target_obj = multi_get_network_object(target_sig);
4011 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4014 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4015 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4016 Net_players[obs_num].s_info.eye_pos = g_vec;
4017 Net_players[obs_num].s_info.eye_orient = g_mat;
4020 void send_netplayer_slot_packet()
4022 ubyte data[MAX_PACKET_SIZE];
4023 int packet_size,idx;
4028 BUILD_HEADER(NETPLAYER_SLOTS_P);
4029 for(idx=0;idx<MAX_PLAYERS;idx++){
4030 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4032 ADD_SHORT(Net_players[idx].player_id);
4033 ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4034 ADD_INT(Net_players[idx].p_info.ship_class);
4035 ADD_INT(Net_players[idx].p_info.ship_index);
4041 // standalone case or not
4042 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
4043 multi_io_send_to_all_reliable(data, packet_size);
4045 multi_io_send_reliable(Net_player, data, packet_size);
4049 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4052 int player_num,ship_class,ship_index;
4058 offset = HEADER_LENGTH;
4060 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4061 multi_untag_player_ships();
4065 GET_SHORT(player_id);
4066 GET_USHORT(net_sig);
4067 GET_INT(ship_class);
4068 GET_INT(ship_index);
4069 player_num = find_player_id(player_id);
4071 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4073 // call the function in multiutil.cpp to set up the player object stuff
4074 // being careful not to muck with the standalone object
4075 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4076 objp = multi_get_network_object(net_sig);
4077 SDL_assert(objp != NULL);
4078 multi_assign_player_ship( player_num, objp, ship_class );
4079 Net_players[player_num].p_info.ship_index = ship_index;
4080 objp->flags &= ~(OF_COULD_BE_PLAYER);
4081 objp->flags |= OF_PLAYER_SHIP;
4088 // standalone should forward the packet and wait for a response
4089 if(Game_mode & GM_STANDALONE_SERVER){
4090 send_netplayer_slot_packet();
4093 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4094 send_netplayer_update_packet();
4097 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4098 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4099 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4100 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4102 ubyte data[MAX_PACKET_SIZE], utmp;
4105 BUILD_HEADER(SHIP_WSTATE_CHANGE);
4106 ADD_USHORT( Objects[shipp->objnum].net_signature );
4107 utmp = (ubyte)(what);
4109 utmp = (ubyte)(new_bank);
4111 utmp = (ubyte)(link_status);
4114 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4115 multi_io_send_to_all_reliable(data, packet_size);
4118 void process_ship_weapon_change( ubyte *data, header *hinfo )
4122 ubyte what, new_bank, link_status;
4126 offset = HEADER_LENGTH;
4127 GET_USHORT( signature );
4129 GET_DATA( new_bank );
4130 GET_DATA( link_status );
4133 objp = multi_get_network_object( signature );
4134 if ( objp == NULL ) {
4135 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4138 // SDL_assert( objp->type == OBJ_SHIP );
4139 if(objp->type != OBJ_SHIP){
4143 // if this is my data, do nothing since I already have my own data
4144 if ( objp == Player_obj ){
4148 // now, get the ship and set the new bank and link modes based on the 'what' value
4149 shipp = &Ships[objp->instance];
4150 if ( what == MULTI_PRIMARY_CHANGED ) {
4151 shipp->weapons.current_primary_bank = new_bank;
4153 shipp->flags |= SF_PRIMARY_LINKED;
4155 shipp->flags &= ~SF_PRIMARY_LINKED;
4158 shipp->weapons.current_secondary_bank = new_bank;
4160 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4162 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4167 // ship status change procedure
4168 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4170 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4171 // for added redundancy.
4172 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4173 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4174 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4175 // back to the client. Also sends multiple times for redundancy
4176 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4177 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4178 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4180 #define SHIP_STATUS_REPEAT 2
4181 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4184 ubyte data[MAX_PACKET_SIZE];
4185 int packet_size = 0;
4191 BUILD_HEADER(SHIP_STATUS_CHANGE);
4193 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4194 temp = bi->status[idx];
4198 // server should send reliably (response packet)
4199 if(MULTIPLAYER_MASTER){
4200 multi_io_send_reliable(pl, data, packet_size);
4202 multi_io_send(pl, data, packet_size);
4206 void process_ship_status_packet(ubyte *data, header *hinfo)
4210 int player_num,unique_id;
4214 offset = HEADER_LENGTH;
4216 // zero out the button info structure for good measure
4217 memset(&bi,0,sizeof(button_info));
4219 // read the button-info
4222 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4224 bi.status[idx] = i_tmp;
4229 // this will be handled differently client and server side. Duh.
4230 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4231 // find which net-player has sent us butotn information
4232 player_num = find_player_id(hinfo->id);
4233 SDL_assert(player_num >= 0);
4238 // don't process critical button information for observers
4239 // its a new button_info for this guy. apply and ack
4240 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4241 // mark that he's pressed this button
4242 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4244 // send a return packet
4245 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4247 // apply the button presses to his ship as normal
4248 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4250 // else ignore it as a repeat from the same guy
4251 } else { // CLIENT SIDE
4252 // this is the return from the server, so we should now apply them locally
4253 // if(lookup_ship_status(Net_player,unique_id,1)){
4254 multi_apply_ship_status(Net_player, &bi, 1);
4259 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4260 // for clients. Left all details to this function instead of higher level messaging
4262 void send_player_order_packet(int type, int index, int cmd)
4264 ubyte data[MAX_PACKET_SIZE];
4266 ushort target_signature;
4268 int packet_size = 0;
4270 BUILD_HEADER(PLAYER_ORDER_PACKET);
4273 ADD_DATA(val); // ship order or wing order, or message all fighters
4275 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4276 if ( val != SQUAD_MSG_ALL ){
4277 ADD_INT(index); // net signature of target ship
4280 ADD_INT(cmd); // the command itself
4283 target_signature = 0;
4284 if ( Player_ai->target_objnum != -1 ){
4285 target_signature = Objects[Player_ai->target_objnum].net_signature;
4288 ADD_USHORT( target_signature );
4291 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4294 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4295 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
4296 t_subsys = (char)s_index;
4300 multi_io_send_reliable(Net_player, data, packet_size);
4303 // brief explanation :
4304 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4305 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4306 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4307 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4308 void process_player_order_packet(ubyte *data, header *hinfo)
4310 int offset, player_num, command, index = 0, tobjnum_save;
4311 ushort target_signature;
4312 char t_subsys, type;
4313 object *objp, *target_objp;
4316 ship_subsys *tsubsys_save, *targeted_subsys;
4318 SDL_assert(MULTIPLAYER_MASTER);
4320 // packet values - its easier to read all of these in first
4322 offset = HEADER_LENGTH;
4325 if ( type != SQUAD_MSG_ALL ){
4330 GET_USHORT( target_signature );
4331 GET_DATA( t_subsys );
4335 player_num = find_player_id(hinfo->id);
4336 if(player_num == -1){
4337 nprintf(("Network","Received player order packet from unknown player\n"));
4341 objp = &Objects[Net_players[player_num].player->objnum];
4342 if ( objp->type != OBJ_SHIP ) {
4343 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4347 // HACK HACK HACK HACK HACK HACK
4348 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4349 // the data is BOGUS. All people should be able to to these things as well.
4350 if(command == REARM_REPAIR_ME_ITEM){
4351 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4353 } else if(command == ABORT_REARM_REPAIR_ITEM){
4354 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4358 // if this player is not allowed to do messaging, quit here
4359 if( !multi_can_message(&Net_players[player_num]) ){
4360 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4364 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4365 // then call them in.
4366 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4367 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4368 hud_squadmsg_call_reinforcement(index, player_num);
4372 // set the player's ai information here
4373 shipp = &Ships[objp->instance];
4374 aip = &Ai_info[shipp->ai_index];
4376 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4377 target_objp = multi_get_network_object( target_signature );
4378 if ( target_objp == NULL ) {
4382 targeted_subsys = NULL;
4383 if ( t_subsys != -1 ) {
4384 SDL_assert( target_objp != NULL );
4385 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4388 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4390 tobjnum_save = aip->target_objnum;
4391 tsubsys_save = aip->targeted_subsys;
4393 if ( target_objp ) {
4394 aip->target_objnum = OBJ_INDEX(target_objp);
4396 aip->target_objnum = -1;
4399 aip->targeted_subsys = targeted_subsys;
4401 if ( type == SQUAD_MSG_SHIP ) {
4402 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4403 } else if ( type == SQUAD_MSG_WING ) {
4404 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4405 } else if ( type == SQUAD_MSG_ALL ) {
4406 hud_squadmsg_send_to_all_fighters( command, player_num );
4409 SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4410 aip->target_objnum = tobjnum_save;
4411 aip->targeted_subsys = tsubsys_save;
4414 // FILE SIGNATURE stuff :
4415 // there are 2 cases for file signature sending which are handled very differently
4416 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4417 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4418 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4419 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4420 // would have to keep track of up to potentially 14 other ack handles (ouch).
4421 void send_file_sig_packet(ushort sum_sig,int length_sig)
4423 ubyte data[MAX_PACKET_SIZE];
4424 int packet_size = 0;
4426 BUILD_HEADER(FILE_SIG_INFO);
4427 ADD_USHORT(sum_sig);
4428 ADD_INT(length_sig);
4430 multi_io_send_reliable(Net_player, data, packet_size);
4433 void process_file_sig_packet(ubyte *data, header *hinfo)
4438 offset = HEADER_LENGTH;
4440 // should only be received on the server-side
4441 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4443 GET_USHORT(sum_sig);
4444 GET_INT(length_sig);
4446 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4449 void send_file_sig_request(char *file_name)
4451 ubyte data[MAX_PACKET_SIZE];
4452 int packet_size = 0;
4454 BUILD_HEADER(FILE_SIG_REQUEST);
4455 ADD_STRING(file_name);
4457 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4459 multi_io_send_to_all_reliable(data, packet_size);
4462 void process_file_sig_request(ubyte *data, header *hinfo)
4464 int offset = HEADER_LENGTH;
4466 // get the mission name
4467 GET_STRING(Netgame.mission_name);
4470 // set the current mission filename
4471 SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, sizeof(Game_current_mission_filename));
4474 multi_get_mission_checksum(Game_current_mission_filename);
4476 if(!multi_endgame_ending()){
4477 // reply to the server
4478 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4482 // functions to deal with subsystems getting whacked
4483 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4485 ubyte data[MAX_PACKET_SIZE];
4488 vector tmp, local_hitpos;
4491 SDL_assert ( index < UCHAR_MAX );
4492 uindex = (ubyte)(index);
4494 objp = &Objects[shipp->objnum];
4496 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4497 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4499 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4500 ADD_USHORT( Objects[shipp->objnum].net_signature );
4502 // ADD_DATA( local_hitpos );
4503 add_vector_data(data, &packet_size, local_hitpos);
4505 multi_io_send_to_all_reliable(data, packet_size);
4508 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4514 vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4516 offset = HEADER_LENGTH;
4518 GET_USHORT( signature );
4520 // GET_DATA( local_hit_pos );
4521 get_vector_data(data, &offset, local_hit_pos);
4523 // get the network object. process it if we find it.
4524 objp = multi_get_network_object( signature );
4525 if ( objp != NULL ) {
4527 ship_subsys *subsysp;
4529 // be sure we have a ship!!!
4530 // SDL_assert ( objp->type == OBJ_SHIP );
4531 if(objp->type != OBJ_SHIP){
4536 shipp = &Ships[objp->instance];
4538 // call to get the pointer to the subsystem we should be working on
4539 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4540 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4541 vm_vec_add2( &world_hit_pos, &objp->pos );
4543 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4544 if ( objp == Player_obj ) {
4545 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4553 // packet to tell clients cargo of a ship was revealed to all
4554 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4556 ubyte data[MAX_PACKET_SIZE], uindex;
4559 SDL_assert ( index < UCHAR_MAX );
4560 uindex = (ubyte)(index);
4562 // build the header and add the data
4563 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4564 ADD_USHORT( Objects[shipp->objnum].net_signature );
4567 // server sends to all players
4568 if(MULTIPLAYER_MASTER){
4569 multi_io_send_to_all_reliable(data, packet_size);
4571 // clients just send to the server
4573 multi_io_send_reliable(Net_player, data, packet_size);
4577 // process a subsystem cargo revealed packet
4578 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4585 ship_subsys *subsysp;
4587 offset = HEADER_LENGTH;
4588 GET_USHORT( signature );
4592 // get a ship pointer and call the ship function to reveal the cargo
4593 objp = multi_get_network_object( signature );
4594 if ( objp == NULL ) {
4595 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4599 // SDL_assert( objp->type == OBJ_SHIP );
4600 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4604 shipp = &Ships[objp->instance];
4606 // call to get the pointer to the subsystem we should be working on
4607 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4608 if (subsysp == NULL) {
4609 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4613 // this will take care of re-routing to all other clients
4614 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4615 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4617 // server should rebroadcast
4618 if(MULTIPLAYER_MASTER){
4619 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4623 void send_netplayer_load_packet(net_player *pl)
4625 ubyte data[MAX_PACKET_SIZE];
4626 int packet_size = 0;
4628 BUILD_HEADER(LOAD_MISSION_NOW);
4629 ADD_STRING(Netgame.mission_name);
4632 multi_io_send_to_all_reliable(data, packet_size);
4634 multi_io_send_reliable(pl, data, packet_size);
4638 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4641 int offset = HEADER_LENGTH;
4646 SDL_strlcpy(Netgame.mission_name, str, sizeof(Netgame.mission_name));
4647 SDL_strlcpy(Game_current_mission_filename, str, sizeof(Game_current_mission_filename));
4648 if(!Multi_mission_loaded){
4650 // MWA 2/3/98 -- ingame join changes!!!
4651 // everyone can go through the same mission loading path here!!!!
4652 nprintf(("Network","Loading mission..."));
4654 // notify everyone that I'm loading the mission
4655 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4656 send_netplayer_update_packet();
4658 // do the load itself
4659 game_start_mission();
4661 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4662 // code will remark the correct player ships
4663 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4664 multi_untag_player_ships();
4667 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4668 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4669 send_netplayer_update_packet();
4671 Multi_mission_loaded = 1;
4672 nprintf(("Network","Finished loading mission\n"));
4676 void send_jump_into_mission_packet(net_player *pl)
4678 ubyte data[MAX_PACKET_SIZE];
4679 int packet_size = 0;
4681 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4683 BUILD_HEADER(JUMP_INTO_GAME);
4685 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4686 // and possible other things.
4688 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4689 ADD_INT(Netgame.game_state);
4695 multi_io_send_to_all_reliable(data, packet_size);
4697 // send to a specific player
4699 multi_io_send_reliable(pl, data, packet_size);
4703 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4705 int offset = HEADER_LENGTH;
4710 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4711 // the game could be paused, so ingame joiner needs to deal with it.
4712 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4714 Netgame.game_state = state;
4719 // handle any special processing for being in a weird substate
4720 multi_handle_state_special();
4722 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4723 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4724 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4725 multi_ingame_observer_finish();
4727 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4728 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4729 send_netplayer_update_packet();
4732 // start the mission!!
4733 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4734 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4735 gameseq_post_event(GS_EVENT_ENTER_GAME);
4736 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4737 send_netplayer_update_packet();
4741 extern time_t Player_multi_died_check;
4742 Player_multi_died_check = -1;
4744 // recalc all object pairs now
4745 extern void obj_reset_all_collisions();
4746 obj_reset_all_collisions();
4748 // display some cool text
4749 multi_common_add_text(XSTR("Received mission start\n",720),1);
4752 ml_string(NOX("Client received mission start from server - entering mission"));
4757 const char *repair_text[] = {
4759 "REPAIR_INFO_BEGIN",
4761 "REPAIR_INFO_UPDATE",
4762 "REPAIR_INFO_QUEUE",
4763 "REPAIR_INFO_ABORT",
4764 "REPAIR_INFO_BROKEN",
4765 "REPAIR_INFO_WARP_ADD",
4766 "REPAIR_INFO_WARP_REMOVE",
4767 "REPAIR_INFO_ONWAY",
4768 "REPAIR_INFO_KILLED",
4769 "REPAIR_INFO_COMPLETE",
4774 // the following two routines deal with updating and sending information regarding players
4775 // rearming and repairing during the game. The process function calls the routines to deal with
4776 // setting flags and other interesting things.
4777 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4779 int packet_size = 0;
4780 ushort repaired_signature, repair_signature;
4781 ubyte data[MAX_PACKET_SIZE];
4784 // use the network signature of the destination object if there is one, -1 otherwise.
4785 // client will piece it all together
4786 repaired_signature = repaired_objp->net_signature;
4788 // the repair ship may be NULL here since it might have been destroyed
4789 repair_signature = 0;
4791 repair_signature = repair_objp->net_signature;
4794 BUILD_HEADER(CLIENT_REPAIR_INFO);
4797 ADD_USHORT( repaired_signature );
4798 ADD_USHORT( repair_signature );
4800 multi_io_send_to_all_reliable(data, packet_size);
4802 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));
4805 void process_repair_info_packet(ubyte *data, header *hinfo)
4807 int offset = HEADER_LENGTH;
4808 ushort repaired_signature, repair_signature;
4809 object *repaired_objp, *repair_objp;
4813 GET_USHORT( repaired_signature );
4814 GET_USHORT( repair_signature );
4817 repaired_objp = multi_get_network_object( repaired_signature );
4818 repair_objp = multi_get_network_object( repair_signature );
4820 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));
4822 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4826 if ( repaired_objp == NULL ) {
4827 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4831 // the hope is to simply call the routine in the ai code to set/unset flags
4832 // based on the code value and everything else should happen..I hope....
4833 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4835 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4837 // set the dock flags when repair begins. Prevents problem in lagging docking
4838 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4840 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4841 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4842 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4845 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4847 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4848 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4851 if ( code == REPAIR_INFO_WARP_ADD ){
4852 mission_warp_in_support_ship( repaired_objp );
4854 mission_remove_scheduled_repair( repaired_objp );
4859 // sends information updating clients on certain AI information that clients will
4860 // need to know about to keep HUD information up to date. objp is the object that we
4861 // are updating, and what is the type of stuff that we are updating.
4862 void send_ai_info_update_packet( object *objp, char what )
4865 ushort other_signature;
4866 ubyte data[MAX_PACKET_SIZE];
4868 ubyte dock_index, dockee_index;
4870 // SDL_assert( objp->type == OBJ_SHIP );
4871 if(objp->type != OBJ_SHIP){
4874 aip = &Ai_info[Ships[objp->instance].ai_index];
4877 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4880 BUILD_HEADER( AI_INFO_UPDATE );
4881 ADD_USHORT( objp->net_signature );
4884 // depending on the "what" value, we will send different information
4888 case AI_UPDATE_DOCK:
4889 // for docking ships, add the signature of the ship that we are docking with.
4890 SDL_assert( aip->dock_objnum != -1 );
4891 other_signature = Objects[aip->dock_objnum].net_signature;
4892 dock_index = (ubyte)(aip->dock_index);
4893 dockee_index = (ubyte)(aip->dockee_index);
4894 ADD_USHORT( other_signature );
4895 ADD_DATA(dock_index);
4896 ADD_DATA(dockee_index);
4899 case AI_UPDATE_UNDOCK:
4900 // for undocking ships, check the dock_objnum since we might or might not have it
4901 // depending on whether or not a ship was destroyed while we were docked.
4902 other_signature = 0;
4903 if ( aip->dock_objnum != -1 )
4904 other_signature = Objects[aip->dock_objnum].net_signature;
4905 ADD_USHORT( other_signature );
4909 case AI_UPDATE_ORDERS: {
4912 // for orders, we only need to send a little bit of information here. Be sure that the
4913 // first order for this ship is active
4914 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4915 ADD_INT( aip->goals[0].ai_mode );
4916 ADD_INT( aip->goals[0].ai_submode );
4918 if ( aip->goals[0].ship_name != NULL )
4919 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4921 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4922 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4923 if ( shipnum != -1 ) {
4924 SDL_assert( Ships[shipnum].objnum != -1 );
4925 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4927 other_signature = 0;
4929 ADD_USHORT( other_signature );
4931 // for docking, add the dock and dockee index
4932 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4933 SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4934 SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4935 dock_index = (ubyte)aip->goals[0].docker.index;
4936 dockee_index = (ubyte)aip->goals[0].dockee.index;
4937 ADD_DATA( dock_index );
4938 ADD_DATA( dockee_index );
4947 multi_rate_add(1, "aiu", packet_size);
4948 multi_io_send_to_all_reliable(data, packet_size);
4951 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4952 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4953 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4955 int offset = HEADER_LENGTH;
4957 ushort net_signature, other_net_signature;
4958 object *objp, *other_objp;
4961 ubyte dock_index = 0, dockee_index = 0;
4963 GET_USHORT( net_signature ); // signature of the object that we are dealing with.
4964 GET_DATA( code ); // code of what we are doing.
4965 objp = multi_get_network_object( net_signature );
4967 nprintf(("Network", "Couldn't find object for ai update\n"));
4970 case AI_UPDATE_DOCK:
4971 GET_USHORT( other_net_signature );
4972 GET_DATA( dock_index );
4973 GET_DATA( dockee_index );
4974 other_objp = multi_get_network_object( other_net_signature );
4976 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4978 // if we don't have an object to work with, break out of loop
4979 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4983 SDL_assert( other_objp->type == OBJ_SHIP );
4984 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4985 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4987 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4988 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4990 ai_do_objects_docked_stuff( objp, other_objp );
4993 case AI_UPDATE_UNDOCK:
4994 GET_USHORT( other_net_signature );
4995 other_objp = multi_get_network_object( other_net_signature );
4997 // if we don't have an object to work with, break out of loop
5001 ai_do_objects_undocked_stuff( objp, other_objp );
5004 case AI_UPDATE_ORDERS:
5007 GET_USHORT( other_net_signature );
5008 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5009 GET_DATA(dock_index);
5010 GET_DATA(dockee_index);
5013 // be sure that we have a ship object!!!
5014 if ( !objp || (objp->type != OBJ_SHIP) )
5017 // set up the information in the first goal element of the object in question
5018 aip = &Ai_info[Ships[objp->instance].ai_index];
5019 aip->active_goal = 0;
5020 aip->goals[0].ai_mode = mode;
5021 aip->goals[0].ai_submode = submode;
5023 // for docking, add the dock and dockee index
5024 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5025 aip->dock_index = dock_index;
5026 aip->dockee_index = dockee_index;
5029 // get a shipname if we can.
5030 other_objp = multi_get_network_object( other_net_signature );
5031 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5032 // get a pointer to the shipname in question. Use the ship_name value in the
5033 // ship. We are only using this for HUD display, so I think that using this
5034 // method will be fine.
5035 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5037 // special case for destroy subsystem -- get the ai_info pointer to our target ship
5038 // so that we can properly set up what subsystem this ship is attacking.
5039 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5040 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5042 // if docking -- set the dock index and dockee index of this other ship
5043 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5044 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5045 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5052 Int3(); // this Int3() should be temporary
5053 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5059 // tell the standalone to move into the MISSION_SYNC_STATE
5060 void send_mission_sync_packet(int mode,int start_campaign)
5062 ubyte data[MAX_PACKET_SIZE],is_campaign;
5063 int packet_size = 0;
5065 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5067 // build the header and add the sync mode (pre or post briefing)
5068 BUILD_HEADER(MISSION_SYNC_DATA);
5071 // if this is a campaign game
5072 if(mode == MULTI_SYNC_PRE_BRIEFING){
5073 if(Game_mode & GM_CAMPAIGN_MODE){
5074 // add a byte indicating campaign mode
5076 ADD_DATA(is_campaign);
5078 // add a byte indicating if we should be starting a campaign or continuing it
5079 is_campaign = (ubyte)start_campaign;
5080 ADD_DATA(is_campaign);
5082 // add the campaign filename
5083 ADD_STRING(Netgame.campaign_name);
5085 // otherwise if this is a single mission
5087 // add a byte indicating single mission mode
5089 ADD_DATA(is_campaign);
5091 // add the mission filename
5092 ADD_STRING(Game_current_mission_filename);
5095 multi_io_send_reliable(Net_player, data, packet_size);
5098 // move into the MISSION_SYNC state when this is received
5099 // this packet is sent only from a game host to a standalone
5100 void process_mission_sync_packet(ubyte *data, header *hinfo)
5103 ubyte campaign_flag;
5104 int offset = HEADER_LENGTH;
5106 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5108 // if this is a team vs team situation, lock the players send a final team update
5109 if(Netgame.type_flags & NG_TYPE_TEAM){
5110 multi_team_host_lock_all();
5111 multi_team_send_update();
5114 // get the sync mode (pre or post briefing)
5117 if(mode == MULTI_SYNC_PRE_BRIEFING){
5118 // get the flag indicating if this is a single mission or a campaign mode
5119 GET_DATA(campaign_flag);
5121 // get the flag indicating whether we should be starting a new campaign
5122 GET_DATA(campaign_flag);
5124 // get the campaign filename
5125 GET_STRING(Netgame.campaign_name);
5127 // either start a new campaign or continue on to the next mission in the current campaign
5129 multi_campaign_start(Netgame.campaign_name);
5131 multi_campaign_next_mission();
5134 // make sure we remove the campaign mode flag
5135 Game_mode &= ~(GM_CAMPAIGN_MODE);
5137 // get the single mission filename
5138 GET_STRING(Game_current_mission_filename);
5139 SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, sizeof(Netgame.mission_name));
5144 // set the correct mode and m ove into the state
5145 Multi_sync_mode = mode;
5146 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5149 // tell a player to merge his mission stats into his alltime stats
5150 void send_store_stats_packet(int accept)
5153 int packet_size = 0;
5155 BUILD_HEADER(STORE_MISSION_STATS);
5157 // add whether we're accepting or tossing
5158 val = (ubyte)accept;
5161 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5162 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5163 multi_io_send_to_all_reliable(data, packet_size);
5165 multi_io_send_reliable(Net_player, data, packet_size);
5169 void process_store_stats_packet(ubyte *data, header *hinfo)
5171 int offset = HEADER_LENGTH;
5177 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5178 if(Game_mode & GM_STANDALONE_SERVER){
5179 // rebroadcast the packet to all others in the game
5180 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5181 multi_io_send_to_all_reliable(data, offset);
5184 // all players should mark the stats as being accepted in the debriefing
5185 multi_debrief_stats_accept();
5187 // all players should mark the stats as being "tossed" in the debriefing
5188 multi_debrief_stats_toss();
5193 void send_debris_update_packet(object *objp,int code)
5195 ubyte data[MAX_PACKET_SIZE];
5197 int packet_size = 0;
5199 BUILD_HEADER(DEBRIS_UPDATE);
5200 ADD_USHORT(objp->net_signature);
5204 // add any extra relevant data
5206 case DEBRIS_UPDATE_UPDATE:
5207 // ADD_DATA(objp->pos); // add position
5208 add_vector_data(data, &packet_size, objp->pos);
5209 ADD_ORIENT(objp->orient); // add orientation
5210 // ADD_DATA(objp->phys_info.vel); // add velocity
5211 add_vector_data(data, &packet_size, objp->phys_info.vel);
5212 // ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5213 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5216 multi_io_send_to_all(data, packet_size);
5219 void process_debris_update_packet(ubyte *data, header *hinfo)
5223 object bogus_object;
5225 int offset = HEADER_LENGTH;
5227 GET_USHORT(net_sig);
5231 objp = multi_get_network_object(net_sig);
5233 objp = &bogus_object;
5237 // update the object
5238 case DEBRIS_UPDATE_UPDATE:
5239 //GET_DATA(objp->pos);
5240 get_vector_data( data, &offset, objp->pos );
5242 GET_ORIENT(objp->orient);
5243 GET_DATA(objp->phys_info.vel);
5244 GET_DATA(objp->phys_info.rotvel);
5246 // simply remove it (no explosion)
5247 case DEBRIS_UPDATE_REMOVE:
5248 if(objp != &bogus_object){
5249 SDL_assert(objp->type == OBJ_DEBRIS);
5250 obj_delete(OBJ_INDEX(objp));
5254 case DEBRIS_UPDATE_NUKE:
5255 if(objp != &bogus_object)
5256 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5264 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)
5266 ubyte data[MAX_PACKET_SIZE];
5268 int packet_size = 0;
5270 BUILD_HEADER(WSS_REQUEST_PACKET);
5272 // add the request information
5273 ADD_SHORT(player_id);
5275 ADD_INT(from_index);
5278 ADD_INT(wl_ship_slot); // only used in weapons loadout
5279 ADD_INT(ship_class);
5282 // a standard request
5284 multi_io_send_reliable(Net_player, data, packet_size);
5286 // being routed through the standalone to the host of the game
5288 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5289 multi_io_send_reliable(p, data, packet_size);
5293 void process_wss_request_packet(ubyte *data, header *hinfo)
5295 int offset = HEADER_LENGTH;
5296 int from_slot,from_index;
5297 int to_slot,to_index;
5299 int wl_ship_slot,ship_class;
5303 // determine who this request is from
5304 GET_SHORT(player_id);
5305 player_num = find_player_id(player_id);
5307 // read in the request data
5309 GET_INT(from_index);
5312 GET_INT(wl_ship_slot); // only used in weapons loadout
5313 GET_INT(ship_class); // only used in multi team select
5317 SDL_assert(player_num != -1);
5318 if(player_num == -1){
5322 // if we're the standalone, we have to route this packet to the host of the game
5323 if(Game_mode & GM_STANDALONE_SERVER){
5324 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5326 // otherwise we're the host and should process the request
5329 case WSS_WEAPON_SELECT :
5330 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5332 case WSS_SHIP_SELECT :
5333 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5341 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5343 ubyte data[MAX_PACKET_SIZE],team;
5344 int packet_size = 0;
5346 SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5348 BUILD_HEADER(WSS_UPDATE_PACKET);
5350 // add the team/pool # this is for
5351 team = (ubyte)team_num;
5354 // add the data block size
5357 // add the data itself
5358 memcpy(data + packet_size,wss_data,size);
5359 packet_size += size;
5361 // if we're also the master of the game (not on a standalone)
5362 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5363 multi_io_send_to_all_reliable(data, packet_size);
5365 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5367 multi_io_send_reliable(Net_player, data, packet_size);
5371 void process_wss_update_packet(ubyte *data, header *hinfo)
5374 int size,player_index,idx;
5375 int offset = HEADER_LENGTH;
5377 // get the team/pool #
5380 // get the data size
5383 // if we're the standalone, then we should be routing this data to all the other clients
5384 if(Game_mode & GM_STANDALONE_SERVER){
5389 // determine where this came from
5390 player_index = find_player_id(hinfo->id);
5391 SDL_assert(player_index != -1);
5392 if(player_index < 0){
5396 // route the packet (don't resend it to the host)
5397 for(idx=0;idx<MAX_PLAYERS;idx++){
5398 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5399 multi_io_send_reliable(&Net_players[idx], data, offset);
5403 // set the proper pool pointers
5404 ss_set_team_pointers((int)team);
5406 // read in the block of data, and apply it to the weapons/ship pools
5407 offset += restore_wss_data(data + offset);
5410 // set the pool pointers back to my own team
5411 ss_set_team_pointers(Net_player->p_info.team);
5413 // sync the interface if this was for my own team
5414 if((int)team == Net_player->p_info.team){
5415 multi_ts_sync_interface();
5422 // function to send firing information from the client to the server once they reach
5423 // the final sync screen.
5424 void send_firing_info_packet()
5426 ubyte data[MAX_PACKET_SIZE];
5428 ubyte plinked, sdual;
5430 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5432 BUILD_HEADER(FIRING_INFO);
5433 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5434 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5435 ADD_DATA( plinked );
5438 multi_io_send_reliable(Net_player, data, packet_size);
5441 void process_firing_info_packet( ubyte *data, header *hinfo )
5443 int offset, player_num;
5444 ubyte plinked, sdual;
5447 // only the master of the game should be dealing with these packets
5448 SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5450 offset = HEADER_LENGTH;
5451 GET_DATA( plinked );
5455 player_num = find_player_id(hinfo->id);
5457 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5461 // get the ship pointer for this player and set the flags accordingly.
5462 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5464 shipp->flags |= SF_PRIMARY_LINKED;
5466 shipp->flags &= ~SF_PRIMARY_LINKED;
5469 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5471 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5474 // packet to deal with changing status of mission goals. used to be sent every so often from server
5475 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5476 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5477 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5478 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5480 ubyte data[MAX_PACKET_SIZE];
5483 BUILD_HEADER(MISSION_GOAL_INFO);
5486 ADD_INT(new_status);
5489 multi_io_send_to_all_reliable(data, packet_size);
5492 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5494 int offset, goal_num, new_status, valid;
5496 offset = HEADER_LENGTH;
5498 GET_INT(new_status);
5502 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5503 if ( new_status != -1 ){
5504 mission_goal_status_change( goal_num, new_status );
5506 mission_goal_validation_change( goal_num, valid );
5510 void send_player_settings_packet(net_player *p)
5512 ubyte data[MAX_PACKET_SIZE];
5515 int packet_size = 0;
5518 BUILD_HEADER(PLAYER_SETTINGS);
5520 // add all the data for all the players
5522 for(idx=0;idx<MAX_PLAYERS;idx++){
5523 if(MULTI_CONNECTED(Net_players[idx])){
5525 ADD_SHORT(Net_players[idx].player_id);
5527 // break the p_info structure by member, so we don't overwrite any absolute pointers
5528 // ADD_DATA(Net_players[idx].p_info);
5529 ADD_INT(Net_players[idx].p_info.team);
5530 ADD_INT(Net_players[idx].p_info.ship_index);
5531 ADD_INT(Net_players[idx].p_info.ship_class);
5534 // add the stop byte
5538 // either broadcast the data or send to a specific player
5540 multi_io_send_to_all_reliable(data, packet_size);
5542 multi_io_send_reliable(p, data, packet_size);
5546 void process_player_settings_packet(ubyte *data, header *hinfo)
5548 int offset,player_num;
5549 net_player_info bogus,*ptr;
5553 offset = HEADER_LENGTH;
5555 // read in the data for all the players
5557 while(stop != 0xff){
5558 // lookup the player
5559 GET_SHORT(player_id);
5560 player_num = find_player_id(player_id);
5562 // make sure this is a valid player
5563 if(player_num == -1){
5566 ptr = &Net_players[player_num].p_info;
5570 GET_INT(ptr->ship_index);
5571 GET_INT(ptr->ship_class);
5578 // update the server with my new state
5579 // MWA -- 3/31/98 -- check for in mission instead of state.
5580 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5581 if( !(Game_mode & GM_IN_MISSION) ) {
5582 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5583 send_netplayer_update_packet();
5587 // display some cool text
5588 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5591 void send_deny_packet(net_addr *addr, int code)
5594 int packet_size = 0;
5596 // build the header and add the rejection code
5602 psnet_send(addr, data, packet_size);
5605 void process_deny_packet(ubyte *data, header *hinfo)
5609 // get the denial code
5610 offset = HEADER_LENGTH;
5614 // if there is already a dialog active, do nothing - who cares at this point.
5619 // display the appropriate dialog
5621 case JOIN_DENY_JR_STATE :
5622 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));
5624 case JOIN_DENY_JR_TRACKER_INVAL :
5625 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));
5627 case JOIN_DENY_JR_PASSWD :
5628 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5630 case JOIN_DENY_JR_CLOSED :
5631 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));
5633 case JOIN_DENY_JR_TEMP_CLOSED :
5634 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));
5636 case JOIN_DENY_JR_RANK_HIGH :
5637 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));
5639 case JOIN_DENY_JR_RANK_LOW :
5640 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));
5642 case JOIN_DENY_JR_DUP :
5643 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5645 case JOIN_DENY_JR_FULL :
5646 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5648 case JOIN_DENY_JR_BANNED :
5649 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5651 case JOIN_DENY_JR_NOOBS :
5652 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5654 case JOIN_DENY_JR_INGAME_JOIN :
5655 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));
5657 case JOIN_DENY_JR_BAD_VERSION :
5658 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));
5660 case JOIN_DENY_JR_TYPE :
5661 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5665 // call this so that the join request timestamp automatically expires when we hear back from the server
5666 multi_join_reset_join_stamp();
5669 // this packet will consist of
5670 // 1.) netplayer ship classes (85 bytes max)
5671 // 2.) ship weapon state data (241 bytes max)
5672 // 3.) player settings et. al. (133 bytes max)
5673 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5674 void send_post_sync_data_packet(net_player *p, int std_request)
5676 ubyte data[MAX_PACKET_SIZE], val;
5681 ushort sval, ship_ets;
5682 int idx, player_index;
5683 int packet_size = 0;
5687 BUILD_HEADER(POST_SYNC_DATA);
5689 // some header information for standalone packet routing purposes
5690 val = (ubyte)std_request;
5693 // the standalone has two situations
5694 // 1.) sending a request to the host to distribute this block of data
5695 // 2.) having recevied this block of data from the host, it redistributes it
5696 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5697 // case 1, send the request
5698 multi_io_send_reliable(Netgame.host, data, packet_size);
5701 // case 2 for the standalone is below (as normal)
5703 // otherwise build the data now
5705 // add all deleted ships
5706 val = (ubyte)Multi_ts_num_deleted;
5708 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5709 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5715 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5716 shipp = &Ships[Objects[so->objnum].instance];
5718 // don't process non player wing ships
5719 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5725 // # of ships - used multiple times in the packet
5726 val = (ubyte)ship_count;
5729 // add ship class information (85 bytes max)
5730 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5731 shipp = &Ships[Objects[so->objnum].instance];
5733 // don't process non player wing ships
5734 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5737 // add the net signature of the object for look up
5738 ADD_USHORT( Objects[so->objnum].net_signature );
5740 // add the ship info index
5741 val = (ubyte)(shipp->ship_info_index);
5744 // add the ships's team select index
5745 val = (ubyte)shipp->ts_index;
5749 // add weapon state information for all starting ships (241 bytes max)
5750 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5751 shipp = &Ships[Objects[so->objnum].instance];
5753 // don't process non player wing ships
5754 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5757 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5759 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5760 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5761 if(player_index == -1){
5764 pl = &Net_players[player_index];
5768 // add the net signature and other weapon information
5769 ADD_USHORT( Objects[so->objnum].net_signature );
5771 // add number of primary and secondary banks
5772 bval = (char)(shipp->weapons.num_primary_banks);
5774 bval = (char)(shipp->weapons.num_secondary_banks);
5777 // add weapon bank status
5778 bval = (char)(shipp->weapons.current_primary_bank);
5780 pl->s_info.cur_primary_bank = bval;
5782 // SDL_assert(bval != -1);
5785 bval = (char)(shipp->weapons.current_secondary_bank);
5787 pl->s_info.cur_secondary_bank = bval;
5789 // SDL_assert(bval != -1);
5792 // primary weapon info
5793 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5795 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5798 // secondary weapon info
5799 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5801 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5802 ADD_SHORT(val_short);
5803 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5805 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5806 ADD_SHORT(val_short);
5807 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5809 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5810 ADD_SHORT(val_short);
5812 // send primary and secondary weapon link status
5814 if(shipp->flags & SF_PRIMARY_LINKED){
5816 pl->s_info.cur_link_status |= (1<<0);
5820 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5822 pl->s_info.cur_link_status |= (1<<1);
5826 // if this is a player ship add (1<<2)
5827 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5832 // add a ship ets value
5835 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5837 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5839 ship_ets |= ((ushort)shipp->engine_recharge_index);
5840 ADD_USHORT(ship_ets);
5844 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5845 // or if I'm the server as well as the host, I should be sending this to all players
5846 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5847 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5850 multi_io_send_to_all_reliable(data, packet_size);
5852 // send to a specific player
5854 multi_io_send_reliable(p, data, packet_size);
5857 multi_io_send_reliable(Net_player, data, packet_size);
5864 multi_io_send_to_all_reliable(data, packet_size);
5866 // send to a specific player
5868 multi_io_send_reliable(p, data, packet_size);
5873 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5875 ubyte val, sinfo_index, ts_index;
5877 ushort net_sig, ship_ets, sval;
5881 int offset = HEADER_LENGTH;
5885 // packet routing information
5888 // 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
5889 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5892 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5893 multi_ts_create_wings();
5895 // send to the standalone through my socket
5896 send_post_sync_data_packet(Net_player);
5902 // add all deleted ships
5904 Multi_ts_num_deleted = (int)val;
5905 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5906 // get the ship's objnum
5909 objp = multi_get_network_object(sval);
5911 // delete the ship appropriately
5912 // mark the object as having been deleted
5913 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5916 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5917 obj_delete(Multi_ts_deleted_objnums[idx]);
5918 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5920 Multi_ts_num_deleted--;
5921 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5929 // process ship class information
5930 for(idx=0; idx<ship_count; idx++){
5931 // get the object's net signature
5932 GET_USHORT(net_sig);
5933 GET_DATA(sinfo_index);
5936 // attempt to get the object
5937 objp = multi_get_network_object(net_sig);
5939 // make sure we found a ship
5940 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5942 // set the ship to be the right class
5943 change_ship_type(objp->instance,(int)sinfo_index);
5945 // set the ship's team select index
5946 Ships[objp->instance].ts_index = (int)ts_index;
5949 // process ship weapon state info
5950 for(idx=0; idx<ship_count; idx++){
5951 // get the object's net signature
5952 GET_USHORT(net_sig);
5954 // attempt to get the object
5955 objp = multi_get_network_object(net_sig);
5957 // make sure we found a ship
5958 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5960 // get a pointer to the ship
5961 shipp = &Ships[objp->instance];
5963 // get number of primary and secondary banks;
5965 SDL_assert( b != -1 );
5966 shipp->weapons.num_primary_banks = (int)b;
5969 SDL_assert( b != -1 );
5970 shipp->weapons.num_secondary_banks = (int)b;
5972 // get bank selection info
5977 shipp->weapons.current_primary_bank = (int)b;
5983 shipp->weapons.current_secondary_bank = (int)b;
5985 // primary weapon info
5987 shipp->weapons.primary_bank_weapons[0] = (int)b;
5990 shipp->weapons.primary_bank_weapons[1] = (int)b;
5992 // secondary weapon info
5994 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5995 GET_SHORT(val_short);
5996 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5999 shipp->weapons.secondary_bank_weapons[1] = (int)b;
6000 GET_SHORT(val_short);
6001 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
6004 shipp->weapons.secondary_bank_weapons[2] = (int)b;
6005 GET_SHORT(val_short);
6006 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6013 shipp->flags |= SF_PRIMARY_LINKED;
6016 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
6018 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6019 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6021 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6023 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6027 GET_USHORT(ship_ets);
6029 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6031 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6033 shipp->engine_recharge_index = (ship_ets & 0x000f);
6038 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6039 send_netplayer_update_packet();
6041 // the standalone server will receive this packet from the host of the game, to be applied locally and
6042 // also to be rebroadcast.
6043 if(Game_mode & GM_STANDALONE_SERVER){
6044 // update player ets settings
6045 for(idx=0;idx<MAX_PLAYERS;idx++){
6046 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6047 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6051 send_post_sync_data_packet(NULL,0);
6055 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6057 ubyte data[MAX_PACKET_SIZE],val;
6060 int packet_size = 0;
6063 BUILD_HEADER(WSS_SLOTS_DATA);
6065 // some header information for standalone packet routing purposes
6066 val = (ubyte)std_request;
6070 val = (ubyte)team_num;
6073 // add whether this is the final packet or not
6077 // the standalone has two situations
6078 // 1.) sending a request to the host to distribute this block of data
6079 // 2.) having recevied this block of data from the host, it redistributes it
6080 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6081 // case 1, send the request
6082 multi_io_send_reliable(Netgame.host, data, packet_size);
6085 // case 2 for the standalone is below (as normal)
6087 // add all the slots
6088 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6089 // add the ship class
6090 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6094 for(i = 0;i<MAX_WL_WEAPONS;i++){
6095 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6099 // add the weapon counts
6100 for(i = 0;i<MAX_WL_WEAPONS;i++){
6101 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6102 ADD_SHORT(val_short);
6106 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6107 // or if I'm the server as well as the host, I should be sending this to all players
6108 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6109 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6112 multi_io_send_to_all_reliable(data, packet_size);
6114 // send to a specific player
6116 multi_io_send_reliable(p, data, packet_size);
6119 multi_io_send_reliable(Net_player, data, packet_size);
6126 multi_io_send_to_all_reliable(data, packet_size);
6128 // send to a specific player
6130 multi_io_send_reliable(p, data, packet_size);
6135 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6137 ubyte val,team_num,final;
6139 int offset = HEADER_LENGTH;
6142 // packet routing information
6148 // get whether this is the final packet or not
6151 // 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
6152 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6155 // send to the standalone through my socket
6156 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6160 // read in all the slot data
6161 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6162 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6164 // get the ship class
6166 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6169 for(i = 0;i<MAX_WL_WEAPONS;i++){
6171 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6173 // check for signed/unsigned problems
6174 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6175 Wss_slots_teams[team_num][idx].wep[i] = -1;
6179 // get the weapon counts
6180 for(i = 0;i<MAX_WL_WEAPONS;i++){
6181 GET_SHORT(val_short);
6182 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6187 // update my netplayer state if this is the final packet
6189 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6190 send_netplayer_update_packet();
6193 // the standalone server will receive this packet from the host of the game, to be applied locally and
6194 // also to be rebroadcast.
6195 if(Game_mode & GM_STANDALONE_SERVER){
6196 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6198 // add some mission sync text
6199 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6203 #define OBJ_VISIBILITY_DOT 0.6f
6205 // send and receive packets for shield explosion information
6206 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6209 ubyte data[MAX_PACKET_SIZE], utri_num;
6212 // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6214 SDL_assert( tri_num < UCHAR_MAX );
6215 utri_num = (ubyte)tri_num;
6217 // for each player, determine if this object is behind the player -- if so, don't
6219 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6220 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6222 vector eye_to_obj_vec, diff, eye_pos;
6225 eye_pos = Net_players[i].s_info.eye_pos;
6226 eye_orient = Net_players[i].s_info.eye_orient;
6228 // check for same vectors
6229 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6230 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6234 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6235 dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6237 if ( dot < OBJ_VISIBILITY_DOT ){
6241 BUILD_HEADER(SHIELD_EXPLOSION);
6243 ADD_USHORT( Objects[objnum].net_signature );
6246 multi_io_send(&Net_players[i], data, packet_size);
6251 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6253 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6260 // get the shield hit data
6261 offset = HEADER_LENGTH;
6262 GET_USHORT(signature);
6264 //GET_DATA(hit_pos);
6267 // find the object with this signature. If found, then do a shield explosion
6268 objp = multi_get_network_object( signature );
6271 shield_info *shieldp;
6276 // given the tri num, find the local position which is the average of the
6277 // three vertices of the triangle affected. Use this average point as the hit
6279 // SDL_assert( objp->type == OBJ_SHIP );
6280 if(objp->type != OBJ_SHIP){
6284 pm = model_get(Ships[objp->instance].modelnum);
6285 shieldp = &pm->shield;
6286 SDL_assert( utri_num < shieldp->ntris );
6287 stri = shieldp->tris[utri_num];
6288 vm_vec_zero(&hit_pos);
6289 for ( i = 0; i < 3; i++ ) {
6290 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6292 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6293 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6297 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6300 ubyte data[MAX_PACKET_SIZE], val;
6302 int packet_size = 0;
6307 sc = &pl->player->stats;
6310 BUILD_HEADER(PLAYER_STATS);
6312 // add the player id
6313 ADD_SHORT(pl->player_id);
6315 // add the byte indicating whether these stats are all-time or not
6316 val = (ubyte)stats_code;
6319 // kill information - alltime
6323 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6324 u_tmp = sc->kills[idx];
6327 // medal information
6328 for(idx=0;idx<NUM_MEDALS;idx++){
6329 i_tmp = sc->medals[idx];
6335 ADD_INT(sc->assists);
6336 ADD_INT(sc->kill_count);
6337 ADD_INT(sc->kill_count_ok);
6338 ADD_UINT(sc->p_shots_fired);
6339 ADD_UINT(sc->s_shots_fired);
6340 ADD_UINT(sc->p_shots_hit);
6341 ADD_UINT(sc->s_shots_hit);
6342 ADD_UINT(sc->p_bonehead_hits);
6343 ADD_UINT(sc->s_bonehead_hits);
6344 ADD_INT(sc->bonehead_kills);
6346 ADD_UINT(sc->missions_flown);
6347 ADD_UINT(sc->flight_time);
6348 ADD_INT(sc->last_flown);
6349 ADD_INT(sc->last_backup);
6354 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6355 u_tmp = sc->m_okKills[idx];
6359 ADD_INT(sc->m_score);
6360 ADD_INT(sc->m_assists);
6361 ADD_INT(sc->m_kill_count);
6362 ADD_INT(sc->m_kill_count_ok);
6363 ADD_UINT(sc->mp_shots_fired);
6364 ADD_UINT(sc->ms_shots_fired);
6365 ADD_UINT(sc->mp_shots_hit);
6366 ADD_UINT(sc->ms_shots_hit);
6367 ADD_UINT(sc->mp_bonehead_hits);
6368 ADD_UINT(sc->ms_bonehead_hits);
6369 ADD_INT(sc->m_bonehead_kills);
6370 ADD_INT(sc->m_player_deaths);
6371 ADD_INT(sc->m_medal_earned);
6374 case STATS_MISSION_KILLS:
6375 ADD_INT(sc->m_kill_count);
6376 ADD_INT(sc->m_kill_count_ok);
6377 ADD_INT(sc->m_assists);
6380 case STATS_DOGFIGHT_KILLS:
6381 for(idx=0; idx<MAX_PLAYERS; idx++){
6382 u_tmp = sc->m_dogfight_kills[idx];
6385 ADD_INT(sc->m_kill_count);
6386 ADD_INT(sc->m_kill_count_ok);
6387 ADD_INT(sc->m_assists);
6391 SDL_assert(packet_size < MAX_PACKET_SIZE);
6393 // if we're a client, always send the data to the server
6394 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6395 multi_io_send_reliable(Net_player, data, packet_size);
6397 // otherwise do server specific stuff
6399 // send to a specific target
6401 multi_io_send_reliable(target, data, packet_size);
6403 // otherwise, send to everyone
6405 multi_io_send_to_all_reliable(data, packet_size);
6410 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6414 scoring_struct *sc,bogus;
6416 int offset = HEADER_LENGTH;
6420 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6422 // get the player who these stats are for
6423 GET_SHORT(player_id);
6424 player_num = find_player_id(player_id);
6425 if (player_num == -1) {
6426 nprintf(("Network", "Couldn't find player for stats update!\n"));
6427 ml_string("Couldn't find player for stats update!\n");
6432 sc = &Net_players[player_num].player->stats;
6435 // get the stats code
6439 ml_string("Received STATS_ALLTIME\n");
6442 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6444 sc->kills[idx] = u_tmp;
6447 // read in the stats
6448 for (idx=0; idx<NUM_MEDALS; idx++) {
6450 sc->medals[idx] = i_tmp;
6455 GET_INT(sc->assists);
6456 GET_INT(sc->kill_count);
6457 GET_INT(sc->kill_count_ok);
6458 GET_UINT(sc->p_shots_fired);
6459 GET_UINT(sc->s_shots_fired);
6460 GET_UINT(sc->p_shots_hit);
6461 GET_UINT(sc->s_shots_hit);
6462 GET_UINT(sc->p_bonehead_hits);
6463 GET_UINT(sc->s_bonehead_hits);
6464 GET_INT(sc->bonehead_kills);
6466 GET_UINT(sc->missions_flown);
6467 GET_UINT(sc->flight_time);
6468 GET_INT(sc->last_flown);
6469 GET_INT(sc->last_backup);
6473 ml_string("Received STATS_MISSION\n");
6475 // kills - mission OK
6476 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6478 sc->m_okKills[idx] = u_tmp;
6481 GET_INT(sc->m_score);
6482 GET_INT(sc->m_assists);
6483 GET_INT(sc->m_kill_count);
6484 GET_INT(sc->m_kill_count_ok);
6485 GET_UINT(sc->mp_shots_fired);
6486 GET_UINT(sc->ms_shots_fired);
6487 GET_UINT(sc->mp_shots_hit);
6488 GET_UINT(sc->ms_shots_hit);
6489 GET_UINT(sc->mp_bonehead_hits);
6490 GET_UINT(sc->ms_bonehead_hits);
6491 GET_INT(sc->m_bonehead_kills);
6492 GET_INT(sc->m_player_deaths);
6493 GET_INT(sc->m_medal_earned);
6496 case STATS_MISSION_KILLS:
6497 ml_string("Received STATS_MISSION_KILLS\n");
6499 GET_INT(sc->m_kill_count);
6500 GET_INT(sc->m_kill_count_ok);
6501 GET_INT(sc->m_assists);
6504 case STATS_DOGFIGHT_KILLS:
6505 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6506 if(player_num >= 0){
6507 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6509 for(idx=0; idx<MAX_PLAYERS; idx++){
6511 sc->m_dogfight_kills[idx] = u_tmp;
6512 if(player_num >= 0){
6513 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6516 GET_INT(sc->m_kill_count);
6517 GET_INT(sc->m_kill_count_ok);
6518 GET_INT(sc->m_assists);
6523 // if I'm the server of the game, I should always rebroadcast these stats
6524 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6525 // make sure these are alltime stats
6526 SDL_assert(val == STATS_ALLTIME);
6528 multi_broadcast_stats(STATS_ALLTIME);
6532 // called to create asteroid stuff
6533 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6536 ubyte data[MAX_PACKET_SIZE];
6537 ubyte packet_type, atype;
6541 if (relvec != NULL )
6544 BUILD_HEADER( ASTEROID_INFO );
6545 packet_type = ASTEROID_CREATE;
6547 SDL_assert( asteroid_type < UCHAR_MAX );
6548 atype = (ubyte)asteroid_type;
6550 ADD_DATA( packet_type );
6551 ADD_USHORT( parent_objp->net_signature );
6552 ADD_USHORT( new_objp->net_signature );
6555 add_vector_data( data, &packet_size, vec );
6557 multi_io_send_to_all(data, packet_size);
6560 void send_asteroid_throw( object *objp )
6563 ubyte data[MAX_PACKET_SIZE], packet_type;
6565 BUILD_HEADER( ASTEROID_INFO );
6567 // this packet type is an asteroid throw
6568 packet_type = ASTEROID_THROW;
6569 ADD_DATA( packet_type );
6570 ADD_USHORT( objp->net_signature );
6571 //ADD_DATA( objp->pos );
6572 add_vector_data( data, &packet_size, objp->pos );
6573 //ADD_DATA( objp->phys_info.vel );
6574 add_vector_data( data, &packet_size, objp->phys_info.vel );
6576 multi_io_send_to_all(data, packet_size);
6579 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6582 ubyte data[MAX_PACKET_SIZE], packet_type;
6586 if ( hitpos != NULL )
6589 // build up an asteroid hit packet
6590 BUILD_HEADER( ASTEROID_INFO );
6591 packet_type = ASTEROID_HIT;
6592 ADD_DATA( packet_type );
6593 ADD_USHORT( objp->net_signature );
6595 if(other_objp == NULL){
6596 ushort invalid_sig = 0xffff;
6597 ADD_USHORT(invalid_sig);
6599 ADD_USHORT( other_objp->net_signature );
6602 add_vector_data( data, &packet_size, vec );
6603 ADD_FLOAT( damage );
6605 multi_io_send_to_all(data, packet_size);
6608 void process_asteroid_info( ubyte *data, header *hinfo )
6613 offset = HEADER_LENGTH;
6614 GET_DATA( packet_type );
6616 // based on the packet type, do something interesting with an asteroid!
6617 switch( packet_type ) {
6619 case ASTEROID_CREATE: {
6620 ushort psignature, signature;
6622 vector relvec = ZERO_VECTOR;
6623 object *parent_objp;
6625 GET_USHORT( psignature );
6626 GET_USHORT( signature );
6628 //GET_DATA( relvec );
6629 get_vector_data( data, &offset, relvec );
6631 // after getting the values, set the next network signature, and call the create sub function
6632 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6633 parent_objp = multi_get_network_object( psignature );
6634 if ( parent_objp ) {
6635 asteroid_sub_create( parent_objp, atype, &relvec );
6637 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6644 // asteroid throw packet -- asteroid has wrapped bounds
6645 case ASTEROID_THROW: {
6647 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6650 GET_USHORT( signature );
6652 get_vector_data( data, &offset, pos );
6654 get_vector_data( data, &offset, vel );
6655 objp = multi_get_network_object( signature );
6657 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6661 objp->phys_info.vel = vel;
6662 objp->phys_info.desired_vel = vel;
6666 case ASTEROID_HIT: {
6667 ushort signature, osignature;
6668 object *objp, *other_objp;
6669 vector hitpos = ZERO_VECTOR;
6672 GET_USHORT( signature );
6673 GET_USHORT( osignature );
6674 //GET_DATA( hitpos );
6675 get_vector_data( data, &offset, hitpos );
6676 GET_FLOAT( damage );
6678 objp = multi_get_network_object( signature );
6679 if(osignature == 0xffff){
6682 other_objp = multi_get_network_object( osignature );
6685 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6689 if ( IS_VEC_NULL(&hitpos) ){
6690 asteroid_hit( objp, other_objp, NULL, damage );
6692 asteroid_hit( objp, other_objp, &hitpos, damage );
6695 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6696 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6697 weapon_hit( other_objp, objp, &hitpos );
6710 void send_host_restr_packet(const char *callsign, int code, int mode)
6712 ubyte data[MAX_PACKET_SIZE],val;
6713 int packet_size = 0;
6715 // build the header and add the opcode
6716 BUILD_HEADER(HOST_RESTR_QUERY);
6723 ADD_STRING(callsign);
6725 // if I'm the standalone server, I should be sending this to the game host
6726 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6727 multi_io_send_reliable(Netgame.host, data, packet_size);
6729 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6731 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6732 multi_io_send_reliable(Net_player, data, packet_size);
6736 void process_host_restr_packet(ubyte *data, header *hinfo)
6740 int offset = HEADER_LENGTH;
6742 // get the opcode and the callsign
6745 GET_STRING(callsign);
6748 // do code specific operations
6750 // query to the host from standalone
6752 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6754 // set the join mode
6755 Multi_join_restr_mode = mode;
6757 // set the timestamp
6758 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6760 // notify the host of the event
6761 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6762 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6765 // affirmative reply from the host to the standalone
6767 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6769 // let the player join if the timestamp has not already elapsed on the server
6770 if(Multi_restr_query_timestamp != -1){
6771 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6777 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6778 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6779 Multi_restr_query_timestamp = -1;
6784 void send_netgame_end_error_packet(int notify_code,int err_code)
6788 int packet_size = 0;
6790 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6791 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6793 // build the header and add the notification and error codes
6794 BUILD_HEADER(NETGAME_END_ERROR);
6795 code = (char)notify_code;
6797 code = (char)err_code;
6801 multi_io_send_to_all_reliable(data, packet_size);
6804 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6806 int offset = HEADER_LENGTH;
6807 char notify_code,error_code;
6809 // get the error and notification codes
6810 GET_DATA(notify_code);
6811 GET_DATA(error_code);
6815 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6818 // sends info that a countermeasure succeeded.
6819 void send_countermeasure_success_packet( int objnum )
6821 int pnum, packet_size;
6822 ubyte data[MAX_PACKET_SIZE];
6824 pnum = multi_find_player_by_object( &Objects[objnum] );
6826 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6830 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6831 multi_io_send(&Net_players[pnum], data, packet_size);
6834 // start the flashing of my hud gauge
6835 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6839 offset = HEADER_LENGTH;
6842 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6843 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6846 #define UPDATE_IS_PAUSED (1<<0)
6847 #define UPDATE_HULL_INFO (1<<1)
6849 void send_client_update_packet(net_player *pl)
6851 ubyte data[MAX_PACKET_SIZE],val;
6852 int packet_size = 0;
6855 BUILD_HEADER(CLIENT_UPDATE);
6859 // add the pause status
6860 if ( Multi_pause_status ) {
6861 val |= UPDATE_IS_PAUSED;
6862 } 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) ) {
6863 val |= UPDATE_HULL_INFO;
6864 SDL_assert( Player_ship ); // I"d better have one of these!!!!
6869 // if paused, add the net address of the guy who paused
6870 if(val & UPDATE_IS_PAUSED){
6871 SDL_assert(Multi_pause_pauser != NULL);
6872 ADD_SHORT(Multi_pause_pauser->player_id);
6875 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6876 if ( val & UPDATE_HULL_INFO ) {
6878 ubyte percent, ns, threats;
6881 ship_subsys *subsysp;
6884 // get the object for the player
6885 SDL_assert( pl->player->objnum != -1 );
6887 objp = &Objects[pl->player->objnum];
6889 SDL_assert ( objp->type == OBJ_SHIP );
6890 shipp = &Ships[objp->instance];
6891 sip = &Ship_info[shipp->ship_info_index];
6893 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6894 // percentage value since that should be close enough
6895 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6899 percent = (ubyte)temp;
6901 ADD_DATA( percent );
6903 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6904 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6905 ADD_DATA( percent );
6908 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6909 // both machines. Added as percent since that number <= 100
6911 // also write out the number of subsystems. We do this because the client might not know
6912 // about the object he is getting data for. (i.e. he killed the object already).
6913 ns = (ubyte)sip->n_subsystems;
6916 // now the subsystems.
6917 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6918 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6919 ADD_DATA( percent );
6922 // compute the threats for this player. Only compute the threats if this player is actually
6923 // playing (i.e. he has a ship)
6924 hud_update_reticle( pl->player );
6925 threats = (ubyte)pl->player->threat_flags;
6926 ADD_DATA( threats );
6928 // add his energy level for guns
6929 ADD_FLOAT(shipp->weapon_energy);
6931 // add his secondary bank ammo
6932 ADD_INT(shipp->weapons.num_secondary_banks);
6933 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6934 ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6939 ADD_INT(pl->sv_last_pl);
6941 // send the packet reliably to the player
6942 multi_io_send(pl, data, packet_size);
6945 void process_client_update_packet(ubyte *data, header *hinfo)
6950 int is_paused, have_hull_info;
6953 float weapon_energy;
6954 int offset = HEADER_LENGTH;
6956 // get the header byte containing useful information
6959 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6960 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6962 // if we are paused, get who paused
6965 player_index = find_player_id(pauser);
6966 if(player_index != -1){
6967 Multi_pause_pauser = &Net_players[player_index];
6969 Multi_pause_pauser = NULL;
6973 // if we have hull information, then read it in.
6974 if ( have_hull_info ) {
6978 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6980 ship_subsys *subsysp;
6984 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6985 // percentage value since that should be close enough
6986 GET_DATA( hull_percent );
6988 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6990 shield_percent[i] = ub_tmp;
6993 // get the data for the subsystems
6994 GET_DATA( n_subsystems );
6995 for ( i = 0; i < n_subsystems; i++ ){
6997 subsystem_percent[i] = ub_tmp;
7000 GET_DATA( threats );
7002 // add his energy level for guns
7003 GET_FLOAT(weapon_energy);
7005 // add his secondary bank ammo
7006 GET_INT(ammo_count);
7007 for(i=0; i<ammo_count; i++){
7011 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
7012 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7013 // UDP client update packets. Only read this info if I have a ship.
7014 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
7015 shipp = Player_ship;
7017 sip = &Ship_info[shipp->ship_info_index];
7019 val = hull_percent * sip->initial_hull_strength / 100.0f;
7020 objp->hull_strength = val;
7022 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7023 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7024 objp->shields[i] = val;
7027 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
7028 // then don't read these in.
7029 if ( n_subsystems == sip->n_subsystems ) {
7031 n_subsystems = 0; // reuse this variable
7032 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7035 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7036 subsysp->current_hits = val;
7038 // add the value just generated (it was zero'ed above) into the array of generic system types
7039 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
7040 SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7041 shipp->subsys_info[subsys_type].current_hits += val;
7045 ship_recalc_subsys_strength( shipp );
7047 shipp->weapon_energy = weapon_energy;
7048 for(i=0; i<ammo_count; i++){
7049 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7052 // update my threat flags.
7053 // temporarily commented out until tested.
7054 Net_player->player->threat_flags = threats;
7061 if(Net_player != NULL){
7062 Net_player->cl_last_pl = pl;
7066 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7067 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7069 multi_pause_pause();
7071 multi_pause_unpause();
7076 void send_countdown_packet(int time)
7080 int packet_size = 0;
7082 // build the header and add the time
7083 BUILD_HEADER(COUNTDOWN);
7087 // if we're the server, we should broadcast to everyone
7088 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
7089 multi_io_send_to_all_reliable(data, packet_size);
7091 // otherwise we'de better be a host sending to the standalone
7093 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7094 multi_io_send_reliable(Net_player, data, packet_size);
7098 void process_countdown_packet(ubyte *data, header *hinfo)
7100 int offset = HEADER_LENGTH;
7107 // if we're not in the post sync data screen, ignore it
7108 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7112 // if we're the standalone, this should be a -1 telling us to start the countdown
7113 if(Game_mode & GM_STANDALONE_SERVER){
7114 SDL_assert((int)time == -1);
7116 // start the countdown
7117 multi_sync_start_countdown();
7119 // otherwise if we're clients, just bash the countdown
7121 Multi_sync_countdown = (int)time;
7125 // packets for debriefing information
7126 void send_debrief_info( int stage_count[], int *stages[] )
7128 ubyte data[MAX_PACKET_SIZE];
7129 int packet_size, i, j;
7132 BUILD_HEADER(DEBRIEF_INFO);
7134 // add the data for the teams
7135 for ( i = 0; i < Num_teams; i++ ) {
7138 count = stage_count[i];
7140 for ( j = 0; j < count; j++ ) {
7141 i_tmp = stages[i][j];
7146 multi_io_send_to_all_reliable(data, packet_size);
7149 // process a debrief info packet from the server
7150 void process_debrief_info( ubyte *data, header *hinfo )
7153 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7156 offset = HEADER_LENGTH;
7157 for ( i = 0; i < Num_teams; i++ ) {
7161 stage_counts[i] = count;
7162 stages[i] = active_stages[i];
7163 for ( j = 0; j < count; j++ ) {
7165 active_stages[i][j] = i_tmp;
7170 // now that we have the stage data for the debriefing stages, call debrief function with the
7171 // data so that clients can now see the debriefing stuff. Do it only for my team.
7172 SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7173 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7176 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7177 // sends homing_object and homing_subsystem to all clients.
7178 void send_homing_weapon_info( int weapon_num )
7180 ubyte data[MAX_PACKET_SIZE];
7183 object *homing_object;
7184 ushort homing_signature;
7187 wp = &Weapons[weapon_num];
7189 // be sure that this weapon object is a homing object.
7190 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7193 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7194 // homing signature.
7195 homing_signature = 0;
7196 homing_object = wp->homing_object;
7197 if ( homing_object != NULL ) {
7198 homing_signature = homing_object->net_signature;
7200 // get the subsystem index.
7202 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7205 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7206 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
7207 t_subsys = (char)s_index;
7211 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7212 ADD_USHORT( Objects[wp->objnum].net_signature );
7213 ADD_USHORT( homing_signature );
7214 ADD_DATA( t_subsys );
7216 multi_io_send_to_all(data, packet_size);
7219 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7220 // packet contains information for multiple weapons (like hornets).
7221 void process_homing_weapon_info( ubyte *data, header *hinfo )
7224 ushort weapon_signature, homing_signature;
7226 object *homing_object, *weapon_objp;
7229 offset = HEADER_LENGTH;
7231 // get the data for the packet
7232 GET_USHORT( weapon_signature );
7233 GET_USHORT( homing_signature );
7234 GET_DATA( h_subsys );
7237 // deal with changing this weapons homing information
7238 weapon_objp = multi_get_network_object( weapon_signature );
7239 if ( weapon_objp == NULL ) {
7240 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7243 SDL_assert( weapon_objp->type == OBJ_WEAPON );
7244 wp = &Weapons[weapon_objp->instance];
7246 // be sure that we can find these weapons and
7247 homing_object = multi_get_network_object( homing_signature );
7248 if ( homing_object == NULL ) {
7249 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7253 if ( homing_object->type == OBJ_WEAPON ) {
7254 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7257 wp->homing_object = homing_object;
7258 wp->homing_subsys = NULL;
7259 wp->target_num = OBJ_INDEX(homing_object);
7260 wp->target_sig = homing_object->signature;
7261 if ( h_subsys != -1 ) {
7262 SDL_assert( homing_object->type == OBJ_SHIP );
7263 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7266 if ( homing_object->type == OBJ_SHIP ) {
7267 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7271 void send_emp_effect(ushort net_sig, float intensity, float time)
7276 SDL_assert(MULTIPLAYER_MASTER);
7278 // build the packet and add the opcode
7279 BUILD_HEADER(EMP_EFFECT);
7280 ADD_USHORT(net_sig);
7281 ADD_FLOAT(intensity);
7284 // send it to the player
7285 multi_io_send_to_all(data, packet_size);
7288 void process_emp_effect(ubyte *data, header *hinfo)
7290 float intensity, time;
7293 int offset = HEADER_LENGTH;
7295 // read in the EMP effect data
7296 GET_USHORT(net_sig);
7297 GET_FLOAT(intensity);
7301 // try and find the object
7302 objp = multi_get_network_object(net_sig);
7303 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7304 // if i'm not an observer and I have a valid ship, play the EMP effect
7305 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7306 emp_start_local(intensity, time);
7309 // start the effect for the ship itself
7310 emp_start_ship(objp, intensity, time);
7314 // tells whether or not reinforcements are available
7315 void send_reinforcement_avail( int rnum )
7320 BUILD_HEADER(REINFORCEMENT_AVAIL);
7322 multi_io_send_to_all_reliable(data, packet_size);
7325 void process_reinforcement_avail( ubyte *data, header *hinfo )
7330 offset = HEADER_LENGTH;
7334 // sanity check for a valid reinforcement number
7335 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7336 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7340 void send_change_iff_packet(ushort net_signature, int new_team)
7342 ubyte data[MAX_PACKET_SIZE];
7343 int packet_size = 0;
7345 if(Net_player == NULL){
7348 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7352 // build the packet and add the data
7353 BUILD_HEADER(CHANGE_IFF);
7354 ADD_USHORT(net_signature);
7357 // send to all players
7358 multi_io_send_to_all_reliable(data, packet_size);
7361 void process_change_iff_packet( ubyte *data, header *hinfo)
7363 int offset = HEADER_LENGTH;
7364 ushort net_signature;
7369 GET_USHORT(net_signature);
7373 // lookup the object
7374 objp = multi_get_network_object(net_signature);
7375 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7376 Ships[objp->instance].team = new_team;
7380 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7382 int packet_size, objnum;
7383 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7386 net_player *ignore = NULL;
7388 // sanity checking for now
7389 SDL_assert ( banks_fired <= 3 );
7391 // get an object pointer for this ship.
7392 objnum = shipp->objnum;
7393 objp = &Objects[objnum];
7395 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7396 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7400 // just in case nothing got fired
7401 if(banks_fired <= 0){
7405 // ubanks_fired = (ubyte)banks_fired;
7406 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7407 // SDL_assert( current_bank <= 3 );
7409 // insert the current primary bank into this byte
7410 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7412 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7413 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7414 // ubanks_fired |= (1<<7);
7417 // determine if its a player ship and don't send to him if we're in "client firing" mode
7418 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7419 if(MULTIPLAYER_MASTER){
7420 np_index = multi_find_player_by_net_signature(objp->net_signature);
7421 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7422 ignore = &Net_players[np_index];
7426 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7427 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7428 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7429 // and server in sync w.r.t. weapon energy for player ship
7430 BUILD_HEADER( PRIMARY_FIRED_NEW );
7431 ADD_USHORT(objp->net_signature);
7432 // ADD_DATA(ubanks_fired);
7434 // if I'm a server, broadcast to all players
7435 if(MULTIPLAYER_MASTER){
7436 multi_io_send_to_all(data, packet_size, ignore);
7439 multi_rate_add(1, "wfi", packet_size);
7441 // otherwise just send to the server
7443 multi_io_send(Net_player, data, packet_size);
7447 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7449 int offset; // linked;
7450 // ubyte banks_fired, current_bank;
7455 // read all packet info
7456 offset = HEADER_LENGTH;
7457 GET_USHORT(shooter_sig);
7458 // GET_DATA(banks_fired);
7461 // find the object this fired packet is operating on
7462 objp = multi_get_network_object( shooter_sig );
7463 if ( objp == NULL ) {
7464 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7467 // if this object is not actually a valid ship, don't do anything
7468 if(objp->type != OBJ_SHIP){
7471 if(objp->instance < 0){
7474 // shipp = &Ships[objp->instance];
7476 // get the link status of the primary banks
7478 // if ( banks_fired & (1<<7) ) {
7480 // banks_fired ^= (1<<7);
7483 // get the current primary bank
7484 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7485 // current_bank &= 0x3;
7486 // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7487 // shipp->weapons.current_primary_bank = current_bank;
7489 // strip off all remaining bits and just keep which banks were actually fired.
7490 // banks_fired &= 0x3;
7492 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7495 // shipp->flags &= ~SF_PRIMARY_LINKED;
7497 // shipp->flags |= SF_PRIMARY_LINKED;
7500 // if we're in client firing mode, ignore ones for myself
7501 if((Player_obj != NULL) && (Player_obj == objp)){
7505 ship_fire_primary( objp, 0, 1 );
7508 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7510 ubyte data[MAX_PACKET_SIZE];
7513 net_player *ignore = NULL;
7515 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7516 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7520 SDL_assert ( cmeasure_count < UCHAR_MAX );
7521 BUILD_HEADER(COUNTERMEASURE_NEW);
7522 ADD_USHORT( objp->net_signature );
7523 ADD_INT( rand_val );
7525 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7527 // determine if its a player ship and don't send to him if we're in "client firing" mode
7528 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7529 if(MULTIPLAYER_MASTER){
7530 np_index = multi_find_player_by_net_signature(objp->net_signature);
7531 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7532 ignore = &Net_players[np_index];
7536 // if I'm the server, send to all players
7537 if(MULTIPLAYER_MASTER){
7538 multi_io_send_to_all(data, packet_size, ignore);
7540 // otherwise send to the server
7542 multi_io_send(Net_player, data, packet_size);
7546 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7553 offset = HEADER_LENGTH;
7554 GET_USHORT( signature );
7555 GET_INT( rand_val );
7558 objp = multi_get_network_object( signature );
7559 if ( objp == NULL ) {
7560 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7563 if(objp->type != OBJ_SHIP){
7567 // if we're in client firing mode, ignore ones for myself
7568 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7569 if((Player_obj != NULL) && (Player_obj == objp)){
7573 // make it so ship can fire right away!
7574 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7575 if ( objp == Player_obj ){
7576 nprintf(("network", "firing countermeasure from my ship\n"));
7578 ship_launch_countermeasure( objp, rand_val );
7581 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7583 ubyte data[MAX_PACKET_SIZE];
7584 int packet_size = 0;
7589 // only the server should ever be doing this
7590 SDL_assert(MULTIPLAYER_MASTER);
7592 // setup outgoing data
7593 SDL_assert(shooter != NULL);
7594 SDL_assert(turret != NULL);
7595 SDL_assert(target != NULL);
7596 SDL_assert(override != NULL);
7597 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7600 u_beam_info = (ubyte)beam_info_index;
7601 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7602 SDL_assert(subsys_index >= 0);
7603 if(subsys_index < 0){
7607 // swap the beam_info override info into little endian byte order
7608 b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7609 b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7610 b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7612 b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7613 b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7614 b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7616 b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7617 b_info.shot_count = override->shot_count;
7619 for (int i = 0; i < b_info.shot_count; i++) {
7620 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7624 BUILD_HEADER(BEAM_FIRED);
7625 ADD_USHORT(shooter->net_signature);
7626 ADD_DATA(subsys_index);
7627 ADD_USHORT(target->net_signature);
7628 ADD_DATA(u_beam_info);
7629 ADD_DATA(b_info); // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7631 // send to all clients
7632 multi_io_send_to_all_reliable(data, packet_size);
7635 void process_beam_fired_packet(ubyte *data, header *hinfo)
7638 ushort shooter_sig, target_sig;
7642 beam_fire_info fire_info;
7644 // only clients should ever get this
7645 SDL_assert(MULTIPLAYER_CLIENT);
7647 // read in packet data
7648 offset = HEADER_LENGTH;
7649 GET_USHORT(shooter_sig);
7650 GET_DATA(subsys_index);
7651 GET_USHORT(target_sig);
7652 GET_DATA(u_beam_info);
7657 // swap the beam_info override info into native byte order
7658 b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7659 b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7660 b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7661 b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7662 b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7663 b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7664 b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7666 for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7667 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7670 // lookup all relevant data
7671 fire_info.beam_info_index = (int)u_beam_info;
7672 fire_info.shooter = NULL;
7673 fire_info.target = NULL;
7674 fire_info.turret = NULL;
7675 fire_info.target_subsys = NULL;
7676 fire_info.beam_info_override = NULL;
7677 fire_info.shooter = multi_get_network_object(shooter_sig);
7678 fire_info.target = multi_get_network_object(target_sig);
7679 fire_info.beam_info_override = &b_info;
7680 fire_info.accuracy = 1.0f;
7681 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)){
7682 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7685 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7686 if(fire_info.turret == NULL){
7687 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7692 beam_fire(&fire_info);
7695 void send_sw_query_packet(ubyte code, char *txt)
7697 ubyte data[MAX_PACKET_SIZE];
7698 int packet_size = 0;
7700 // build the packet and add the code
7701 BUILD_HEADER(SW_STD_QUERY);
7703 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7707 // if I'm the host, send to standalone
7708 if(MULTIPLAYER_HOST){
7709 SDL_assert(!MULTIPLAYER_MASTER);
7710 SDL_assert(code == SW_STD_START);
7711 multi_io_send_reliable(Net_player, data, packet_size);
7713 // otherwise standalone sends back to host
7715 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7716 SDL_assert(code != SW_STD_START);
7717 SDL_assert(Netgame.host != NULL);
7718 if(Netgame.host != NULL){
7719 multi_io_send_reliable(Netgame.host, data, packet_size);
7724 void process_sw_query_packet(ubyte *data, header *hinfo)
7728 void send_event_update_packet(int event)
7730 ubyte data[MAX_PACKET_SIZE];
7731 ushort u_event = (ushort)event;
7732 int packet_size = 0;
7734 // build the header and add the event
7735 BUILD_HEADER(EVENT_UPDATE);
7736 ADD_USHORT(u_event);
7737 ADD_INT(Mission_events[event].flags);
7738 ADD_INT(Mission_events[event].formula);
7739 ADD_INT(Mission_events[event].result);
7740 ADD_INT(Mission_events[event].count);
7742 // send to all players
7743 multi_io_send_to_all_reliable(data, packet_size);
7746 void process_event_update_packet(ubyte *data, header *hinfo)
7748 int offset = HEADER_LENGTH;
7753 GET_USHORT(u_event);
7754 store_flags = Mission_events[u_event].flags;
7755 GET_INT(Mission_events[u_event].flags);
7756 GET_INT(Mission_events[u_event].formula);
7757 GET_INT(Mission_events[u_event].result);
7758 GET_INT(Mission_events[u_event].count);
7761 // went from non directive special to directive special
7762 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7763 mission_event_set_directive_special(u_event);
7765 // if we went directive special to non directive special
7766 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7767 mission_event_unset_directive_special(u_event);
7771 // weapon detonate packet
7772 void send_weapon_detonate_packet(object *objp)
7774 ubyte data[MAX_PACKET_SIZE];
7775 int packet_size = 0;
7778 SDL_assert(MULTIPLAYER_MASTER);
7779 if(!MULTIPLAYER_MASTER){
7782 SDL_assert(objp != NULL);
7787 // build the header and add the data
7788 BUILD_HEADER(WEAPON_DET);
7789 ADD_USHORT(objp->net_signature);
7791 // send to all players
7792 multi_io_send_to_all(data, packet_size);
7795 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7798 int offset = HEADER_LENGTH;
7799 object *objp = NULL;
7801 // get the weapon signature
7802 GET_USHORT(net_sig);
7805 // lookup the weapon
7806 objp = multi_get_network_object(net_sig);
7807 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7808 weapon_detonate(objp);
7812 // flak fired packet
7813 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7816 ushort pnet_signature;
7817 ubyte data[MAX_PACKET_SIZE], cindex;
7823 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7827 // local setup -- be sure we are actually passing a weapon!!!!
7828 objp = &Objects[weapon_objnum];
7829 SDL_assert ( objp->type == OBJ_WEAPON );
7830 pnet_signature = Objects[ship_objnum].net_signature;
7832 SDL_assert( subsys_index < UCHAR_MAX );
7833 cindex = (ubyte)subsys_index;
7835 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7840 // build the fire turret packet.
7841 BUILD_HEADER(FLAK_FIRED);
7842 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7843 ADD_USHORT( pnet_signature );
7845 val = (short)ssp->submodel_info_1.angs.h;
7847 val = (short)ssp->submodel_info_2.angs.p;
7849 ADD_FLOAT( flak_range );
7851 multi_io_send_to_all(data, packet_size);
7853 multi_rate_add(1, "flk", packet_size);
7856 void process_flak_fired_packet(ubyte *data, header *hinfo)
7858 int offset, weapon_objnum, wid;
7859 ushort pnet_signature;
7867 short pitch, heading;
7870 // get the data for the turret fired packet
7871 offset = HEADER_LENGTH;
7872 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7873 GET_USHORT( pnet_signature );
7874 GET_DATA( turret_index );
7875 GET_SHORT( heading );
7877 GET_FLOAT( flak_range );
7878 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7881 objp = multi_get_network_object( pnet_signature );
7882 if ( objp == NULL ) {
7883 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7887 // if this isn't a ship, do nothing
7888 if ( objp->type != OBJ_SHIP ){
7892 // make an orientation matrix from the o_fvec
7893 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7895 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7896 // hack, but should be suitable.
7897 shipp = &Ships[objp->instance];
7898 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7902 wid = ssp->system_info->turret_weapon_type;
7903 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7907 // bash the position and orientation of the turret
7908 ssp->submodel_info_1.angs.h = (float)heading;
7909 ssp->submodel_info_2.angs.p = (float)pitch;
7911 // get the world position of the weapon
7912 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7914 // create the weapon object
7915 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7916 if (weapon_objnum != -1) {
7917 if ( Weapon_info[wid].launch_snd != -1 ) {
7918 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7921 // create a muzzle flash from a flak gun based upon firing position and weapon type
7922 flak_muzzle_flash(&pos, &dir, wid);
7924 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7925 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7929 #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);
7930 #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);
7932 // player pain packet
7933 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7935 ubyte data[MAX_PACKET_SIZE];
7938 int packet_size = 0;
7940 SDL_assert(MULTIPLAYER_MASTER);
7941 if(!MULTIPLAYER_MASTER){
7944 SDL_assert(pl != NULL);
7949 // build the packet and add the code
7950 BUILD_HEADER(NETPLAYER_PAIN);
7951 windex = (ubyte)weapon_info_index;
7953 udamage = (ushort)damage;
7954 ADD_USHORT(udamage);
7955 //ADD_DATA((*force));
7956 add_vector_data( data, &packet_size, *force );
7957 //ADD_DATA((*hitpos));
7958 add_vector_data( data, &packet_size, *hitpos );
7960 // send to the player
7961 multi_io_send(pl, data, packet_size);
7963 multi_rate_add(1, "pai", packet_size);
7966 void process_player_pain_packet(ubyte *data, header *hinfo)
7971 vector force = ZERO_VECTOR;
7972 vector local_hit_pos = ZERO_VECTOR;
7975 // get the data for the pain packet
7976 offset = HEADER_LENGTH;
7978 GET_USHORT(udamage);
7980 get_vector_data( data, &offset, force );
7981 //GET_DATA(local_hit_pos);
7982 get_vector_data( data, &offset, local_hit_pos );
7985 mprintf(("PAIN!\n"));
7987 // get weapon info pointer
7988 //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)); // always true
7989 if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7992 wip = &Weapon_info[windex];
7994 // play the weapon hit sound
7995 SDL_assert(Player_obj != NULL);
7996 if(Player_obj == NULL){
7999 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
8001 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
8002 ship_hit_pain((float)udamage);
8005 ship_apply_whack(&force, &local_hit_pos, Player_obj);
8009 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8011 ubyte data[MAX_PACKET_SIZE];
8013 int packet_size = 0;
8015 // build the header and add the data
8016 BUILD_HEADER(LIGHTNING_PACKET);
8017 val = (char)bolt_type;
8019 //ADD_DATA((*start));
8020 add_vector_data( data, &packet_size, *start );
8021 //ADD_DATA((*strike));
8022 add_vector_data( data, &packet_size, *strike );
8024 // send to everyone unreliable for now
8025 multi_io_send_to_all(data, packet_size);
8028 void process_lightning_packet(ubyte *data, header *hinfo)
8032 vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8035 offset = HEADER_LENGTH;
8036 GET_DATA(bolt_type);
8038 get_vector_data(data, &offset, start);
8039 // GET_DATA(strike);
8040 get_vector_data(data, &offset, strike);
8049 nebl_bolt(bolt_type, &start, &strike);
8052 void send_bytes_recvd_packet(net_player *pl)
8054 // only clients should ever be doing this
8059 ubyte data[MAX_PACKET_SIZE];
8060 int packet_size = 0;
8061 BUILD_HEADER(BYTES_SENT);
8062 ADD_INT(pl->cl_bytes_recvd);
8064 // send to the server
8065 multi_io_send_reliable(pl, data, packet_size);
8068 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8072 net_player *pl = NULL;
8073 int offset = HEADER_LENGTH;
8079 if(Net_player == NULL){
8082 if(!MULTIPLAYER_MASTER){
8086 // make sure we know what player sent this
8087 pid = find_player_id(hinfo->id);
8088 if((pid < 0) || (pid >= MAX_PLAYERS)){
8091 pl = &Net_players[pid];
8094 pl->cl_bytes_recvd = bytes;
8098 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8101 pl->sv_bytes_sent = 0;
8105 void send_host_captain_change_packet(short player_id, int captain_change)
8107 ubyte data[MAX_PACKET_SIZE];
8108 int packet_size = 0;
8111 BUILD_HEADER(TRANSFER_HOST);
8112 ADD_SHORT(player_id);
8113 ADD_INT(captain_change);
8116 multi_io_send_to_all_reliable(data, packet_size);
8119 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8121 int offset = HEADER_LENGTH;
8122 int idx, found_player, captain_change;
8125 // get the player id
8126 GET_SHORT(player_id);
8127 GET_INT(captain_change);
8133 for(idx=0; idx<MAX_PLAYERS; idx++){
8134 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8135 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8140 // unflag all old players
8141 for(idx=0; idx<MAX_PLAYERS; idx++){
8142 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8147 for(idx=0; idx<MAX_PLAYERS; idx++){
8148 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8149 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8151 // spew to the HUD config
8152 if(Net_players[idx].player != NULL){
8153 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8163 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8168 void send_self_destruct_packet()
8170 ubyte data[MAX_PACKET_SIZE];
8171 int packet_size = 0;
8174 if(Net_player == NULL){
8178 // if i'm the server, I shouldn't be here
8179 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8180 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8184 // only if this is valid
8185 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8190 if((Player_ship == NULL) || (Player_obj == NULL)){
8195 BUILD_HEADER(SELF_DESTRUCT);
8196 ADD_USHORT(Player_obj->net_signature);
8198 // send to the server
8199 multi_io_send_reliable(Net_player, data, packet_size);
8202 void process_self_destruct_packet(ubyte *data, header *hinfo)
8204 int offset = HEADER_LENGTH;
8208 // get the net signature
8209 GET_USHORT(net_sig);
8213 np_index = find_player_id(hinfo->id);
8217 if(MULTI_OBSERVER(Net_players[np_index])){
8220 if(Net_players[np_index].player == NULL){
8223 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8226 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8229 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8232 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8237 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);