2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Network/MultiMsgs.cpp $
15 * C file that holds functions for the building and processing of multiplayer packets
18 * Revision 1.11 2006/04/26 19:48:58 taylor
19 * various big-endian fixes, mainly networking support related
21 * Revision 1.10 2005/10/02 09:30:10 taylor
22 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
24 * Revision 1.9 2005/08/12 08:59:17 taylor
27 * Revision 1.8 2004/09/20 01:31:44 theoddone33
30 * Revision 1.7 2004/06/11 01:49:45 tigital
31 * byte-swapping changes for bigendian systems
33 * Revision 1.6 2003/08/03 16:10:29 taylor
34 * cleanup; compile warning fixes
36 * Revision 1.5 2002/06/17 06:33:10 relnev
37 * ryan's struct patch for gcc 2.95
39 * Revision 1.4 2002/06/09 04:41:24 relnev
40 * added copyright header
42 * Revision 1.3 2002/05/26 20:49:54 theoddone33
45 * Revision 1.2 2002/05/07 03:16:47 theoddone33
46 * The Great Newline Fix
48 * Revision 1.1.1.1 2002/05/03 03:28:10 root
52 * 83 9/14/99 2:21p Dave
53 * Fixed observer mode joining and ingame stuff.
55 * 82 9/14/99 3:26a Dave
56 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
57 * respawn-too-early problem. Made a few crash points safe.
59 * 81 9/13/99 4:52p Dave
62 * 80 9/08/99 10:01p Dave
63 * Make sure game won't run in a drive's root directory. Make sure
64 * standalone routes suqad war messages properly to the host.
66 * 79 8/28/99 4:54p Dave
67 * Fixed directives display for multiplayer clients for wings with
68 * multiple waves. Fixed hud threat indicator rendering color.
70 * 78 8/27/99 12:32a Dave
71 * Allow the user to specify a local port through the launcher.
73 * 77 8/26/99 8:51p Dave
74 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
76 * 76 8/25/99 4:38p Dave
77 * Updated PXO stuff. Make squad war report stuff much more nicely.
79 * 75 8/24/99 1:50a Dave
80 * Fixed client-side afterburner stuttering. Added checkbox for no version
81 * checking on PXO join. Made button info passing more friendly between
84 * 74 8/22/99 5:53p Dave
85 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
86 * instead of ship designations for multiplayer players.
88 * 73 8/22/99 1:55p Dave
89 * Cleaned up host/team-captain leaving code.
91 * 72 8/22/99 1:19p Dave
92 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
93 * which d3d cards are detected.
95 * 71 8/19/99 10:59a Dave
96 * Packet loss detection.
98 * 70 8/17/99 1:12p Dave
99 * Send TvT update when a client has finished joining so he stays nice and
102 * 69 8/16/99 4:05p Dave
103 * Big honking checkin.
105 * 68 8/11/99 5:54p Dave
106 * Fixed collision problem. Fixed standalone ghost problem.
108 * 67 8/06/99 9:46p Dave
109 * Hopefully final changes for the demo.
111 * 66 8/05/99 2:06a Dave
114 * 65 7/30/99 7:01p Dave
115 * Dogfight escort gauge. Fixed up laser rendering in Glide.
117 * 64 7/29/99 5:41p Jefff
118 * Sound hooks for cmeasure success
120 * 63 7/28/99 5:34p Dave
121 * Nailed the missing stats bug to the wall. Problem was optimized build
122 * and using GET_DATA() with array elements. BLECH.
124 * 62 7/26/99 5:50p Dave
125 * Revised ingame join. Better? We'll see....
127 * 61 7/24/99 1:54p Dave
128 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
131 * 60 7/22/99 7:17p Dave
132 * Fixed excessive whacks in multiplayer.
134 * 59 7/08/99 10:53a Dave
135 * New multiplayer interpolation scheme. Not 100% done yet, but still
136 * better than the old way.
138 * 58 7/03/99 5:50p Dave
139 * Make rotated bitmaps draw properly in padlock views.
141 * 57 7/03/99 4:08p Dave
142 * Fixed wss_slots size issues. Fixed potentially nasty bug in low level
145 * 56 6/21/99 7:24p Dave
146 * netplayer pain packet. Added type E unmoving beams.
148 * 55 6/18/99 5:16p Dave
149 * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
150 * dialog to PXO screen.
152 * 54 6/16/99 4:06p Dave
153 * New pilot info popup. Added new draw-bitmap-as-poly function.
155 * 53 6/16/99 10:20a Dave
156 * Added send-message-list sexpression.
158 * 52 6/04/99 3:52p Anoop
159 * Removed bogus assert.
161 * 51 6/01/99 8:35p Dave
162 * Finished lockarm weapons. Added proper supercap weapons/damage. Added
163 * awacs-set-radius sexpression.
165 * 50 5/21/99 5:03p Andsager
166 * Add code to display engine wash death. Modify ship_kill_packet
168 * 49 5/18/99 1:30p Dave
169 * Added muzzle flash table stuff.
171 * 48 5/14/99 1:59p Andsager
172 * Multiplayer message for subsystem cargo revealed.
174 * 47 5/14/99 12:15p Andsager
175 * Add vaporized to kill packet
177 * 46 5/03/99 8:32p Dave
178 * New version of multi host options screen.
180 * 45 4/30/99 12:18p Dave
181 * Several minor bug fixes.
183 * 44 4/29/99 2:29p Dave
184 * Made flak work much better in multiplayer.
186 * 43 4/28/99 11:13p Dave
187 * Temporary checkin of artillery code.
189 * 42 4/16/99 5:54p Dave
190 * Support for on/off style "stream" weapons. Real early support for
191 * target-painting lasers.
193 * 41 4/12/99 2:22p Dave
194 * More checks for dogfight stats.
196 * 40 4/09/99 2:21p Dave
197 * Multiplayer beta stuff. CD checking.
199 * 39 4/02/99 9:55a Dave
200 * Added a few more options in the weapons.tbl for beam weapons. Attempt
201 * at putting "pain" packets into multiplayer.
203 * 38 4/01/99 3:41p Anoop
204 * Removed bogus Int3().
206 * 37 3/19/99 9:51a Dave
207 * Checkin to repair massive source safe crash. Also added support for
208 * pof-style nebulae, and some new weapons code.
210 * 38 3/12/99 2:32p Anoop
211 * Removed bogus asserts.
213 * 37 3/11/99 11:41a Neilk
214 * Don't do multi_io_* operations in single-player
216 * 36 3/10/99 6:50p Dave
217 * Changed the way we buffer packets for all clients. Optimized turret
218 * fired packets. Did some weapon firing optimizations.
220 * 35 3/09/99 6:24p Dave
221 * More work on object update revamping. Identified several sources of
222 * unnecessary bandwidth.
224 * 34 3/08/99 7:03p Dave
225 * First run of new object update system. Looks very promising.
227 * 33 3/04/99 6:09p Dave
228 * Added in sexpressions for firing beams and checking for if a ship is
231 * 32 3/01/99 10:00a Dave
232 * Fxied several dogfight related stats bugs.
234 * 31 2/24/99 2:25p Dave
235 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
236 * bug for dogfight more.
238 * 30 2/23/99 2:29p Dave
239 * First run of oldschool dogfight mode.
241 * 29 2/21/99 6:01p Dave
242 * Fixed standalone WSS packets.
244 * 28 2/21/99 1:48p Dave
245 * Some code for monitoring datarate for multiplayer in detail.
247 * 27 2/17/99 2:11p Dave
248 * First full run of squad war. All freespace and tracker side stuff
251 * 26 2/12/99 6:16p Dave
252 * Pre-mission Squad War code is 95% done.
254 * 25 2/11/99 3:08p Dave
255 * PXO refresh button. Very preliminary squad war support.
257 * 24 1/29/99 5:07p Dave
258 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
261 * 23 1/27/99 9:56a Dave
262 * Temporary checkin of beam weapons for Dan to make cool sounds.
264 * 22 1/26/99 6:33p Anoop
265 * Fixed multiplayer slot switching problem (be sure to remember that
266 * hinfo->id is player id# _not_ player index #)
268 * 21 1/24/99 11:37p Dave
269 * First full rev of beam weapons. Very customizable. Removed some bogus
270 * Int3()'s in low level net code.
272 * 20 1/15/99 4:37p Dave
273 * Potential fix for weapon pair problem.
275 * 19 1/14/99 6:06p Dave
276 * 100% full squad logo support for single player and multiplayer.
278 * 18 1/14/99 12:48a Dave
279 * Todo list bug fixes. Made a pass at putting briefing icons back into
280 * FRED. Sort of works :(
282 * 17 1/12/99 5:45p Dave
283 * Moved weapon pipeline in multiplayer to almost exclusively client side.
284 * Very good results. Bandwidth goes down, playability goes up for crappy
285 * connections. Fixed object update problem for ship subsystems.
287 * 16 1/08/99 4:56p Anoop
288 * Fixed a problem with wss request packets.
290 * 15 12/18/98 12:24p Markm
291 * Fixed a dumb bug where player image_filenames were not being passed
292 * properly in new players packet.
294 * 14 12/14/98 12:13p Dave
295 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
298 * 13 11/30/98 1:07p Dave
299 * 16 bit conversion, first run.
301 * 12 11/20/98 4:08p Dave
302 * Fixed flak effect in multiplayer.
304 * 11 11/19/98 4:19p Dave
305 * Put IPX sockets back in psnet. Consolidated all multiplayer config
308 * 10 11/19/98 8:04a Dave
309 * Full support for D3-style reliable sockets. Revamped packet lag/loss
310 * system, made it receiver side and at the lowest possible level.
312 * 9 11/17/98 11:12a Dave
313 * Removed player identification by address. Now assign explicit id #'s.
315 * 8 11/12/98 11:50a Dave
316 * Multiplayer clients set flak range to be very long.
318 * 7 11/12/98 12:13a Dave
319 * Tidied code up for multiplayer test. Put in network support for flak
322 * 6 11/05/98 5:55p Dave
323 * Big pass at reducing #includes
325 * 5 10/20/98 1:39p Andsager
326 * Make so sparks follow animated ship submodels. Modify
327 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
328 * submodel_num. Add submodel_num to multiplayer hit packet.
330 * 4 10/13/98 9:29a Dave
331 * Started neatening up freespace.h. Many variables renamed and
332 * reorganized. Added AlphaColors.[h,cpp]
334 * 3 10/07/98 6:27p Dave
335 * Globalized mission and campaign file extensions. Removed Silent Threat
336 * special code. Moved \cache \players and \multidata into the \data
339 * 2 10/07/98 10:53a Dave
342 * 1 10/07/98 10:50a Dave
344 * 506 10/02/98 3:22p Allender
345 * fix up the -connect option and fix the -port option
347 * 505 10/02/98 11:45a Dave
348 * Fixed stupid chat message bug.
350 * 504 9/29/98 1:33p Dave
351 * Remove standalone only conditional compiles for pre 1.04 stuff.
353 * 503 9/28/98 1:54p Dave
354 * Make sure French and German don't xfer builtin files they don't have
357 * 502 9/20/98 7:19p Dave
358 * Added CHANGE_IFF packet.
360 * 501 9/17/98 3:08p Dave
361 * PXO to non-pxo game warning popup. Player icon stuff in create and join
362 * game screens. Upped server count refresh time in PXO to 35 secs (from
371 #include <io.h> // for findfirst/findnext, etc
374 #include "multimsgs.h"
375 #include "multiutil.h"
378 #include "multiteamselect.h"
379 #include "linklist.h"
380 #include "gamesequence.h"
381 #include "hudmessage.h"
382 #include "hudsquadmsg.h"
383 #include "freespace.h"
387 #include "missiongoals.h"
388 #include "missionparse.h"
389 #include "missionlog.h"
390 #include "missionmessage.h"
391 #include "missionbrief.h"
393 #include "cmeasure.h"
394 #include "model.h" // for some limits
395 #include "afterburner.h"
396 #include "stand_gui.h"
397 #include "multi_xfer.h"
403 #include "managepilot.h"
404 #include "hudsquadmsg.h"
406 #include "missionweaponchoice.h"
407 #include "missionshipchoice.h"
408 #include "fireballs.h"
411 #include "multi_ingame.h"
412 #include "multiteamselect.h"
414 #include "multi_campaign.h"
415 #include "multi_team.h"
416 #include "multi_respawn.h"
417 #include "multi_observer.h"
418 #include "multi_voice.h"
419 #include "asteroid.h"
420 #include "multi_pmsg.h"
421 #include "multi_data.h"
422 #include "multi_options.h"
423 #include "objcollide.h"
424 #include "hudreticle.h"
425 #include "multi_pause.h"
426 #include "multi_endgame.h"
427 #include "missiondebrief.h"
428 #include "multi_obj.h"
429 #include "multi_log.h"
431 #include "multi_kick.h"
435 #include "multi_rate.h"
436 #include "neblightning.h"
437 #include "hudescort.h"
439 // #define _MULTI_SUPER_WACKY_COMPRESSION
441 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
443 #define MAX_CODE ( ( 1 << BITS ) - 1 )
444 #define TABLE_SIZE 35023L
445 #define END_OF_STREAM 256
446 #define BUMP_CODE 257
447 #define FLUSH_CODE 258
448 #define FIRST_CODE 259
457 static DICTIONARY dict[TABLE_SIZE];
458 static char decode_stack[TABLE_SIZE];
459 static uint next_code;
460 static int current_code_bits;
461 static uint next_bump_code;
463 typedef struct BitBuf {
469 void output_bits( BitBuf *bitbuf, uint code, int count )
473 mask = 1L << ( count - 1 );
476 bitbuf->rack |= bitbuf->mask;
478 if ( bitbuf->mask == 0 ) {
479 *bitbuf->data++=(ubyte)bitbuf->rack;
487 uint input_bits( BitBuf *bitbuf, int bit_count )
492 mask = 1L << ( bit_count - 1 );
495 if ( bitbuf->mask == 0x80 ) {
496 bitbuf->rack = *bitbuf->data++;
497 if ( bitbuf->rack == EOF )
498 return END_OF_STREAM;
500 if ( bitbuf->rack & bitbuf->mask )
501 return_value |= mask;
504 if ( bitbuf->mask == 0 )
507 return( return_value );
511 static void InitializeDictionary()
515 for ( i = 0 ; i < TABLE_SIZE ; i++ )
516 dict[i].code_value = UNUSED;
518 next_code = FIRST_CODE;
519 current_code_bits = 9;
520 next_bump_code = 511;
524 static uint find_child_node( int parent_code, int child_character )
529 index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
533 offset = TABLE_SIZE - index;
535 if ( dict[ index ].code_value == UNUSED )
536 return( (uint) index );
537 if ( dict[ index ].parent_code == parent_code &&
538 dict[ index ].character == (char) child_character )
540 if ( (int) index >= offset )
543 index += TABLE_SIZE - offset;
548 static uint decode_string( uint count, uint code )
550 while ( code > 255 ) {
551 decode_stack[ count++ ] = dict[ code ].character;
552 code = dict[ code ].parent_code;
554 decode_stack[ count++ ] = (char) code;
558 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size )
566 // Init output bit buffer
569 output.data = outputbuf;
571 InitializeDictionary();
573 string_code = *inputbuf++;
575 for ( i=1 ; i<input_size ; i++ ) {
576 character = *inputbuf++;
577 index = find_child_node( string_code, character );
578 if ( dict[ index ].code_value != - 1 )
579 string_code = dict[ index ].code_value;
581 dict[ index ].code_value = next_code++;
582 dict[ index ].parent_code = string_code;
583 dict[ index ].character = (char) character;
584 output_bits( &output, (unsigned long) string_code, current_code_bits );
585 string_code = character;
586 if ( next_code > MAX_CODE ) {
587 output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
588 InitializeDictionary();
589 } else if ( next_code > next_bump_code ) {
590 output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
592 next_bump_code <<= 1;
597 output_bits( &output, (unsigned long) string_code, current_code_bits );
598 output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
600 if ( output.mask != 0x80 )
601 *output.data++ = (ubyte)output.rack;
603 return output.data-outputbuf;
607 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf )
618 input.data = inputbuf;
622 InitializeDictionary();
623 old_code = (uint) input_bits( &input, current_code_bits );
624 if ( old_code == END_OF_STREAM )
626 character = old_code;
627 outputbuf[counter++] = ( ubyte )old_code;
629 new_code = (uint) input_bits( &input, current_code_bits );
630 if ( new_code == END_OF_STREAM )
632 if ( new_code == FLUSH_CODE )
634 if ( new_code == BUMP_CODE ) {
638 if ( new_code >= next_code ) {
639 decode_stack[ 0 ] = (char) character;
640 count = decode_string( 1, old_code );
642 count = decode_string( 0, new_code );
644 character = decode_stack[ count - 1 ];
646 outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
647 dict[ next_code ].parent_code = old_code;
648 dict[ next_code ].character = (char) character;
656 // process a join request packet add
657 void add_join_request(ubyte *data, int *size, join_request *jr)
659 int packet_size = *size;
660 join_request *jr_tmp = jr;
662 jr_tmp->tracker_id = INTEL_INT(jr->tracker_id);
663 jr_tmp->player_options.flags = INTEL_INT(jr->player_options.flags);
664 jr_tmp->player_options.obj_update_level = INTEL_INT(jr->player_options.obj_update_level);
671 // process a join request packet get
672 void get_join_request(ubyte *data, int *size, join_request jr)
678 jr.tracker_id = INTEL_INT(jr.tracker_id);
679 jr.player_options.flags = INTEL_INT(jr.player_options.flags);
680 jr.player_options.obj_update_level = INTEL_INT(jr.player_options.obj_update_level);
685 void add_net_addr(ubyte *data, int *size, net_addr addr)
687 int packet_size = *size;
688 net_addr addr_tmp = addr;
690 addr_tmp.type = INTEL_INT(addr.type);
691 addr_tmp.port = INTEL_SHORT(addr.port);
698 void get_net_addr(ubyte *data, int *size, net_addr addr)
704 addr.type = INTEL_INT(addr.type);
705 addr.port = INTEL_SHORT(addr.port);
710 void add_vector_data(ubyte *data, int *size, vector vec)
712 int packet_size = *size;
714 ADD_FLOAT(vec.xyz.x);
715 ADD_FLOAT(vec.xyz.y);
716 ADD_FLOAT(vec.xyz.z);
721 void get_vector_data(ubyte *data, int *size, vector vec)
725 GET_FLOAT(vec.xyz.x);
726 GET_FLOAT(vec.xyz.y);
727 GET_FLOAT(vec.xyz.z);
732 // send the specified data packet to all players
733 void multi_io_send(net_player *pl, ubyte *data, int len)
736 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
740 // don't do it for single player
741 if(!(Game_mode & GM_MULTIPLAYER)){
746 if(MULTIPLAYER_CLIENT){
747 // SDL_assert(pl == Net_player);
748 if(pl != Net_player){
752 // SDL_assert(pl != Net_player);
753 if(pl == Net_player){
758 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
759 if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
760 multi_io_send_force(pl);
761 pl->s_info.unreliable_buffer_size = 0;
764 SDL_assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
766 memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
767 pl->s_info.unreliable_buffer_size += len;
770 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
773 SDL_assert(MULTIPLAYER_MASTER);
775 // need to check for i > 1, hmmm... and connected. I don't know.
776 for (i = 0; i < MAX_PLAYERS; i++ ) {
777 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
781 // maybe ignore a player
782 if((ignore != NULL) && (&Net_players[i] == ignore)){
786 // ingame joiners not waiting to select a ship doesn't get any packets
787 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
792 multi_io_send(&Net_players[i], data, length);
796 void multi_io_send_force(net_player *pl)
799 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
803 // don't do it for single player
804 if(!(Game_mode & GM_MULTIPLAYER)){
808 // send everything in
809 if (MULTIPLAYER_MASTER) {
810 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
812 // add the bytes sent to this player
813 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
815 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
817 pl->s_info.unreliable_buffer_size = 0;
820 // send the data packet to all players via their reliable sockets
821 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
824 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
828 // don't do it for single player
829 if(!(Game_mode & GM_MULTIPLAYER)){
834 if(MULTIPLAYER_CLIENT){
835 // SDL_assert(pl == Net_player);
836 if(pl != Net_player){
840 // SDL_assert(pl != Net_player);
841 if(pl == Net_player){
846 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
847 if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
848 multi_io_send_reliable_force(pl);
849 pl->s_info.reliable_buffer_size = 0;
852 SDL_assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
854 memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
855 pl->s_info.reliable_buffer_size += len;
858 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
861 SDL_assert(MULTIPLAYER_MASTER);
863 // need to check for i > 1, hmmm... and connected. I don't know.
864 for (i = 0; i < MAX_PLAYERS; i++ ) {
865 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
869 // maybe ignore a player
870 if((ignore != NULL) && (&Net_players[i] == ignore)){
874 // ingame joiners not waiting to select a ship doesn't get any packets
875 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
880 multi_io_send_reliable(&Net_players[i], data, length);
884 void multi_io_send_reliable_force(net_player *pl)
887 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
891 // don't do it for single player
892 if(!(Game_mode & GM_MULTIPLAYER)){
896 // send everything in
897 if(MULTIPLAYER_MASTER) {
898 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
899 } else if(Net_player != NULL){
900 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
902 pl->s_info.reliable_buffer_size = 0;
905 // send all buffered packets
906 void multi_io_send_buffered_packets()
910 // don't do it for single player
911 if(!(Game_mode & GM_MULTIPLAYER)){
916 if(MULTIPLAYER_MASTER){
917 for(idx=0; idx<MAX_PLAYERS; idx++){
918 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
919 // force unreliable data
920 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
921 multi_io_send_force(&Net_players[idx]);
922 Net_players[idx].s_info.unreliable_buffer_size = 0;
925 // force reliable data
926 if(Net_players[idx].s_info.reliable_buffer_size > 0){
927 multi_io_send_reliable_force(&Net_players[idx]);
928 Net_players[idx].s_info.reliable_buffer_size = 0;
934 else if(Net_player != NULL){
935 // force unreliable data
936 if(Net_player->s_info.unreliable_buffer_size > 0){
937 multi_io_send_force(Net_player);
938 Net_player->s_info.unreliable_buffer_size = 0;
941 // force reliable data
942 if(Net_player->s_info.reliable_buffer_size > 0){
943 multi_io_send_reliable_force(Net_player);
944 Net_player->s_info.reliable_buffer_size = 0;
949 // send a general game chat packet (if msg_mode == MULTI_MSG_TARGET, need to pass in "to", if == MULTI_MSG_EXPR, need to pass in expr)
950 void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
952 ubyte data[MAX_PACKET_SIZE],mode;
955 BUILD_HEADER(GAME_CHAT);
958 ADD_SHORT(from->player_id);
960 // add the message mode and if in MSG_TARGET mode, add who the target is
962 mode = (ubyte)msg_mode;
965 case MULTI_MSG_TARGET:
966 SDL_assert(to != NULL);
967 ADD_SHORT(to->player_id);
970 SDL_assert(expr != NULL);
974 // add the message itself
977 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
979 // message all players
981 for(idx=0;idx<MAX_PLAYERS;idx++){
982 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
983 multi_io_send_reliable(&Net_players[idx], data, packet_size);
988 // message only friendly players
989 case MULTI_MSG_FRIENDLY:
990 for(idx=0;idx<MAX_PLAYERS;idx++){
991 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team == from->p_info.team)){
992 multi_io_send_reliable(&Net_players[idx], data, packet_size);
997 // message only hostile players
998 case MULTI_MSG_HOSTILE:
999 for(idx=0;idx<MAX_PLAYERS;idx++){
1000 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && (Net_players[idx].p_info.team != from->p_info.team)){
1001 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1006 // message the player's target
1007 case MULTI_MSG_TARGET:
1008 SDL_assert(to != NULL);
1009 if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
1010 multi_io_send_reliable(to, data, packet_size);
1014 // message all players who match the expression string
1015 case MULTI_MSG_EXPR:
1016 SDL_assert(expr != NULL);
1017 for(idx=0;idx<MAX_PLAYERS;idx++){
1018 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
1019 multi_io_send_reliable(&Net_players[idx], data, packet_size);
1025 // send to the server, who will take care of routing it
1027 multi_io_send_reliable(Net_player, data, packet_size);
1031 // process a general game chat packet, if we're the standalone we should rebroadcast
1032 void process_game_chat_packet( ubyte *data, header *hinfo )
1036 int color_index,player_index,to_player_index,should_display,server_msg;
1037 char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
1041 offset = HEADER_LENGTH;
1043 // get the id of the sender
1046 // determine if this is a server message
1047 GET_INT(server_msg);
1052 // if targeting a specific player, get the address
1055 case MULTI_MSG_TARGET:
1058 case MULTI_MSG_EXPR:
1062 // get the message itself
1066 // get the index of the sending player
1067 color_index = find_player_id(from);
1068 player_index = color_index;
1070 // if we couldn't find the player - bail
1071 if(player_index == -1){
1072 nprintf(("Network","Could not find player for processing game chat packet!\n"));
1078 // if we're the server, determine what to do with the packet here
1079 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1080 // if he's targeting a specific player, find out who it is
1081 if(mode == MULTI_MSG_TARGET){
1082 to_player_index = find_player_id(to);
1084 to_player_index = -1;
1087 // if we couldn't find who sent the message or who should be getting the message, the bail
1088 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
1092 // determine if _I_ should be seeing the text
1093 if(Game_mode & GM_STANDALONE_SERVER){
1096 // check against myself for several specific cases
1098 if((mode == MULTI_MSG_ALL) ||
1099 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
1100 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
1101 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
1102 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
1107 // if we're the server of a game, we need to rebroadcast to all other players
1109 // individual target mission
1110 case MULTI_MSG_TARGET:
1111 // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
1112 if(to_player_index != MY_NET_PLAYER_NUM){
1113 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1117 case MULTI_MSG_EXPR:
1118 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1122 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1126 // if a client receives this packet, its always ok for him to display it
1131 // if we're not on a standalone
1133 if(server_msg == 2){
1136 multi_display_chat_msg(msg, player_index, !server_msg);
1141 // broadcast a hud message to all players
1142 void send_hud_msg_to_all( char* msg )
1144 ubyte data[MAX_PACKET_SIZE];
1147 // only the server should be sending this packet
1148 BUILD_HEADER(HUD_MSG);
1152 multi_io_send_to_all( data, packet_size );
1155 // process an incoming hud message packet
1156 void process_hud_message(ubyte* data, header* hinfo)
1159 char msg_buffer[255];
1161 offset = HEADER_LENGTH;
1163 GET_STRING(msg_buffer);
1166 // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1167 if(Game_mode & GM_IN_MISSION){
1168 HUD_printf(msg_buffer);
1172 // send a join packet request to the specified address (should be a server)
1173 void send_join_packet(net_addr* addr,join_request *jr)
1175 ubyte data[MAX_PACKET_SIZE];
1178 // build the header and add the request
1181 add_join_request(data, &packet_size, jr);
1183 psnet_send(addr, data, packet_size);
1186 // process an incoming join request packet
1187 void process_join_packet(ubyte* data, header* hinfo)
1192 int host_restr_mode;
1193 // int team0_avail,team1_avail;
1194 char join_string[255];
1197 // only the server of the game should ever receive this packet
1198 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1201 offset = HEADER_LENGTH;
1203 // read in the request info
1204 memset(&jr,0,sizeof(join_request));
1207 jr.tracker_id = INTEL_INT(jr.tracker_id);
1211 // fill in the address information of where this came from
1212 fill_net_addr(&addr, hinfo->addr, hinfo->port);
1214 // determine if we should accept this guy, or return a reason we should reject him
1215 // see the DENY_* codes in multi.h
1216 ret_code = multi_eval_join_request(&jr,&addr);
1218 // evaluate the return code
1220 // he should be accepted
1224 // we have to query the host because this is a restricted game
1225 case JOIN_QUERY_RESTRICTED :
1226 if(!(Game_mode & GM_STANDALONE_SERVER)){
1227 // notify the host of the event
1228 snd_play(&Snds[SND_CUE_VOICE]);
1231 // set the query timestamp
1232 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1233 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1235 // determine what mode we're in
1236 // host_restr_mode = -1;
1237 memset(join_string,0,255);
1238 // if(Netgame.type == NG_TYPE_TEAM){
1239 // multi_player_ships_available(&team0_avail,&team1_avail);
1241 // if(team0_avail && team1_avail){
1242 // host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1243 // sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1244 // } else if(team0_avail && !team1_avail){
1245 // host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1246 // sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1247 // } else if(!team0_avail && team1_avail){
1248 // host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1249 // sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1251 // } else if(Netgame.mode == NG_MODE_RESTRICTED){
1252 host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1253 SDL_snprintf(join_string,SDL_arraysize(join_string),XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1255 SDL_assert(host_restr_mode != -1);
1257 // store the request info
1258 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1259 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1260 Multi_join_restr_mode = host_restr_mode;
1262 // if i'm the standalone server, I need to send a query to the host
1263 if(Game_mode & GM_STANDALONE_SERVER){
1264 send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1266 HUD_printf(join_string);
1270 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1274 // he'e being denied for some reason
1276 // send him the reason he is being denied
1277 send_deny_packet(&addr,ret_code);
1281 // process the rest of the request
1282 multi_process_valid_join_request(&jr,&addr);
1285 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1286 void send_new_player_packet(int new_player_num,net_player *target)
1288 ubyte data[MAX_PACKET_SIZE], val;
1289 int packet_size = 0;
1291 BUILD_HEADER( NOTIFY_NEW_PLAYER );
1293 // add the new player's info
1294 ADD_INT(new_player_num);
1295 // ADD_DATA(Net_players[new_player_num].p_info.addr);
1297 add_net_addr(data, &packet_size, Net_players[new_player_num].p_info.addr);
1299 ADD_SHORT(Net_players[new_player_num].player_id);
1300 ADD_INT(Net_players[new_player_num].flags);
1301 ADD_STRING(Net_players[new_player_num].player->callsign);
1302 ADD_STRING(Net_players[new_player_num].player->image_filename);
1303 ADD_STRING(Net_players[new_player_num].player->squad_filename);
1304 ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1306 val = (ubyte)Net_players[new_player_num].p_info.team;
1309 // broadcast the data
1311 multi_io_send_reliable(target, data, packet_size);
1313 multi_io_send_to_all_reliable(data, packet_size);
1317 // process a notification for a new player who has joined the game
1318 void process_new_player_packet(ubyte* data, header* hinfo)
1320 int already_in_game = 0;
1321 int offset, new_player_num,player_num,new_flags;
1323 char new_player_name[CALLSIGN_LEN+2] = "";
1324 char new_player_image[MAX_FILENAME_LEN+1] = "";
1325 char new_player_squad[MAX_FILENAME_LEN+1] = "";
1326 char new_player_pxo_squad[LOGIN_LEN+1] = "";
1327 char notify_string[256];
1331 offset = HEADER_LENGTH;
1333 // get the new players information
1334 GET_INT(new_player_num);
1335 memset(&new_addr, 0, sizeof(net_addr));
1336 get_net_addr(data, &offset, new_addr);
1340 GET_STRING(new_player_name);
1341 GET_STRING(new_player_image);
1342 GET_STRING(new_player_squad);
1343 GET_STRING(new_player_pxo_squad);
1347 player_num = multi_find_open_player_slot();
1348 SDL_assert(player_num != -1);
1350 // note that this new code does not check for duplicate IPs. It merely checks to see if
1351 // the slot referenced by new_player_num is already occupied by a connected player
1352 if(MULTI_CONNECTED(Net_players[new_player_num])){
1356 // if he's not alreayd in the game for one reason or another
1357 if ( !already_in_game ) {
1358 if ( Game_mode & GM_IN_MISSION ){
1359 HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1362 // create the player
1363 if(new_flags & NETINFO_FLAG_OBSERVER){
1364 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1365 Net_players[new_player_num].flags |= new_flags;
1367 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1368 Net_players[new_player_num].flags |= new_flags;
1371 // copy in the filename
1372 if(strlen(new_player_image) > 0){
1373 SDL_strlcpy(Net_players[new_player_num].player->image_filename, new_player_image, MAX_FILENAME_LEN);
1375 SDL_strlcpy(Net_players[new_player_num].player->image_filename, "", MAX_FILENAME_LEN);
1377 // copy his pilot squad filename
1378 Net_players[new_player_num].player->insignia_texture = -1;
1379 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1381 // copy in his pxo squad name
1382 SDL_strlcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad, LOGIN_LEN);
1384 // since we just created the player, set the last_heard_time here.
1385 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1387 Net_players[new_player_num].p_info.team = team;
1389 Net_players[new_player_num].player_id = new_id;
1391 // zero out this players ping
1392 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1394 // add a chat message
1395 if(Net_players[new_player_num].player->callsign != NULL){
1396 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1397 multi_display_chat_msg(notify_string,0,0);
1402 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1404 // let the current ui screen know someone joined
1405 switch(gameseq_get_state()){
1406 case GS_STATE_MULTI_HOST_SETUP :
1407 multi_create_handle_join(&Net_players[new_player_num]);
1409 case GS_STATE_MULTI_CLIENT_SETUP :
1410 multi_jw_handle_join(&Net_players[new_player_num]);
1415 #define PLAYER_DATA_SLOP 100
1417 void send_accept_player_data( net_player *npp, int is_ingame )
1421 ubyte data[MAX_PACKET_SIZE], stop;
1423 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1425 // add in the netplayer data for all players
1427 for (i=0; i<MAX_PLAYERS; i++) {
1428 // skip non connected players
1429 if ( !MULTI_CONNECTED(Net_players[i]) ){
1433 // skip this new player's entry
1434 if ( npp->player_id == Net_players[i].player_id ){
1438 // add the stop byte
1441 // add the player's number
1444 // add the player's address
1445 // ADD_DATA(Net_players[i].p_info.addr);
1446 add_net_addr(data, &packet_size, Net_players[i].p_info.addr);
1449 ADD_SHORT(Net_players[i].player_id);
1452 ADD_STRING(Net_players[i].player->callsign);
1454 // add his image filename
1455 ADD_STRING(Net_players[i].player->image_filename);
1457 // add his squad filename
1458 ADD_STRING(Net_players[i].player->squad_filename);
1460 // add his PXO squad name
1461 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1464 ADD_INT(Net_players[i].flags);
1466 // add his object's net sig
1468 ADD_USHORT( Objects[Net_players[i].player->objnum].net_signature );
1471 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1472 stop = APD_END_PACKET;
1474 multi_io_send_reliable( npp, data, packet_size );
1475 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1481 // add the stop byte
1482 stop = APD_END_DATA;
1484 multi_io_send_reliable(npp, data, packet_size);
1487 // send an accept packet to a client in response to a request to join the game
1488 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1490 int packet_size = 0, i;
1491 ubyte data[MAX_PACKET_SIZE],val;
1492 char notify_string[256];
1495 SDL_assert(new_player_num >= 0);
1497 // setup his "reliable" socket
1498 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1500 // build the packet header
1501 BUILD_HEADER(ACCEPT);
1503 // add the accept code
1506 // add code specific accept data
1507 if (code & ACCEPT_INGAME) {
1508 // the game filename
1509 ADD_STRING(Game_current_mission_filename);
1511 // if he is joining on a specific team, mark it here
1512 if(ingame_join_team != -1){
1515 val = (ubyte)ingame_join_team;
1523 if (code & ACCEPT_OBSERVER) {
1524 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1527 if (code & ACCEPT_HOST) {
1528 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1531 if (code & ACCEPT_CLIENT) {
1532 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1535 // add the current skill level setting on the host
1536 ADD_INT(Game_skill_level);
1538 // add this guys player num
1539 ADD_INT(new_player_num);
1541 // add his player id
1542 ADD_SHORT(Net_players[new_player_num].player_id);
1544 // add netgame type flags
1545 ADD_INT(Netgame.type_flags);
1548 // char buffer[100];
1549 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1552 // actually send the packet
1553 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1555 // if he's not an observer, inform all the other players in the game about him
1556 // inform the other players in the game about this new player
1557 for (i=0; i<MAX_PLAYERS; i++) {
1558 // skip unconnected players as well as this new guy himself
1559 if ( !MULTI_CONNECTED(Net_players[i]) || psnet_same(&Net_players[new_player_num].p_info.addr, &(Net_players[i].p_info.addr)) || (Net_player == &Net_players[i])) {
1563 // send the new packet
1564 send_new_player_packet(new_player_num,&Net_players[i]);
1567 // add a chat message
1568 if(Net_players[new_player_num].player->callsign != NULL){
1569 SDL_snprintf(notify_string,SDL_arraysize(notify_string),XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1570 multi_display_chat_msg(notify_string, 0, 0);
1573 // handle any team vs. team details
1574 if (!(code & ACCEPT_OBSERVER)) {
1575 multi_team_handle_join(&Net_players[new_player_num]);
1579 if(Net_players[new_player_num].tracker_player_id >= 0){
1580 ml_printf(NOX("Server accepted %s (tracker id %d) as new client"), Net_players[new_player_num].player->callsign, Net_players[new_player_num].tracker_player_id);
1582 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1587 // process the player data from the server
1588 void process_accept_player_data( ubyte *data, header *hinfo )
1590 int offset, player_num, player_slot_num, new_flags;
1591 char name[CALLSIGN_LEN + 1] = "";
1592 char image_name[MAX_FILENAME_LEN + 1] = "";
1593 char squad_name[MAX_FILENAME_LEN + 1] = "";
1594 char pxo_squad_name[LOGIN_LEN+1] = "";
1598 ushort ig_signature;
1600 offset = HEADER_LENGTH;
1603 while ( stop == APD_NEXT ) {
1604 player_slot_num = multi_find_open_player_slot();
1605 SDL_assert(player_slot_num != -1);
1607 // get the player's number
1608 GET_INT(player_num);
1610 // add the player's address
1611 memset(&addr, 0, sizeof(net_addr));
1612 get_net_addr(data, &offset, addr);
1614 // get the player's id#
1615 GET_SHORT(player_id);
1620 // add his image filename
1621 GET_STRING(image_name);
1623 // get his squad logo filename
1624 GET_STRING(squad_name);
1626 // get his PXO squad name
1627 GET_STRING(pxo_squad_name);
1632 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1633 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1638 // the error handling here is less than stellar. We should probably put up a popup and go
1639 // back to the main menu. But then again, this should never ever happen!
1640 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1645 // copy his image filename
1646 SDL_strlcpy(Net_players[player_num].player->image_filename, image_name, MAX_FILENAME_LEN);
1648 // copy his pilot squad filename
1649 Net_players[player_num].player->insignia_texture = -1;
1650 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1652 // copy his pxo squad name
1653 SDL_strlcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name, LOGIN_LEN);
1655 // set his player id#
1656 Net_players[player_num].player_id = player_id;
1658 // mark him as being connected
1659 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1660 Net_players[player_num].flags |= new_flags;
1662 // set the server pointer
1663 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1664 Netgame.server = &Net_players[player_num];
1665 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1667 // also - always set the server address to be where this data came from, NOT from
1668 // the data in the packet
1669 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->port);
1672 // set the host pointer
1673 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1674 Netgame.host = &Net_players[player_num];
1677 // read in the player's object net signature and store as his objnum for now
1678 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1679 GET_USHORT( ig_signature );
1680 Net_players[player_num].player->objnum = ig_signature;
1683 // get the stop byte
1688 if ( stop == APD_END_DATA ) {
1689 // if joining a game automatically, set the connect address to NULl so we don't try and
1690 // do this next time we enter a game
1691 if (Cmdline_connect_addr != NULL) {
1692 Cmdline_connect_addr = NULL;
1695 // send my stats to the server if I'm not in observer mode
1696 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1697 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1700 // if i'm being accepted as a host, then move into the host setup state
1701 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1702 // set my permission bits
1703 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1704 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1706 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1709 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1710 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1712 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1713 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1714 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1718 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1719 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1722 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1723 // flag myself as being an ingame joiner
1724 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1726 // move myself into the ingame join mission sync state
1727 Multi_sync_mode = MULTI_SYNC_INGAME;
1728 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1731 // update my options on the server
1732 multi_options_update_local();
1734 // if we're in PXO mode, mark it down in our player struct
1735 if(MULTI_IS_TRACKER_GAME){
1736 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1737 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1742 // process an accept packet from the server
1743 extern int Select_default_ship;
1745 void process_accept_packet(ubyte* data, header* hinfo)
1747 int code, my_player_num, offset;
1751 // get the accept code
1752 offset = HEADER_LENGTH;
1756 // read in the accept code specific data
1758 if (code & ACCEPT_INGAME) {
1759 // the game filename
1760 GET_STRING(Game_current_mission_filename);
1761 Select_default_ship = 0;
1763 // determine if I'm being placed on a team
1770 if (code & ACCEPT_OBSERVER) {
1771 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1774 if (code & ACCEPT_HOST) {
1775 SDL_assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1778 if (code & ACCEPT_CLIENT) {
1779 SDL_assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1782 // fill in the netgame server address
1783 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->port );
1785 // get the skill level setting
1786 GET_INT(Game_skill_level);
1788 // get my netplayer number
1789 GET_INT(my_player_num);
1792 GET_SHORT(player_id);
1794 // get netgame type flags
1795 GET_INT(Netgame.type_flags);
1797 // setup the Net_players structure for myself first
1798 Net_player = &Net_players[my_player_num];
1799 Net_player->flags = 0;
1800 Net_player->tracker_player_id = Multi_tracker_id;
1801 Net_player->player_id = player_id;
1802 Net_player->s_info.xfer_handle = -1;
1803 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1804 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1805 multi_options_local_load(&Net_player->p_info.options, Net_player);
1807 Net_player->p_info.team = team;
1810 // determine if I have a CD
1812 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1815 // set accept code in netplayer for this guy
1816 if ( code & ACCEPT_INGAME ){
1817 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1819 if ( code & ACCEPT_OBSERVER ){
1820 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1822 if ( code & ACCEPT_HOST ){
1823 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1825 if ( code & ACCEPT_CLIENT ){
1826 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1829 // if I have hacked data
1830 if(game_hacked_data()){
1831 Net_player->flags |= NETINFO_FLAG_HAXOR;
1834 // if we're supposed to flush our local data cache, do so now
1835 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1836 multi_flush_multidata_cache();
1839 Net_player->sv_bytes_sent = 0;
1840 Net_player->sv_last_pl = -1;
1841 Net_player->cl_bytes_recvd = 0;
1842 Net_player->cl_last_pl = -1;
1844 // intiialize endgame stuff
1845 multi_endgame_init();
1849 // make a call to psnet to initialize and try to connect with the server.
1850 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1851 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1852 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1856 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1857 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1859 ubyte data[MAX_PACKET_SIZE];
1861 int packet_size = 0;
1863 BUILD_HEADER(LEAVE_GAME);
1865 // add a flag indicating whether he was kicked or not
1866 val = (char)kicked_reason;
1869 if (player_id < 0) {
1870 ADD_SHORT(Net_player->player_id);
1872 // inform the host that we are leaving the game
1873 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1874 multi_io_send_to_all_reliable(data, packet_size);
1876 multi_io_send_reliable(Net_player, data, packet_size);
1879 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1880 // so he has to tell everyone that this guy left
1882 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1884 // a couple of important checks
1885 SDL_assert(player_id != Net_player->player_id);
1886 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1888 // add the id of the guy to be kicked
1889 ADD_SHORT(player_id);
1891 // broadcast to everyone
1892 if (target == NULL) {
1893 multi_io_send_to_all_reliable(data, packet_size);
1895 multi_io_send_reliable(target, data, packet_size);
1900 // process a notification the a player has left the game
1901 void process_leave_game_packet(ubyte* data, header* hinfo)
1909 offset = HEADER_LENGTH;
1911 // get whether he was kicked
1912 GET_DATA(kicked_reason);
1914 // get the address of the guy who is to leave
1915 GET_SHORT(deader_id);
1918 // determine who is dropping and printf out a notification
1919 player_num = find_player_id(deader_id);
1920 if (player_num == -1) {
1921 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1925 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1928 // a hook to display that a player was kicked
1929 if (kicked_reason >= 0){
1930 // if it was me that was kicked, leave the game
1931 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1934 switch(kicked_reason){
1935 case KICK_REASON_BAD_XFER:
1936 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1938 case KICK_REASON_CANT_XFER:
1939 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1941 case KICK_REASON_INGAME_ENDED:
1942 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1945 notify_code = MULTI_END_NOTIFY_KICKED;
1949 multi_quit_game(PROMPT_NONE, notify_code);
1952 // otherwise indicate someone was kicked
1954 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1956 // display the result
1957 memset(str, 0, 512);
1958 multi_kick_get_text(&Net_players[player_num], kicked_reason, str, SDL_arraysize(str));
1959 multi_display_chat_msg(str, player_num, 0);
1963 // first of all, if we're the master, we should be rebroadcasting this packet
1964 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1967 SDL_snprintf(msg, SDL_arraysize(msg), XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1969 if (!(Game_mode & GM_STANDALONE_SERVER)){
1970 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1973 send_hud_msg_to_all(msg);
1974 multi_io_send_to_all_reliable(data, offset);
1977 // leave the game if the host and/or master has dropped
1979 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1980 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1983 ml_string(NOX("Host and/or server has left the game"));
1985 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1986 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1987 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1990 delete_player(player_num);
1993 delete_player(player_num);
1995 // OSAPI GUI stuff (if standalone)
1996 if (Game_mode & GM_STANDALONE_SERVER) {
1997 // returns true if we should reset the standalone
1998 if (std_remove_player(&Net_players[player_num])) {
1999 nprintf(("Network", "Should reset!!\n"));
2003 // update these gui vals
2004 std_connect_set_host_connect_status();
2005 std_connect_set_connect_count();
2009 // send information about this currently active game to the specified address
2010 void send_game_active_packet(net_addr* addr)
2014 ubyte data[MAX_PACKET_SIZE],val;
2016 // build the header and add the data
2017 BUILD_HEADER(GAME_ACTIVE);
2019 // add the server version and compatible version #
2020 val = MULTI_FS_SERVER_VERSION;
2022 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
2025 ADD_STRING(Netgame.name);
2026 ADD_STRING(Netgame.mission_name);
2027 ADD_STRING(Netgame.title);
2028 val = (ubyte)multi_num_players();
2031 // add the proper flags
2033 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
2034 flags |= AG_FLAG_PASSWD;
2037 // proper netgame type flags
2038 if(Netgame.type_flags & NG_TYPE_TEAM){
2039 flags |= AG_FLAG_TEAMS;
2040 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
2041 flags |= AG_FLAG_DOGFIGHT;
2043 flags |= AG_FLAG_COOP;
2046 // proper netgame state flags
2047 switch(Netgame.game_state){
2048 case NETGAME_STATE_FORMING:
2049 flags |= AG_FLAG_FORMING;
2052 case NETGAME_STATE_BRIEFING:
2053 case NETGAME_STATE_MISSION_SYNC:
2054 case NETGAME_STATE_HOST_SETUP:
2055 flags |= AG_FLAG_BRIEFING;
2058 case NETGAME_STATE_IN_MISSION:
2059 flags |= AG_FLAG_IN_MISSION;
2062 case NETGAME_STATE_PAUSED:
2063 flags |= AG_FLAG_PAUSE;
2066 case NETGAME_STATE_ENDGAME:
2067 case NETGAME_STATE_DEBRIEF:
2068 flags |= AG_FLAG_DEBRIEF;
2072 // if this is a standalone
2073 if(Game_mode & GM_STANDALONE_SERVER){
2074 flags |= AG_FLAG_STANDALONE;
2077 // if we're in campaign mode
2078 if(Netgame.campaign_mode == MP_CAMPAIGN){
2079 flags |= AG_FLAG_CAMPAIGN;
2082 // add the data about the connection speed of the host machine
2083 SDL_assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
2084 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
2089 psnet_send(addr, data, packet_size);
2092 // process information about an active game
2093 void process_game_active_packet(ubyte* data, header* hinfo)
2098 int modes_compatible;
2100 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->port);
2102 // read this game into a temporary structure
2103 offset = HEADER_LENGTH;
2105 // get the server version and compatible version
2106 GET_DATA(ag.version);
2107 GET_DATA(ag.comp_version);
2109 GET_STRING(ag.name);
2110 GET_STRING(ag.mission_name);
2111 GET_STRING(ag.title);
2113 ag.num_players = val;
2114 GET_USHORT(ag.flags);
2118 modes_compatible = 1;
2120 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2121 modes_compatible = 0;
2123 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2124 modes_compatible = 0;
2128 // if this is a compatible version, and our modes are compatible, register it
2129 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2130 multi_update_active_games(&ag);
2134 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2135 // is used to change the current mission, current state, etc.
2136 void send_netgame_update_packet(net_player *pl)
2138 int packet_size = 0;
2140 ubyte data[MAX_PACKET_SIZE];
2142 BUILD_HEADER(GAME_UPDATE);
2144 // with new mission description field, this becomes way to large
2145 // so we must add every element piece by piece except the
2146 ADD_STRING(Netgame.name);
2147 ADD_STRING(Netgame.mission_name);
2148 ADD_STRING(Netgame.title);
2149 ADD_STRING(Netgame.campaign_name);
2150 ADD_INT(Netgame.campaign_mode);
2151 ADD_INT(Netgame.max_players);
2152 ADD_INT(Netgame.security);
2153 ADD_UINT(Netgame.respawn);
2154 ADD_INT(Netgame.flags);
2155 ADD_INT(Netgame.type_flags);
2156 ADD_INT(Netgame.version_info);
2157 ADD_DATA(Netgame.debug_flags);
2159 // only the server should ever send the netgame state (standalone situation)
2160 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2161 ADD_INT(Netgame.game_state);
2164 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2165 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2167 multi_io_send_to_all_reliable(data, packet_size);
2169 for(idx=0; idx<MAX_PLAYERS; idx++){
2170 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2171 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2175 multi_io_send_reliable(pl, data, packet_size);
2176 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2179 SDL_assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2180 multi_io_send_reliable(Net_player, data, packet_size);
2183 // host should always send a netgame options update as well
2184 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2185 multi_options_update_netgame();
2189 // process information about the netgame sent from the server/host
2190 void process_netgame_update_packet( ubyte *data, header *hinfo )
2192 int offset;//,old_flags;
2195 SDL_assert(!(Game_mode & GM_STANDALONE_SERVER));
2196 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2198 // read in the netgame information
2199 offset = HEADER_LENGTH;
2200 GET_STRING(Netgame.name);
2201 GET_STRING(Netgame.mission_name);
2202 GET_STRING(Netgame.title);
2203 GET_STRING(Netgame.campaign_name);
2204 GET_INT(Netgame.campaign_mode);
2205 GET_INT(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2206 GET_INT(Netgame.security);
2207 GET_UINT(Netgame.respawn);
2209 // be sure not to blast the quitting flag because of the "one frame extra" problem
2210 // old_flags = Netgame.flags;
2211 GET_INT(Netgame.flags);
2212 GET_INT(Netgame.type_flags);
2213 GET_INT(Netgame.version_info);
2214 GET_DATA(Netgame.debug_flags);
2221 // now compare the passed in game state to our current known state. If it has changed, then maybe
2222 // do something interesting.
2223 // move from the forming or debriefing state to the mission sync state
2224 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2225 // if coming from the forming state
2226 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2227 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2228 // do any special processing for forced state transitions
2229 multi_handle_state_special();
2231 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2232 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2233 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2235 // if coming from the debriefing state
2236 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2237 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2239 // do any special processing for forced state transitions
2240 multi_handle_state_special();
2242 multi_flush_mission_stuff();
2244 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2245 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2246 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2249 // move from mission sync to team select
2250 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2251 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2252 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2254 // do any special processing for forced state transitions
2255 multi_handle_state_special();
2257 SDL_strlcpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2258 gameseq_post_event(GS_EVENT_START_BRIEFING);
2261 // move from the debriefing to the create game screen
2262 else if ( ng_state == NETGAME_STATE_FORMING ){
2263 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2264 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2265 // do any special processing for forced state transitions
2266 multi_handle_state_special();
2268 multi_flush_mission_stuff();
2270 // move to the proper screen
2271 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2272 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2274 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2279 Netgame.game_state = ng_state;
2282 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2283 void send_netgame_descript_packet(net_addr *addr, int code)
2285 ubyte data[MAX_PACKET_SIZE],val;
2287 int packet_size = 0;
2290 BUILD_HEADER(UPDATE_DESCRIPT);
2296 // add as much of the description as we dare
2297 len = strlen(The_mission.mission_desc);
2298 if(len > MAX_PACKET_SIZE - 10){
2299 len = MAX_PACKET_SIZE - 10;
2301 memcpy(data+packet_size,The_mission.mission_desc,len);
2304 ADD_STRING(The_mission.mission_desc);
2308 SDL_assert(addr != NULL);
2310 psnet_send(addr, data, packet_size);
2314 // process an incoming netgame description packet
2315 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2319 char mission_desc[MISSION_DESC_LENGTH+2];
2322 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2324 // read this game into a temporary structure
2325 offset = HEADER_LENGTH;
2328 // if this is a request for mission description
2330 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2335 // send an update to this guy
2336 send_netgame_descript_packet(&addr, 1);
2338 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2339 GET_STRING(mission_desc);
2341 // only display if we're in the proper state
2342 state = gameseq_get_state();
2344 case GS_STATE_MULTI_JOIN_GAME:
2345 case GS_STATE_MULTI_CLIENT_SETUP:
2346 case GS_STATE_MULTI_HOST_SETUP:
2347 multi_common_set_text(mission_desc);
2355 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2356 void broadcast_game_query()
2360 server_item *s_moveup;
2361 ubyte data[MAX_PACKET_SIZE];
2363 BUILD_HEADER(GAME_QUERY);
2365 // go through the server list and query each of those as well
2366 s_moveup = Game_server_head;
2367 if(s_moveup != NULL){
2369 send_server_query(&s_moveup->server_addr);
2370 s_moveup = s_moveup->next;
2371 } while(s_moveup != Game_server_head);
2374 fill_net_addr(&addr, Psnet_my_addr.addr, DEFAULT_GAME_PORT);
2376 // send out a broadcast if our options allow us
2377 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2378 psnet_broadcast( &addr, data, packet_size);
2382 // send an individual query to an address to see if there is an active game
2383 void send_server_query(net_addr *addr)
2386 ubyte data[MAX_PACKET_SIZE];
2388 // build the header and send the data
2389 BUILD_HEADER(GAME_QUERY);
2390 psnet_send(addr, data, packet_size);
2393 // process a query from a client looking for active freespace games
2394 void process_game_query(ubyte* data, header* hinfo)
2399 offset = HEADER_LENGTH;
2403 // check to be sure that we don't capture our own broadcast message
2404 fill_net_addr(&addr, hinfo->addr, hinfo->port);
2405 if ( psnet_same( &addr, &Psnet_my_addr) ){
2409 // if I am not a server of a game, don't send a reply!!!
2410 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2414 // if the game options are being selected, then ignore the request
2415 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2416 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2420 // send information about this active game
2421 send_game_active_packet(&addr);
2424 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2425 void send_netplayer_update_packet( net_player *pl )
2427 int packet_size,idx;
2428 ubyte data[MAX_PACKET_SIZE],val;
2430 BUILD_HEADER(NETPLAYER_UPDATE);
2432 // if I'm the server of the game, I should send an update for _all_players in the game
2433 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2434 for(idx=0;idx<MAX_PLAYERS;idx++){
2435 // only send info for connected players
2436 if(MULTI_CONNECTED(Net_players[idx])){
2441 // add the net player's information
2442 ADD_SHORT(Net_players[idx].player_id);
2443 ADD_INT(Net_players[idx].state);
2444 ADD_INT(Net_players[idx].p_info.ship_class);
2445 ADD_INT(Net_players[idx].tracker_player_id);
2447 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2455 // add the final stop byte
2459 // broadcast the packet
2460 if(!(Game_mode & GM_IN_MISSION)){
2462 multi_io_send_to_all_reliable(data, packet_size);
2464 multi_io_send_reliable(pl, data, packet_size);
2468 multi_io_send_to_all(data, packet_size);
2470 multi_io_send(pl, data, packet_size);
2478 // add my current state in the netgame to this packet
2479 ADD_SHORT(Net_player->player_id);
2480 ADD_INT(Net_player->state);
2481 ADD_INT(Net_player->p_info.ship_class);
2482 ADD_INT(Multi_tracker_id);
2484 // add if I have a CD or not
2492 // add a final stop byte
2496 // send the packet to the server
2497 SDL_assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2498 if(!(Game_mode & GM_IN_MISSION)){
2499 multi_io_send_reliable(Net_player, data, packet_size);
2501 multi_io_send(Net_player, data, packet_size);
2506 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2507 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2509 int offset, player_num;
2515 offset = HEADER_LENGTH;
2517 // get the first stop byte
2520 while(stop != 0xff){
2521 // look the player up
2522 GET_SHORT(player_id);
2523 player_num = find_player_id(player_id);
2524 // if we couldn't find him, read in the bogus data
2525 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2526 GET_INT(bogus.state);
2527 GET_INT(bogus.p_info.ship_class);
2528 GET_INT(bogus.tracker_player_id);
2532 // otherwise read in the data correctly
2535 GET_INT(Net_players[player_num].p_info.ship_class);
2536 GET_INT(Net_players[player_num].tracker_player_id);
2539 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2541 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2544 // if he's changing state to joined, send a team update
2545 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2546 multi_team_send_update();
2550 Net_players[player_num].state = new_state;
2553 // get the next stop byte
2559 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2560 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2561 send_netplayer_update_packet(NULL);
2564 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2565 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2566 switch(Net_players[player_num].state){
2567 case NETPLAYER_STATE_STD_HOST_SETUP:
2568 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2571 case NETPLAYER_STATE_HOST_SETUP:
2572 // check for race conditions
2573 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2574 Netgame.game_state = NETGAME_STATE_FORMING;
2581 #define EXTRA_DEATH_VAPORIZED (1<<0)
2582 #define EXTRA_DEATH_WASHED (1<<1)
2583 // send a packet indicating a ship has been killed
2584 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2586 int packet_size, model;
2587 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2588 ushort debris_signature;
2592 // only sendable from the master
2593 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2596 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2598 extra_death_info = 0;
2600 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2603 if ( Ships[objp->instance].wash_killed ) {
2604 extra_death_info |= EXTRA_DEATH_WASHED;
2607 // find out the next network signature that will be used for the debris pieces.
2608 model = Ships[objp->instance].modelnum;
2609 pm = model_get(model);
2610 debris_signature = 0;
2611 if ( pm && !vaporized ) {
2612 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2613 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2614 Ships[objp->instance].arrival_distance = debris_signature;
2617 BUILD_HEADER(SHIP_KILL);
2618 ADD_USHORT(objp->net_signature);
2620 // ships which are initially killed get the rest of the data sent. self destructed ships and
2621 if ( other_objp == NULL ) {
2626 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2628 ADD_USHORT( other_objp->net_signature );
2631 ADD_USHORT( debris_signature );
2632 ADD_FLOAT( percent_killed );
2633 sd = (ubyte)self_destruct;
2635 ADD_DATA( extra_death_info );
2637 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2639 if ( objp->flags & OF_PLAYER_SHIP ) {
2643 pnum = multi_find_player_by_object( objp );
2646 ADD_DATA( was_player );
2648 SDL_assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2649 temp = (char)Net_players[pnum].player->killer_objtype;
2652 SDL_assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2653 temp = (char)Net_players[pnum].player->killer_species;
2656 SDL_assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2657 temp = (char)Net_players[pnum].player->killer_weapon_index;
2660 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2662 ADD_DATA( was_player );
2665 ADD_DATA( was_player );
2668 // send the packet reliably!!!
2669 multi_io_send_to_all_reliable(data, packet_size);
2672 // process a packet indicating that a ship has been killed
2673 void process_ship_kill_packet( ubyte *data, header *hinfo )
2676 ushort ship_sig, other_sig, debris_sig;
2677 object *sobjp, *oobjp;
2678 float percent_killed;
2679 ubyte was_player, extra_death_info, sd;
2680 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2682 offset = HEADER_LENGTH;
2683 GET_USHORT(ship_sig);
2685 GET_USHORT( other_sig );
2686 GET_USHORT( debris_sig );
2687 GET_FLOAT( percent_killed );
2689 GET_DATA( extra_death_info );
2690 GET_DATA( was_player );
2693 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2694 if ( was_player != 0 ) {
2695 GET_DATA( killer_objtype );
2696 GET_DATA( killer_species );
2697 GET_DATA( killer_weapon_index );
2698 GET_STRING( killer_name );
2703 sobjp = multi_get_network_object( ship_sig );
2705 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2706 // another message from the server that this happened!
2707 if ( sobjp == NULL ) {
2708 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2712 // set this ship's hull value to 0
2713 sobjp->hull_strength = 0.0f;
2715 // maybe set vaporized
2716 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2717 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2720 // maybe set wash_killed
2721 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2722 Ships[sobjp->instance].wash_killed = 1;
2725 oobjp = multi_get_network_object( other_sig );
2727 if ( was_player != 0 ) {
2730 pnum = multi_find_player_by_object( sobjp );
2732 Net_players[pnum].player->killer_objtype = killer_objtype;
2733 Net_players[pnum].player->killer_species = killer_species;
2734 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2735 SDL_strlcpy( Net_players[pnum].player->killer_parent_name, killer_name, NAME_LENGTH );
2739 // check to see if I need to respawn myself
2740 multi_respawn_check(sobjp);
2742 // store the debris signature in the arrival distance which will never get used for player ships
2743 Ships[sobjp->instance].arrival_distance = debris_sig;
2745 // set this bit so that we don't accidentally start switching targets when we die
2746 if(sobjp == Player_obj){
2747 Game_mode |= GM_DEAD_DIED;
2750 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2752 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2753 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2754 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2756 extern void ship_destroyed( int shipnum );
2757 ship_destroyed( sobjp->instance );
2758 sobjp->flags |= OF_SHOULD_BE_DEAD;
2759 obj_delete( OBJ_INDEX(sobjp) );
2763 // send a packet indicating a ship should be created
2764 void send_ship_create_packet( object *objp, int is_support )
2767 ubyte data[MAX_PACKET_SIZE];
2769 // We will pass the ship to create by name.
2770 BUILD_HEADER(SHIP_CREATE);
2771 ADD_USHORT(objp->net_signature);
2772 ADD_INT( is_support );
2774 add_vector_data(data, &packet_size, objp->pos);
2777 // broadcast the packet
2778 multi_io_send_to_all_reliable(data, packet_size);
2781 // process a packet indicating a ship should be created
2782 void process_ship_create_packet( ubyte *data, header *hinfo )
2784 int offset, objnum, is_support;
2787 vector pos = ZERO_VECTOR;
2789 SDL_assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2790 offset = HEADER_LENGTH;
2791 GET_USHORT(signature);
2792 GET_INT( is_support );
2794 get_vector_data(data, &offset, pos);
2799 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2800 if ( !is_support ) {
2801 objp = mission_parse_get_arrival_ship( signature );
2802 if ( objp != NULL ) {
2803 parse_create_object(objp);
2805 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2808 SDL_assert( Arriving_support_ship );
2809 if(Arriving_support_ship == NULL){
2812 Arriving_support_ship->pos = pos;
2813 Arriving_support_ship->net_signature = signature;
2814 objnum = parse_create_object( Arriving_support_ship );
2815 SDL_assert( objnum != -1 );
2817 mission_parse_support_arrived( objnum );
2822 // send a packet indicating a wing of ships should be created
2823 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2825 int packet_size, index, ship_instance;
2826 ubyte data[MAX_PACKET_SIZE];
2830 // for creating wing -- we just send the index into the wing array of this wing.
2831 // all players load the same mission, and so their array's should all match. We also
2832 // need to send the signature of the first ship that was created. We can find this by
2833 // looking num_to_create places back in the ship_index field in the wing structure.
2835 index = WING_INDEX(wingp);
2836 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2837 signature = Objects[Ships[ship_instance].objnum].net_signature;
2839 BUILD_HEADER( WING_CREATE );
2841 ADD_INT(num_to_create);
2842 ADD_USHORT(signature);
2843 ADD_INT(pre_create_count);
2844 val = wingp->current_wave - 1;
2847 multi_io_send_to_all_reliable(data, packet_size);
2850 // process a packet saying that a wing should be created
2851 void process_wing_create_packet( ubyte *data, header *hinfo )
2853 int offset, index, num_to_create;
2855 int total_arrived_count, current_wave;
2857 offset = HEADER_LENGTH;
2859 GET_INT(num_to_create);
2860 GET_USHORT(signature);
2861 GET_INT(total_arrived_count);
2862 GET_INT(current_wave);
2866 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2867 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2868 nprintf(("Network", "invalid index %d for wing create packet\n"));
2871 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2872 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2877 Wings[index].current_count = 0;
2878 Wings[index].total_arrived_count = total_arrived_count;
2879 Wings[index].current_wave = current_wave;
2881 // set the network signature that was passed. The client should create ships in the same order
2882 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2883 // need to set some timestamps and cues correctly to be sure that these things get created on
2884 // the clients correctly
2885 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2886 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2889 // packet indicating a ship is departing
2890 void send_ship_depart_packet( object *objp )
2892 ubyte data[MAX_PACKET_SIZE];
2896 signature = objp->net_signature;
2898 BUILD_HEADER(SHIP_DEPART);
2899 ADD_USHORT( signature );
2901 multi_io_send_to_all_reliable(data, packet_size);
2904 // process a packet indicating a ship is departing
2905 void process_ship_depart_packet( ubyte *data, header *hinfo )
2911 offset = HEADER_LENGTH;
2912 GET_USHORT( signature );
2915 // find the object which is departing
2916 objp = multi_get_network_object( signature );
2917 if ( objp == NULL ) {
2918 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2922 // start warping him out
2923 shipfx_warpout_start( objp );
2926 // packet to tell clients cargo of a ship was revealed to all
2927 void send_cargo_revealed_packet( ship *shipp )
2929 ubyte data[MAX_PACKET_SIZE];
2932 // build the header and add the data
2933 BUILD_HEADER(CARGO_REVEALED);
2934 ADD_USHORT( Objects[shipp->objnum].net_signature );
2936 // server sends to all players
2937 if(MULTIPLAYER_MASTER){
2938 multi_io_send_to_all_reliable(data, packet_size);
2940 // clients just send to the server
2942 multi_io_send_reliable(Net_player, data, packet_size);
2946 // process a cargo revealed packet
2947 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2953 offset = HEADER_LENGTH;
2954 GET_USHORT(signature);
2957 // get a ship pointer and call the ship function to reveal the cargo
2958 objp = multi_get_network_object( signature );
2959 if ( objp == NULL ) {
2960 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2964 // SDL_assert( objp->type == OBJ_SHIP );
2965 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2969 // this will take care of re-routing to all other clients
2970 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2972 // server should rebroadcast
2973 if(MULTIPLAYER_MASTER){
2974 send_cargo_revealed_packet(&Ships[objp->instance]);
2978 // defines used for secondary fire packet
2979 #define SFPF_ALLOW_SWARM (1<<7)
2980 #define SFPF_DUAL_FIRE (1<<6)
2981 #define SFPF_TARGET_LOCKED (1<<5)
2983 // send a packet indicating a secondary weapon was fired
2984 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2986 int packet_size, net_player_num;
2987 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2989 ushort target_signature;
2993 // SDL_assert ( starting_count < UCHAR_MAX );
2995 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
2996 // we might send the info to the other player different than the one who fired
2997 objp = &Objects[shipp->objnum];
2998 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2999 if ( num_fired == 0 ) {
3004 aip = &Ai_info[shipp->ai_index];
3006 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
3007 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3009 // build up the header portion
3010 BUILD_HEADER( SECONDARY_FIRED_AI );
3012 ADD_USHORT( Objects[shipp->objnum].net_signature );
3013 ADD_USHORT( starting_sig );
3015 // add a couple of bits for swarm missiles and dual fire secondary weaspons
3018 sinfo = current_bank;
3021 sinfo |= SFPF_ALLOW_SWARM;
3024 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
3025 sinfo |= SFPF_DUAL_FIRE;
3028 if ( aip->current_target_is_locked ){
3029 sinfo |= SFPF_TARGET_LOCKED;
3034 // add the ship's target and any targeted subsystem
3035 target_signature = 0;
3037 if ( aip->target_objnum != -1) {
3038 target_signature = Objects[aip->target_objnum].net_signature;
3039 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
3042 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
3043 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
3044 t_subsys = (char)s_index;
3047 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3048 SDL_assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
3053 ADD_USHORT( target_signature );
3054 ADD_DATA( t_subsys );
3056 // just send this packet to everyone, then bail if an AI ship fired.
3057 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3058 multi_io_send_to_all(data, packet_size);
3062 net_player_num = multi_find_player_by_object( objp );
3064 // getting here means a player fired. Send the current packet to all players except the player
3065 // who fired. If nothing got fired, then don't send to the other players -- we will just send
3066 // a packet to the player who will find out that he didn't fire anything
3067 if ( num_fired > 0 ) {
3068 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3071 // if I (the master) fired, then return
3072 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3076 // now build up the packet to send to the player who actually fired.
3077 BUILD_HEADER( SECONDARY_FIRED_PLR );
3078 ADD_USHORT(starting_sig);
3081 // add the targeting information so that the player's weapons will always home on the correct
3083 ADD_USHORT( target_signature );
3084 ADD_DATA( t_subsys );
3086 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3089 /// process a packet indicating a secondary weapon was fired
3090 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3092 int offset, allow_swarm, target_objnum_save;
3093 ushort net_signature, starting_sig, target_signature;
3094 ubyte sinfo, current_bank;
3095 object* objp, *target_objp;
3099 ship_subsys *targeted_subsys_save;
3101 offset = HEADER_LENGTH; // size of the header
3103 // if from_player is false, it means that the secondary weapon info in this packet was
3104 // fired by an ai object (or another player). from_player == 1 means tha me (the person
3105 // receiving this packet) fired the secondary weapon
3106 if ( !from_player ) {
3107 GET_USHORT( net_signature );
3108 GET_USHORT( starting_sig );
3109 GET_DATA( sinfo ); // are we firing swarm missiles
3111 GET_USHORT( target_signature );
3112 GET_DATA( t_subsys );
3116 // find the object (based on network signatures) for the object that fired
3117 objp = multi_get_network_object( net_signature );
3118 if ( objp == NULL ) {
3119 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3123 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3124 // of the next fire time of this bank to 0 so we can fire right away
3125 shipp = &Ships[objp->instance];
3128 GET_USHORT( starting_sig );
3131 GET_USHORT( target_signature );
3132 GET_DATA( t_subsys );
3136 // get the object and ship
3138 shipp = Player_ship;
3141 // check the allow swarm bit
3143 if ( sinfo & SFPF_ALLOW_SWARM ){
3147 // set the dual fire properties of the ship
3148 if ( sinfo & SFPF_DUAL_FIRE ){
3149 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3151 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3154 // determine whether current target is locked
3155 SDL_assert( shipp->ai_index != -1 );
3156 aip = &Ai_info[shipp->ai_index];
3157 if ( sinfo & SFPF_TARGET_LOCKED ) {
3158 aip->current_target_is_locked = 1;
3160 aip->current_target_is_locked = 0;
3163 // find out the current bank
3164 current_bank = (ubyte)(sinfo & 0x3);
3165 //SDL_assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) ); // always true
3166 shipp->weapons.current_secondary_bank = current_bank;
3168 // make it so we can fire this ship's secondary bank immediately!!!
3169 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3170 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3172 // set this ship's target and subsystem information. We will save and restore target and
3173 // targeted subsystem so that we do not accidentally change targets for this player or
3174 // any AI ships on his system.
3175 target_objnum_save = aip->target_objnum;
3176 targeted_subsys_save = aip->targeted_subsys;
3178 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3179 aip->target_objnum = -1;
3180 aip->targeted_subsys = NULL;
3182 target_objp = multi_get_network_object( target_signature );
3183 if ( target_objp != NULL ) {
3184 aip->target_objnum = OBJ_INDEX(target_objp);
3186 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3187 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3191 if ( starting_sig != 0 ){
3192 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3194 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3197 ship_fire_secondary( objp, allow_swarm );
3199 // restore targeted object and targeted subsystem
3200 aip->target_objnum = target_objnum_save;
3201 aip->targeted_subsys = targeted_subsys_save;
3204 // send a packet indicating a countermeasure was fired
3205 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3207 ubyte data[MAX_PACKET_SIZE];
3212 SDL_assert ( cmeasure_count < UCHAR_MAX );
3213 BUILD_HEADER(COUNTERMEASURE_FIRED);
3214 ADD_USHORT( objp->net_signature );
3215 ADD_INT( rand_val );
3217 multi_io_send_to_all(data, packet_size);
3220 // process a packet indicating a countermeasure was fired
3221 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3223 int offset, rand_val;
3229 offset = HEADER_LENGTH;
3231 GET_USHORT( signature );
3232 GET_INT( rand_val );
3235 objp = multi_get_network_object( signature );
3236 if ( objp == NULL ) {
3237 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3240 if(objp->type != OBJ_SHIP){
3243 // SDL_assert ( objp->type == OBJ_SHIP );
3245 // make it so ship can fire right away!
3246 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3247 if ( objp == Player_obj ){
3248 nprintf(("network", "firing countermeasure from my ship\n"));
3251 ship_launch_countermeasure( objp, rand_val );
3254 // send a packet indicating that a turret has been fired
3255 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3258 ushort pnet_signature;
3259 ubyte data[MAX_PACKET_SIZE], cindex;
3266 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3270 // local setup -- be sure we are actually passing a weapon!!!!
3271 objp = &Objects[weapon_objnum];
3272 SDL_assert ( objp->type == OBJ_WEAPON );
3273 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3277 pnet_signature = Objects[ship_objnum].net_signature;
3279 SDL_assert( subsys_index < UCHAR_MAX );
3280 cindex = (ubyte)subsys_index;
3282 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3287 // build the fire turret packet.
3288 BUILD_HEADER(FIRE_TURRET_WEAPON);
3289 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
3290 ADD_DATA( has_sig );
3291 ADD_USHORT( pnet_signature );
3293 ADD_USHORT( objp->net_signature );
3296 val = (short)ssp->submodel_info_1.angs.h;
3298 val = (short)ssp->submodel_info_2.angs.p;
3301 multi_io_send_to_all(data, packet_size);
3303 multi_rate_add(1, "tur", packet_size);
3306 // process a packet indicating a turret has been fired
3307 void process_turret_fired_packet( ubyte *data, header *hinfo )
3309 int offset, weapon_objnum, wid;
3310 ushort pnet_signature, wnet_signature;
3319 short pitch, heading;
3321 // get the data for the turret fired packet
3322 offset = HEADER_LENGTH;
3323 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3324 GET_DATA( has_sig );
3325 GET_USHORT( pnet_signature );
3327 GET_USHORT( wnet_signature );
3331 GET_DATA( turret_index );
3332 GET_SHORT( heading );
3334 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3337 objp = multi_get_network_object( pnet_signature );
3338 if ( objp == NULL ) {
3339 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3343 // if this isn't a ship, do nothing
3344 if ( objp->type != OBJ_SHIP ){
3348 // make an orientation matrix from the o_fvec
3349 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3351 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3352 // hack, but should be suitable.
3353 shipp = &Ships[objp->instance];
3354 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3358 wid = ssp->system_info->turret_weapon_type;
3360 // bash the position and orientation of the turret
3361 ssp->submodel_info_1.angs.h = (float)heading;
3362 ssp->submodel_info_2.angs.p = (float)pitch;
3364 // get the world position of the weapon
3365 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3367 // create the weapon object
3368 if(wnet_signature != 0){
3369 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3371 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3372 if (weapon_objnum != -1) {
3373 if ( Weapon_info[wid].launch_snd != -1 ) {
3374 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3379 // send a mission log item packet
3380 void send_mission_log_packet( int num )
3383 ubyte data[MAX_PACKET_SIZE];
3388 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3390 // get the data from the log
3391 entry = &log_entries[num];
3392 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3393 sindex = (ushort)entry->index;
3395 BUILD_HEADER(MISSION_LOG_ENTRY);
3397 ADD_INT(entry->flags);
3399 ADD_DATA(entry->timestamp);
3400 ADD_STRING(entry->pname);
3401 ADD_STRING(entry->sname);
3403 // broadcast the packet to all players
3404 multi_io_send_to_all_reliable(data, packet_size);
3407 // process a mission log item packet
3408 void process_mission_log_packet( ubyte *data, header *hinfo )
3413 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3416 SDL_assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3418 offset = HEADER_LENGTH;
3422 GET_DATA(timestamp);
3428 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3431 // send a mission message packet
3432 void send_mission_message_packet( int id, const char *who_from, int priority, int timing, int source, int builtin_type, int multi_target, int multi_team_filter)
3435 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3437 SDL_assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3438 SDL_assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3439 SDL_assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3441 up = (ubyte) priority;
3442 us = (ubyte) source;
3443 utime = (ubyte)timing;
3445 BUILD_HEADER(MISSION_MESSAGE);
3447 ADD_STRING(who_from);
3451 ADD_INT(builtin_type);
3452 ADD_INT(multi_team_filter);
3454 if (multi_target == -1){
3455 multi_io_send_to_all_reliable(data, packet_size);
3457 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3461 // process a mission message packet
3462 void process_mission_message_packet( ubyte *data, header *hinfo )
3464 int offset, id, builtin_type;
3465 ubyte priority, source, utiming;
3466 char who_from[NAME_LENGTH];
3467 int multi_team_filter;
3469 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3471 offset = HEADER_LENGTH;
3473 GET_STRING(who_from);
3477 GET_INT(builtin_type);
3478 GET_INT(multi_team_filter);
3482 // filter out builtin ones in TvT
3483 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3487 // maybe filter this out
3488 if(!message_filter_multi(id)){
3489 // send the message as if it came from an sexpression
3490 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3494 // just send them a pong back as fast as possible
3495 void process_ping_packet(ubyte *data, header *hinfo)
3500 offset = HEADER_LENGTH;
3503 // get the address to return the pong to
3504 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3510 // right now it just routes the pong through to the standalone gui, which is the only
3511 // system which uses ping and pong right now.
3512 void process_pong_packet(ubyte *data, header *hinfo)
3518 offset = HEADER_LENGTH;
3520 fill_net_addr(&addr, hinfo->addr, hinfo->port);
3524 // if we're connected , see who sent us this pong
3525 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3526 lookup = find_player_id(hinfo->id);
3531 p = &Net_players[lookup];
3533 // evaluate the ping
3534 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3536 // put in calls to any functions which may want to know about the ping times from
3538 if(Game_mode & GM_STANDALONE_SERVER){
3539 std_update_player_ping(p);
3542 // mark his socket as still alive (extra precaution)
3543 psnet_mark_received(Net_players[lookup].reliable_socket);
3545 // otherwise, do any special processing
3547 // if we're in the join game state, see if this pong came from a server on our
3549 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3550 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3555 // send a ping packet
3556 void send_ping(net_addr *addr)
3558 unsigned char data[8];
3561 // build the header and send the packet
3562 BUILD_HEADER( PING );
3563 psnet_send(addr, &data[0], packet_size);
3566 // send a pong packet
3567 void send_pong(net_addr *addr)
3569 unsigned char data[8];
3572 // build the header and send the packet
3574 psnet_send(addr, &data[0], packet_size);
3577 // sent from host to master. give me the list of missions you have.
3578 // this will be used only in a standalone mode
3579 void send_mission_list_request( int what )
3581 ubyte data[MAX_PACKET_SIZE];
3584 // build the header and ask for a list of missions or campaigns (depending
3585 // on the 'what' flag).
3586 BUILD_HEADER(MISSION_REQUEST);
3588 multi_io_send_reliable(Net_player, data, packet_size);
3591 // maximum number of bytes that we can send in a mission items packet.
3592 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3594 // defines used to tell what type of packets are being sent
3595 #define MISSION_LIST_ITEMS 1
3596 #define CAMPAIGN_LIST_ITEMS 2
3598 // send an individual mission file item
3599 void send_mission_items( net_player *pl )
3601 ubyte data[MAX_PACKET_SIZE];
3606 BUILD_HEADER(MISSION_ITEM);
3608 // send the list of missions and campaigns avilable on the server. Stop when
3609 // reaching a certain maximum
3610 type = MISSION_LIST_ITEMS;
3612 for (i = 0; i < Multi_create_mission_count; i++ ) {
3616 ADD_STRING( Multi_create_mission_list[i].filename );
3617 ADD_STRING( Multi_create_mission_list[i].name );
3618 ADD_INT( Multi_create_mission_list[i].flags );
3619 ADD_DATA( Multi_create_mission_list[i].max_players );
3620 ADD_UINT( Multi_create_mission_list[i].respawn );
3623 ADD_DATA( Multi_create_mission_list[i].valid_status );
3625 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3628 multi_io_send_reliable(pl, data, packet_size);
3629 BUILD_HEADER( MISSION_ITEM );
3635 multi_io_send_reliable(pl, data, packet_size);
3637 // send the campaign information
3638 type = CAMPAIGN_LIST_ITEMS;
3639 BUILD_HEADER(MISSION_ITEM);
3641 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3645 ADD_STRING( Multi_create_campaign_list[i].filename );
3646 ADD_STRING( Multi_create_campaign_list[i].name );
3647 ADD_INT( Multi_create_campaign_list[i].flags );
3648 ADD_DATA( Multi_create_campaign_list[i].max_players );
3650 if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3653 multi_io_send_reliable(pl, data, packet_size);
3654 BUILD_HEADER( MISSION_ITEM );
3660 multi_io_send_reliable(pl, data, packet_size);
3663 // process a request for a list of missions
3664 void process_mission_request_packet(ubyte *data, header *hinfo)
3666 int player_num,offset;
3668 offset = HEADER_LENGTH;
3671 // fill in the address information of where this came from
3672 player_num = find_player_id(hinfo->id);
3673 if(player_num == -1){
3674 nprintf(("Network","Could not find player to send mission list items to!\n"));
3678 send_mission_items( &Net_players[player_num] );
3681 // process an individual mission file item
3682 void process_mission_item_packet(ubyte *data,header *hinfo)
3685 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3686 ubyte stop, type,max_players;
3689 SDL_assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3690 offset = HEADER_LENGTH;
3695 GET_STRING( filename );
3698 GET_DATA( max_players );
3700 // missions also have respawns and a crc32 associated with them
3701 if(type == MISSION_LIST_ITEMS){
3705 GET_DATA(valid_status);
3707 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3708 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename, MAX_FILENAME_LEN );
3709 SDL_strlcpy(Multi_create_mission_list[Multi_create_mission_count].name, name, NAME_LENGTH );
3710 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3711 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3712 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3715 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3717 Multi_create_mission_count++;
3719 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3720 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3721 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename, MAX_FILENAME_LEN );
3722 SDL_strlcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name, NAME_LENGTH );
3723 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3724 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3725 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3726 Multi_create_campaign_count++;
3735 // this will cause whatever list to get resorted (although they should be appearing in order)
3736 multi_create_setup_list_data(-1);
3739 // send a request to the server to pause or unpause the game
3740 void send_multi_pause_packet(int pause)
3742 ubyte data[MAX_PACKET_SIZE];
3744 int packet_size = 0;
3746 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3749 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3750 val = (ubyte) pause;
3752 // add the pause info
3755 // send the request to the server
3756 multi_io_send_reliable(Net_player, data, packet_size);
3759 // process a pause update packet (pause, unpause, etc)
3760 void process_multi_pause_packet(ubyte *data, header *hinfo)
3766 offset = HEADER_LENGTH;
3772 // get who sent the packet
3773 player_index = find_player_id(hinfo->id);
3774 // if we don't know who sent the packet, don't do anything
3775 if(player_index == -1){
3779 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3780 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3783 // send a game information update
3784 void send_game_info_packet()
3787 ubyte data[MAX_PACKET_SIZE], paused;
3789 // set the paused variable
3790 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3792 BUILD_HEADER(GAME_INFO);
3793 ADD_INT( Missiontime );
3796 multi_io_send_to_all(data, packet_size);
3799 // process a game information update
3800 void process_game_info_packet( ubyte *data, header *hinfo )
3806 offset = HEADER_LENGTH;
3808 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3809 // time, set our time to server time (should take ping time into account!!!)
3810 GET_DATA( mission_time );
3815 // send an ingame nak packet
3816 void send_ingame_nak(int state, net_player *p)
3818 ubyte data[MAX_PACKET_SIZE];
3819 int packet_size = 0;
3821 BUILD_HEADER(INGAME_NAK);
3825 multi_io_send_reliable(p, data, packet_size);
3828 // process an ingame nak packet
3829 void process_ingame_nak(ubyte *data, header *hinfo)
3831 int offset,state,pid;
3833 offset = HEADER_LENGTH;
3837 pid = find_player_id(hinfo->id);
3843 case ACK_FILE_ACCEPTED :
3844 SDL_assert(Net_players[pid].flags & NETINFO_FLAG_INGAME_JOIN);
3845 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3846 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3851 // send a packet telling players to end the mission
3852 void send_endgame_packet(net_player *pl)
3854 ubyte data[MAX_PACKET_SIZE];
3855 int packet_size = 0;
3857 BUILD_HEADER(MISSION_END);
3859 // sending to a specific player?
3861 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3862 multi_io_send_reliable(pl, data, packet_size);
3866 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3867 // send all player stats here
3868 multi_broadcast_stats(STATS_MISSION);
3870 // if in dogfight mode, send all dogfight stats as well
3871 ml_string("Before dogfight stats!");
3872 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3873 ml_string("Sending dogfight stats!");
3875 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3877 ml_string("After dogfight stats!");
3879 // tell everyone to leave the game
3880 multi_io_send_to_all_reliable(data, packet_size);
3882 multi_io_send_reliable(Net_player, data, packet_size);
3886 // process a packet indicating we should end the current mission
3887 void process_endgame_packet(ubyte *data, header *hinfo)
3892 offset = HEADER_LENGTH;
3896 ml_string("Receiving endgame packet");
3898 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3899 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3900 // determine who this came from and make sure he is allowed to end the game
3901 player_num = find_player_id(hinfo->id);
3902 SDL_assert(player_num != -1);
3907 // if the player is allowed to end the mission
3908 if(!multi_can_end_mission(&Net_players[player_num])){
3912 // act as if we hit alt+j locally
3913 multi_handle_end_mission_request();
3915 // all clients process immediately
3917 // ingame joiners should quit when they receive an endgame packet since the game is over
3918 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3919 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3923 // do any special processing for being in a state other than the gameplay state
3924 multi_handle_state_special();
3926 // make sure we're not already in the debrief state
3927 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3928 multi_warpout_all_players();
3933 // send a position/orientation update for myself (if I'm an observer)
3934 void send_observer_update_packet()
3936 ubyte data[MAX_PACKET_SIZE];
3937 int packet_size = 0;
3941 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3942 // to send any update packets to anyone.
3943 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3947 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3951 BUILD_HEADER(OBSERVER_UPDATE);
3953 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3955 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3958 // add targeting infomation
3959 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3960 target_sig = Objects[Player_ai->target_objnum].net_signature;
3964 ADD_USHORT(target_sig);
3966 multi_io_send(Net_player, data, packet_size);
3969 // process a position/orientation update from an observer
3970 void process_observer_update_packet(ubyte *data, header *hinfo)
3976 physics_info bogus_pi;
3979 offset = HEADER_LENGTH;
3981 obs_num = find_player_id(hinfo->id);
3983 memset(&bogus_pi,0,sizeof(physics_info));
3984 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3986 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3989 // targeting information
3990 GET_USHORT(target_sig);
3993 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
3997 // set targeting info
3998 if(target_sig == 0){
3999 Net_players[obs_num].s_info.target_objnum = -1;
4001 target_obj = multi_get_network_object(target_sig);
4002 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4005 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
4006 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
4007 Net_players[obs_num].s_info.eye_pos = g_vec;
4008 Net_players[obs_num].s_info.eye_orient = g_mat;
4011 void send_netplayer_slot_packet()
4013 ubyte data[MAX_PACKET_SIZE];
4014 int packet_size = 0, idx;
4019 BUILD_HEADER(NETPLAYER_SLOTS_P);
4020 for(idx=0;idx<MAX_PLAYERS;idx++){
4021 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
4023 ADD_SHORT(Net_players[idx].player_id);
4024 ADD_USHORT(Objects[Net_players[idx].player->objnum].net_signature);
4025 ADD_INT(Net_players[idx].p_info.ship_class);
4026 ADD_INT(Net_players[idx].p_info.ship_index);
4032 // standalone case or not
4033 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
4034 multi_io_send_to_all_reliable(data, packet_size);
4036 multi_io_send_reliable(Net_player, data, packet_size);
4040 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
4043 int player_num,ship_class,ship_index;
4049 offset = HEADER_LENGTH;
4051 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4052 multi_untag_player_ships();
4056 GET_SHORT(player_id);
4057 GET_USHORT(net_sig);
4058 GET_INT(ship_class);
4059 GET_INT(ship_index);
4060 player_num = find_player_id(player_id);
4062 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4064 // call the function in multiutil.cpp to set up the player object stuff
4065 // being careful not to muck with the standalone object
4066 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4067 objp = multi_get_network_object(net_sig);
4068 SDL_assert(objp != NULL);
4069 multi_assign_player_ship( player_num, objp, ship_class );
4070 Net_players[player_num].p_info.ship_index = ship_index;
4071 objp->flags &= ~(OF_COULD_BE_PLAYER);
4072 objp->flags |= OF_PLAYER_SHIP;
4079 // standalone should forward the packet and wait for a response
4080 if(Game_mode & GM_STANDALONE_SERVER){
4081 send_netplayer_slot_packet();
4084 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
4085 send_netplayer_update_packet();
4088 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4089 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4090 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4091 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4093 ubyte data[MAX_PACKET_SIZE], utmp;
4096 BUILD_HEADER(SHIP_WSTATE_CHANGE);
4097 ADD_USHORT( Objects[shipp->objnum].net_signature );
4098 utmp = (ubyte)(what);
4100 utmp = (ubyte)(new_bank);
4102 utmp = (ubyte)(link_status);
4105 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4106 multi_io_send_to_all_reliable(data, packet_size);
4109 void process_ship_weapon_change( ubyte *data, header *hinfo )
4113 ubyte what, new_bank, link_status;
4117 offset = HEADER_LENGTH;
4118 GET_USHORT( signature );
4120 GET_DATA( new_bank );
4121 GET_DATA( link_status );
4124 objp = multi_get_network_object( signature );
4125 if ( objp == NULL ) {
4126 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4129 // SDL_assert( objp->type == OBJ_SHIP );
4130 if(objp->type != OBJ_SHIP){
4134 // if this is my data, do nothing since I already have my own data
4135 if ( objp == Player_obj ){
4139 // now, get the ship and set the new bank and link modes based on the 'what' value
4140 shipp = &Ships[objp->instance];
4141 if ( what == MULTI_PRIMARY_CHANGED ) {
4142 shipp->weapons.current_primary_bank = new_bank;
4144 shipp->flags |= SF_PRIMARY_LINKED;
4146 shipp->flags &= ~SF_PRIMARY_LINKED;
4149 shipp->weapons.current_secondary_bank = new_bank;
4151 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4153 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4158 // ship status change procedure
4159 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4161 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4162 // for added redundancy.
4163 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4164 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4165 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4166 // back to the client. Also sends multiple times for redundancy
4167 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4168 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4169 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4171 #define SHIP_STATUS_REPEAT 2
4172 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4175 ubyte data[MAX_PACKET_SIZE];
4176 int packet_size = 0;
4182 BUILD_HEADER(SHIP_STATUS_CHANGE);
4184 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4185 temp = bi->status[idx];
4189 // server should send reliably (response packet)
4190 if(MULTIPLAYER_MASTER){
4191 multi_io_send_reliable(pl, data, packet_size);
4193 multi_io_send(pl, data, packet_size);
4197 void process_ship_status_packet(ubyte *data, header *hinfo)
4201 int player_num,unique_id;
4205 offset = HEADER_LENGTH;
4207 // zero out the button info structure for good measure
4208 memset(&bi,0,sizeof(button_info));
4210 // read the button-info
4213 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4215 bi.status[idx] = i_tmp;
4220 // this will be handled differently client and server side. Duh.
4221 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4222 // find which net-player has sent us butotn information
4223 player_num = find_player_id(hinfo->id);
4224 SDL_assert(player_num >= 0);
4229 // don't process critical button information for observers
4230 // its a new button_info for this guy. apply and ack
4231 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4232 // mark that he's pressed this button
4233 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4235 // send a return packet
4236 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4238 // apply the button presses to his ship as normal
4239 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4241 // else ignore it as a repeat from the same guy
4242 } else { // CLIENT SIDE
4243 // this is the return from the server, so we should now apply them locally
4244 // if(lookup_ship_status(Net_player,unique_id,1)){
4245 multi_apply_ship_status(Net_player, &bi, 1);
4250 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4251 // for clients. Left all details to this function instead of higher level messaging
4253 void send_player_order_packet(int type, int index, int cmd)
4255 ubyte data[MAX_PACKET_SIZE];
4257 ushort target_signature;
4259 int packet_size = 0;
4261 BUILD_HEADER(PLAYER_ORDER_PACKET);
4264 ADD_DATA(val); // ship order or wing order, or message all fighters
4266 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4267 if ( val != SQUAD_MSG_ALL ){
4268 ADD_INT(index); // net signature of target ship
4271 ADD_INT(cmd); // the command itself
4274 target_signature = 0;
4275 if ( Player_ai->target_objnum != -1 ){
4276 target_signature = Objects[Player_ai->target_objnum].net_signature;
4279 ADD_USHORT( target_signature );
4282 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4285 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4286 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
4287 t_subsys = (char)s_index;
4291 multi_io_send_reliable(Net_player, data, packet_size);
4294 // brief explanation :
4295 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4296 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4297 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4298 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4299 void process_player_order_packet(ubyte *data, header *hinfo)
4301 int offset, player_num, command, index = 0, tobjnum_save;
4302 ushort target_signature;
4303 char t_subsys, type;
4304 object *objp, *target_objp;
4307 ship_subsys *tsubsys_save, *targeted_subsys;
4309 SDL_assert(MULTIPLAYER_MASTER);
4311 // packet values - its easier to read all of these in first
4313 offset = HEADER_LENGTH;
4316 if ( type != SQUAD_MSG_ALL ){
4321 GET_USHORT( target_signature );
4322 GET_DATA( t_subsys );
4326 player_num = find_player_id(hinfo->id);
4327 if(player_num == -1){
4328 nprintf(("Network","Received player order packet from unknown player\n"));
4332 objp = &Objects[Net_players[player_num].player->objnum];
4333 if ( objp->type != OBJ_SHIP ) {
4334 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4338 // HACK HACK HACK HACK HACK HACK
4339 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4340 // the data is BOGUS. All people should be able to to these things as well.
4341 if(command == REARM_REPAIR_ME_ITEM){
4342 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4344 } else if(command == ABORT_REARM_REPAIR_ITEM){
4345 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4349 // if this player is not allowed to do messaging, quit here
4350 if( !multi_can_message(&Net_players[player_num]) ){
4351 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4355 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4356 // then call them in.
4357 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4358 SDL_assert( (index >= 0) && (index < Num_reinforcements) );
4359 hud_squadmsg_call_reinforcement(index, player_num);
4363 // set the player's ai information here
4364 shipp = &Ships[objp->instance];
4365 aip = &Ai_info[shipp->ai_index];
4367 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4368 target_objp = multi_get_network_object( target_signature );
4369 if ( target_objp == NULL ) {
4373 targeted_subsys = NULL;
4374 if ( t_subsys != -1 ) {
4375 SDL_assert( target_objp != NULL );
4376 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4379 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4381 tobjnum_save = aip->target_objnum;
4382 tsubsys_save = aip->targeted_subsys;
4384 if ( target_objp ) {
4385 aip->target_objnum = OBJ_INDEX(target_objp);
4387 aip->target_objnum = -1;
4390 aip->targeted_subsys = targeted_subsys;
4392 if ( type == SQUAD_MSG_SHIP ) {
4393 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4394 } else if ( type == SQUAD_MSG_WING ) {
4395 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4396 } else if ( type == SQUAD_MSG_ALL ) {
4397 hud_squadmsg_send_to_all_fighters( command, player_num );
4400 SDL_assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4401 aip->target_objnum = tobjnum_save;
4402 aip->targeted_subsys = tsubsys_save;
4405 // FILE SIGNATURE stuff :
4406 // there are 2 cases for file signature sending which are handled very differently
4407 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4408 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4409 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4410 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4411 // would have to keep track of up to potentially 14 other ack handles (ouch).
4412 void send_file_sig_packet(ushort sum_sig,int length_sig)
4414 ubyte data[MAX_PACKET_SIZE];
4415 int packet_size = 0;
4417 BUILD_HEADER(FILE_SIG_INFO);
4418 ADD_USHORT(sum_sig);
4419 ADD_INT(length_sig);
4421 multi_io_send_reliable(Net_player, data, packet_size);
4424 void process_file_sig_packet(ubyte *data, header *hinfo)
4429 offset = HEADER_LENGTH;
4431 // should only be received on the server-side
4432 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4434 GET_USHORT(sum_sig);
4435 GET_INT(length_sig);
4437 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4440 void send_file_sig_request(char *file_name)
4442 ubyte data[MAX_PACKET_SIZE];
4443 int packet_size = 0;
4445 BUILD_HEADER(FILE_SIG_REQUEST);
4446 ADD_STRING(file_name);
4448 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4450 multi_io_send_to_all_reliable(data, packet_size);
4453 void process_file_sig_request(ubyte *data, header *hinfo)
4455 int offset = HEADER_LENGTH;
4457 // get the mission name
4458 GET_STRING(Netgame.mission_name);
4461 // set the current mission filename
4462 SDL_strlcpy(Game_current_mission_filename, Netgame.mission_name, SDL_arraysize(Game_current_mission_filename));
4465 multi_get_mission_checksum(Game_current_mission_filename);
4467 if(!multi_endgame_ending()){
4468 // reply to the server
4469 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4473 // functions to deal with subsystems getting whacked
4474 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4476 ubyte data[MAX_PACKET_SIZE];
4479 vector tmp, local_hitpos;
4482 SDL_assert ( index < UCHAR_MAX );
4483 uindex = (ubyte)(index);
4485 objp = &Objects[shipp->objnum];
4487 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4488 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4490 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4491 ADD_USHORT( Objects[shipp->objnum].net_signature );
4493 // ADD_DATA( local_hitpos );
4494 add_vector_data(data, &packet_size, local_hitpos);
4496 multi_io_send_to_all_reliable(data, packet_size);
4499 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4505 vector local_hit_pos = ZERO_VECTOR, world_hit_pos;
4507 offset = HEADER_LENGTH;
4509 GET_USHORT( signature );
4511 // GET_DATA( local_hit_pos );
4512 get_vector_data(data, &offset, local_hit_pos);
4514 // get the network object. process it if we find it.
4515 objp = multi_get_network_object( signature );
4516 if ( objp != NULL ) {
4518 ship_subsys *subsysp;
4520 // be sure we have a ship!!!
4521 // SDL_assert ( objp->type == OBJ_SHIP );
4522 if(objp->type != OBJ_SHIP){
4527 shipp = &Ships[objp->instance];
4529 // call to get the pointer to the subsystem we should be working on
4530 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4531 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4532 vm_vec_add2( &world_hit_pos, &objp->pos );
4534 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4535 if ( objp == Player_obj ) {
4536 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4544 // packet to tell clients cargo of a ship was revealed to all
4545 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4547 ubyte data[MAX_PACKET_SIZE], uindex;
4550 SDL_assert ( index < UCHAR_MAX );
4551 uindex = (ubyte)(index);
4553 // build the header and add the data
4554 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4555 ADD_USHORT( Objects[shipp->objnum].net_signature );
4558 // server sends to all players
4559 if(MULTIPLAYER_MASTER){
4560 multi_io_send_to_all_reliable(data, packet_size);
4562 // clients just send to the server
4564 multi_io_send_reliable(Net_player, data, packet_size);
4568 // process a subsystem cargo revealed packet
4569 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4576 ship_subsys *subsysp;
4578 offset = HEADER_LENGTH;
4579 GET_USHORT( signature );
4583 // get a ship pointer and call the ship function to reveal the cargo
4584 objp = multi_get_network_object( signature );
4585 if ( objp == NULL ) {
4586 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4590 // SDL_assert( objp->type == OBJ_SHIP );
4591 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4595 shipp = &Ships[objp->instance];
4597 // call to get the pointer to the subsystem we should be working on
4598 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4599 if (subsysp == NULL) {
4600 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4604 // this will take care of re-routing to all other clients
4605 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4606 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4608 // server should rebroadcast
4609 if(MULTIPLAYER_MASTER){
4610 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4614 void send_netplayer_load_packet(net_player *pl)
4616 ubyte data[MAX_PACKET_SIZE];
4617 int packet_size = 0;
4619 BUILD_HEADER(LOAD_MISSION_NOW);
4620 ADD_STRING(Netgame.mission_name);
4623 multi_io_send_to_all_reliable(data, packet_size);
4625 multi_io_send_reliable(pl, data, packet_size);
4629 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4632 int offset = HEADER_LENGTH;
4637 SDL_strlcpy(Netgame.mission_name, str, SDL_arraysize(Netgame.mission_name));
4638 SDL_strlcpy(Game_current_mission_filename, str, SDL_arraysize(Game_current_mission_filename));
4639 if(!Multi_mission_loaded){
4641 // MWA 2/3/98 -- ingame join changes!!!
4642 // everyone can go through the same mission loading path here!!!!
4643 nprintf(("Network","Loading mission..."));
4645 // notify everyone that I'm loading the mission
4646 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4647 send_netplayer_update_packet();
4649 // do the load itself
4650 game_start_mission();
4652 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4653 // code will remark the correct player ships
4654 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4655 multi_untag_player_ships();
4658 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4659 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4660 send_netplayer_update_packet();
4662 Multi_mission_loaded = 1;
4663 nprintf(("Network","Finished loading mission\n"));
4667 void send_jump_into_mission_packet(net_player *pl)
4669 ubyte data[MAX_PACKET_SIZE];
4670 int packet_size = 0;
4672 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4674 BUILD_HEADER(JUMP_INTO_GAME);
4676 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4677 // and possible other things.
4679 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4680 ADD_INT(Netgame.game_state);
4686 multi_io_send_to_all_reliable(data, packet_size);
4688 // send to a specific player
4690 multi_io_send_reliable(pl, data, packet_size);
4694 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4696 int offset = HEADER_LENGTH;
4699 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4700 // the game could be paused, so ingame joiner needs to deal with it.
4701 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4703 Netgame.game_state = state;
4708 // handle any special processing for being in a weird substate
4709 multi_handle_state_special();
4711 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4712 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4713 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4714 multi_ingame_observer_finish();
4716 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4717 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4718 send_netplayer_update_packet();
4721 // start the mission!!
4722 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4723 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4724 gameseq_post_event(GS_EVENT_ENTER_GAME);
4725 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4726 send_netplayer_update_packet();
4730 extern time_t Player_multi_died_check;
4731 Player_multi_died_check = -1;
4733 // recalc all object pairs now
4734 extern void obj_reset_all_collisions();
4735 obj_reset_all_collisions();
4737 // display some cool text
4738 multi_common_add_text(XSTR("Received mission start\n",720),1);
4741 ml_string(NOX("Client received mission start from server - entering mission"));
4746 const char *repair_text[] = {
4748 "REPAIR_INFO_BEGIN",
4750 "REPAIR_INFO_UPDATE",
4751 "REPAIR_INFO_QUEUE",
4752 "REPAIR_INFO_ABORT",
4753 "REPAIR_INFO_BROKEN",
4754 "REPAIR_INFO_WARP_ADD",
4755 "REPAIR_INFO_WARP_REMOVE",
4756 "REPAIR_INFO_ONWAY",
4757 "REPAIR_INFO_KILLED",
4758 "REPAIR_INFO_COMPLETE",
4763 // the following two routines deal with updating and sending information regarding players
4764 // rearming and repairing during the game. The process function calls the routines to deal with
4765 // setting flags and other interesting things.
4766 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4768 int packet_size = 0;
4769 ushort repaired_signature, repair_signature;
4770 ubyte data[MAX_PACKET_SIZE];
4773 // use the network signature of the destination object if there is one, -1 otherwise.
4774 // client will piece it all together
4775 repaired_signature = repaired_objp->net_signature;
4777 // the repair ship may be NULL here since it might have been destroyed
4778 repair_signature = 0;
4780 repair_signature = repair_objp->net_signature;
4783 BUILD_HEADER(CLIENT_REPAIR_INFO);
4786 ADD_USHORT( repaired_signature );
4787 ADD_USHORT( repair_signature );
4789 multi_io_send_to_all_reliable(data, packet_size);
4791 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));
4794 void process_repair_info_packet(ubyte *data, header *hinfo)
4796 int offset = HEADER_LENGTH;
4797 ushort repaired_signature, repair_signature;
4798 object *repaired_objp, *repair_objp;
4802 GET_USHORT( repaired_signature );
4803 GET_USHORT( repair_signature );
4806 repaired_objp = multi_get_network_object( repaired_signature );
4807 repair_objp = multi_get_network_object( repair_signature );
4809 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));
4811 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4815 if ( repaired_objp == NULL ) {
4816 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4820 // the hope is to simply call the routine in the ai code to set/unset flags
4821 // based on the code value and everything else should happen..I hope....
4822 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4824 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4826 // set the dock flags when repair begins. Prevents problem in lagging docking
4827 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4829 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4830 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4831 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4834 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4836 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4837 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4840 if ( code == REPAIR_INFO_WARP_ADD ){
4841 mission_warp_in_support_ship( repaired_objp );
4843 mission_remove_scheduled_repair( repaired_objp );
4848 // sends information updating clients on certain AI information that clients will
4849 // need to know about to keep HUD information up to date. objp is the object that we
4850 // are updating, and what is the type of stuff that we are updating.
4851 void send_ai_info_update_packet( object *objp, char what )
4854 ushort other_signature;
4855 ubyte data[MAX_PACKET_SIZE];
4857 ubyte dock_index, dockee_index;
4859 // SDL_assert( objp->type == OBJ_SHIP );
4860 if(objp->type != OBJ_SHIP){
4863 aip = &Ai_info[Ships[objp->instance].ai_index];
4866 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4869 BUILD_HEADER( AI_INFO_UPDATE );
4870 ADD_USHORT( objp->net_signature );
4873 // depending on the "what" value, we will send different information
4877 case AI_UPDATE_DOCK:
4878 // for docking ships, add the signature of the ship that we are docking with.
4879 SDL_assert( aip->dock_objnum != -1 );
4880 other_signature = Objects[aip->dock_objnum].net_signature;
4881 dock_index = (ubyte)(aip->dock_index);
4882 dockee_index = (ubyte)(aip->dockee_index);
4883 ADD_USHORT( other_signature );
4884 ADD_DATA(dock_index);
4885 ADD_DATA(dockee_index);
4888 case AI_UPDATE_UNDOCK:
4889 // for undocking ships, check the dock_objnum since we might or might not have it
4890 // depending on whether or not a ship was destroyed while we were docked.
4891 other_signature = 0;
4892 if ( aip->dock_objnum != -1 )
4893 other_signature = Objects[aip->dock_objnum].net_signature;
4894 ADD_USHORT( other_signature );
4898 case AI_UPDATE_ORDERS: {
4901 // for orders, we only need to send a little bit of information here. Be sure that the
4902 // first order for this ship is active
4903 SDL_assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4904 ADD_INT( aip->goals[0].ai_mode );
4905 ADD_INT( aip->goals[0].ai_submode );
4907 if ( aip->goals[0].ship_name != NULL )
4908 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4910 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4911 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4912 if ( shipnum != -1 ) {
4913 SDL_assert( Ships[shipnum].objnum != -1 );
4914 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4916 other_signature = 0;
4918 ADD_USHORT( other_signature );
4920 // for docking, add the dock and dockee index
4921 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4922 SDL_assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4923 SDL_assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4924 dock_index = (ubyte)aip->goals[0].docker.index;
4925 dockee_index = (ubyte)aip->goals[0].dockee.index;
4926 ADD_DATA( dock_index );
4927 ADD_DATA( dockee_index );
4936 multi_rate_add(1, "aiu", packet_size);
4937 multi_io_send_to_all_reliable(data, packet_size);
4940 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4941 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4942 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4944 int offset = HEADER_LENGTH;
4946 ushort net_signature, other_net_signature;
4947 object *objp, *other_objp;
4950 ubyte dock_index = 0, dockee_index = 0;
4952 GET_USHORT( net_signature ); // signature of the object that we are dealing with.
4953 GET_DATA( code ); // code of what we are doing.
4954 objp = multi_get_network_object( net_signature );
4956 nprintf(("Network", "Couldn't find object for ai update\n"));
4960 case AI_UPDATE_DOCK:
4961 GET_USHORT( other_net_signature );
4962 GET_DATA( dock_index );
4963 GET_DATA( dockee_index );
4964 other_objp = multi_get_network_object( other_net_signature );
4965 if ( !other_objp ) {
4966 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4969 // if we don't have an object to work with, break out of loop
4970 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4974 SDL_assert( other_objp->type == OBJ_SHIP );
4975 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4976 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4978 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4979 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4981 ai_do_objects_docked_stuff( objp, other_objp );
4984 case AI_UPDATE_UNDOCK:
4985 GET_USHORT( other_net_signature );
4986 other_objp = multi_get_network_object( other_net_signature );
4988 // if we don't have an object to work with, break out of loop
4992 ai_do_objects_undocked_stuff( objp, other_objp );
4995 case AI_UPDATE_ORDERS:
4998 GET_USHORT( other_net_signature );
4999 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5000 GET_DATA(dock_index);
5001 GET_DATA(dockee_index);
5004 // be sure that we have a ship object!!!
5005 if ( !objp || (objp->type != OBJ_SHIP) )
5008 // set up the information in the first goal element of the object in question
5009 aip = &Ai_info[Ships[objp->instance].ai_index];
5010 aip->active_goal = 0;
5011 aip->goals[0].ai_mode = mode;
5012 aip->goals[0].ai_submode = submode;
5014 // for docking, add the dock and dockee index
5015 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5016 aip->dock_index = dock_index;
5017 aip->dockee_index = dockee_index;
5020 // get a shipname if we can.
5021 other_objp = multi_get_network_object( other_net_signature );
5022 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5023 // get a pointer to the shipname in question. Use the ship_name value in the
5024 // ship. We are only using this for HUD display, so I think that using this
5025 // method will be fine.
5026 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
5028 // special case for destroy subsystem -- get the ai_info pointer to our target ship
5029 // so that we can properly set up what subsystem this ship is attacking.
5030 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5031 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5033 // if docking -- set the dock index and dockee index of this other ship
5034 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5035 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
5036 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
5043 Int3(); // this Int3() should be temporary
5044 nprintf(("Network", "Invalid code for ai update: %d\n", code));
5050 // tell the standalone to move into the MISSION_SYNC_STATE
5051 void send_mission_sync_packet(int mode,int start_campaign)
5053 ubyte data[MAX_PACKET_SIZE],is_campaign;
5054 int packet_size = 0;
5056 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
5058 // build the header and add the sync mode (pre or post briefing)
5059 BUILD_HEADER(MISSION_SYNC_DATA);
5062 // if this is a campaign game
5063 if(mode == MULTI_SYNC_PRE_BRIEFING){
5064 if(Game_mode & GM_CAMPAIGN_MODE){
5065 // add a byte indicating campaign mode
5067 ADD_DATA(is_campaign);
5069 // add a byte indicating if we should be starting a campaign or continuing it
5070 is_campaign = (ubyte)start_campaign;
5071 ADD_DATA(is_campaign);
5073 // add the campaign filename
5074 ADD_STRING(Netgame.campaign_name);
5076 // otherwise if this is a single mission
5078 // add a byte indicating single mission mode
5080 ADD_DATA(is_campaign);
5082 // add the mission filename
5083 ADD_STRING(Game_current_mission_filename);
5086 multi_io_send_reliable(Net_player, data, packet_size);
5089 // move into the MISSION_SYNC state when this is received
5090 // this packet is sent only from a game host to a standalone
5091 void process_mission_sync_packet(ubyte *data, header *hinfo)
5094 ubyte campaign_flag;
5095 int offset = HEADER_LENGTH;
5097 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5099 // if this is a team vs team situation, lock the players send a final team update
5100 if(Netgame.type_flags & NG_TYPE_TEAM){
5101 multi_team_host_lock_all();
5102 multi_team_send_update();
5105 // get the sync mode (pre or post briefing)
5108 if(mode == MULTI_SYNC_PRE_BRIEFING){
5109 // get the flag indicating if this is a single mission or a campaign mode
5110 GET_DATA(campaign_flag);
5112 // get the flag indicating whether we should be starting a new campaign
5113 GET_DATA(campaign_flag);
5115 // get the campaign filename
5116 GET_STRING(Netgame.campaign_name);
5118 // either start a new campaign or continue on to the next mission in the current campaign
5120 multi_campaign_start(Netgame.campaign_name);
5122 multi_campaign_next_mission();
5125 // make sure we remove the campaign mode flag
5126 Game_mode &= ~(GM_CAMPAIGN_MODE);
5128 // get the single mission filename
5129 GET_STRING(Game_current_mission_filename);
5130 SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
5135 // set the correct mode and m ove into the state
5136 Multi_sync_mode = mode;
5137 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5140 // tell a player to merge his mission stats into his alltime stats
5141 void send_store_stats_packet(int accept)
5144 int packet_size = 0;
5146 BUILD_HEADER(STORE_MISSION_STATS);
5148 // add whether we're accepting or tossing
5149 val = (ubyte)accept;
5152 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5153 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5154 multi_io_send_to_all_reliable(data, packet_size);
5156 multi_io_send_reliable(Net_player, data, packet_size);
5160 void process_store_stats_packet(ubyte *data, header *hinfo)
5162 int offset = HEADER_LENGTH;
5168 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5169 if(Game_mode & GM_STANDALONE_SERVER){
5170 // rebroadcast the packet to all others in the game
5171 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5172 multi_io_send_to_all_reliable(data, offset);
5175 // all players should mark the stats as being accepted in the debriefing
5176 multi_debrief_stats_accept();
5178 // all players should mark the stats as being "tossed" in the debriefing
5179 multi_debrief_stats_toss();
5184 void send_debris_update_packet(object *objp,int code)
5186 ubyte data[MAX_PACKET_SIZE];
5188 int packet_size = 0;
5190 BUILD_HEADER(DEBRIS_UPDATE);
5191 ADD_USHORT(objp->net_signature);
5195 // add any extra relevant data
5197 case DEBRIS_UPDATE_UPDATE:
5198 // ADD_DATA(objp->pos); // add position
5199 add_vector_data(data, &packet_size, objp->pos);
5200 ADD_ORIENT(objp->orient); // add orientation
5201 // ADD_DATA(objp->phys_info.vel); // add velocity
5202 add_vector_data(data, &packet_size, objp->phys_info.vel);
5203 // ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5204 add_vector_data(data, &packet_size, objp->phys_info.rotvel);
5207 multi_io_send_to_all(data, packet_size);
5210 void process_debris_update_packet(ubyte *data, header *hinfo)
5214 object bogus_object;
5216 int offset = HEADER_LENGTH;
5218 GET_USHORT(net_sig);
5222 objp = multi_get_network_object(net_sig);
5224 objp = &bogus_object;
5228 // update the object
5229 case DEBRIS_UPDATE_UPDATE:
5230 //GET_DATA(objp->pos);
5231 get_vector_data( data, &offset, objp->pos );
5233 GET_ORIENT(objp->orient);
5234 GET_DATA(objp->phys_info.vel);
5235 GET_DATA(objp->phys_info.rotvel);
5237 // simply remove it (no explosion)
5238 case DEBRIS_UPDATE_REMOVE:
5239 if(objp != &bogus_object){
5240 SDL_assert(objp->type == OBJ_DEBRIS);
5241 obj_delete(OBJ_INDEX(objp));
5245 case DEBRIS_UPDATE_NUKE:
5246 if(objp != &bogus_object)
5247 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5255 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)
5257 ubyte data[MAX_PACKET_SIZE];
5259 int packet_size = 0;
5261 BUILD_HEADER(WSS_REQUEST_PACKET);
5263 // add the request information
5264 ADD_SHORT(player_id);
5266 ADD_INT(from_index);
5269 ADD_INT(wl_ship_slot); // only used in weapons loadout
5270 ADD_INT(ship_class);
5273 // a standard request
5275 multi_io_send_reliable(Net_player, data, packet_size);
5277 // being routed through the standalone to the host of the game
5279 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
5280 multi_io_send_reliable(p, data, packet_size);
5284 void process_wss_request_packet(ubyte *data, header *hinfo)
5286 int offset = HEADER_LENGTH;
5287 int from_slot,from_index;
5288 int to_slot,to_index;
5290 int wl_ship_slot,ship_class;
5294 // determine who this request is from
5295 GET_SHORT(player_id);
5296 player_num = find_player_id(player_id);
5298 // read in the request data
5300 GET_INT(from_index);
5303 GET_INT(wl_ship_slot); // only used in weapons loadout
5304 GET_INT(ship_class); // only used in multi team select
5308 SDL_assert(player_num != -1);
5309 if(player_num == -1){
5313 // if we're the standalone, we have to route this packet to the host of the game
5314 if(Game_mode & GM_STANDALONE_SERVER){
5315 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5317 // otherwise we're the host and should process the request
5320 case WSS_WEAPON_SELECT :
5321 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5323 case WSS_SHIP_SELECT :
5324 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5332 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5334 ubyte data[MAX_PACKET_SIZE],team;
5335 int packet_size = 0;
5337 SDL_assert(size <= (MAX_PACKET_SIZE - 10));
5339 BUILD_HEADER(WSS_UPDATE_PACKET);
5341 // add the team/pool # this is for
5342 team = (ubyte)team_num;
5345 // add the data block size
5348 // add the data itself
5349 memcpy(data + packet_size,wss_data,size);
5350 packet_size += size;
5352 // if we're also the master of the game (not on a standalone)
5353 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5354 multi_io_send_to_all_reliable(data, packet_size);
5356 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5358 multi_io_send_reliable(Net_player, data, packet_size);
5362 void process_wss_update_packet(ubyte *data, header *hinfo)
5365 int size,player_index,idx;
5366 int offset = HEADER_LENGTH;
5368 // get the team/pool #
5371 // get the data size
5374 // if we're the standalone, then we should be routing this data to all the other clients
5375 if(Game_mode & GM_STANDALONE_SERVER){
5380 // determine where this came from
5381 player_index = find_player_id(hinfo->id);
5382 SDL_assert(player_index != -1);
5383 if(player_index < 0){
5387 // route the packet (don't resend it to the host)
5388 for(idx=0;idx<MAX_PLAYERS;idx++){
5389 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5390 multi_io_send_reliable(&Net_players[idx], data, offset);
5394 // set the proper pool pointers
5395 ss_set_team_pointers((int)team);
5397 // read in the block of data, and apply it to the weapons/ship pools
5398 offset += restore_wss_data(data + offset);
5401 // set the pool pointers back to my own team
5402 ss_set_team_pointers(Net_player->p_info.team);
5404 // sync the interface if this was for my own team
5405 if((int)team == Net_player->p_info.team){
5406 multi_ts_sync_interface();
5413 // function to send firing information from the client to the server once they reach
5414 // the final sync screen.
5415 void send_firing_info_packet()
5417 ubyte data[MAX_PACKET_SIZE];
5419 ubyte plinked, sdual;
5421 SDL_assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5423 BUILD_HEADER(FIRING_INFO);
5424 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5425 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5426 ADD_DATA( plinked );
5429 multi_io_send_reliable(Net_player, data, packet_size);
5432 void process_firing_info_packet( ubyte *data, header *hinfo )
5434 int offset, player_num;
5435 ubyte plinked, sdual;
5438 // only the master of the game should be dealing with these packets
5439 SDL_assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5441 offset = HEADER_LENGTH;
5442 GET_DATA( plinked );
5446 player_num = find_player_id(hinfo->id);
5448 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5452 // get the ship pointer for this player and set the flags accordingly.
5453 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5455 shipp->flags |= SF_PRIMARY_LINKED;
5457 shipp->flags &= ~SF_PRIMARY_LINKED;
5460 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5462 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5465 // packet to deal with changing status of mission goals. used to be sent every so often from server
5466 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5467 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5468 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5469 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5471 ubyte data[MAX_PACKET_SIZE];
5474 BUILD_HEADER(MISSION_GOAL_INFO);
5477 ADD_INT(new_status);
5480 multi_io_send_to_all_reliable(data, packet_size);
5483 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5485 int offset, goal_num, new_status, valid;
5487 offset = HEADER_LENGTH;
5489 GET_INT(new_status);
5493 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5494 if ( new_status != -1 ){
5495 mission_goal_status_change( goal_num, new_status );
5497 mission_goal_validation_change( goal_num, valid );
5501 void send_player_settings_packet(net_player *p)
5503 ubyte data[MAX_PACKET_SIZE];
5506 int packet_size = 0;
5509 BUILD_HEADER(PLAYER_SETTINGS);
5511 // add all the data for all the players
5513 for(idx=0;idx<MAX_PLAYERS;idx++){
5514 if(MULTI_CONNECTED(Net_players[idx])){
5516 ADD_SHORT(Net_players[idx].player_id);
5518 // break the p_info structure by member, so we don't overwrite any absolute pointers
5519 // ADD_DATA(Net_players[idx].p_info);
5520 ADD_INT(Net_players[idx].p_info.team);
5521 ADD_INT(Net_players[idx].p_info.ship_index);
5522 ADD_INT(Net_players[idx].p_info.ship_class);
5525 // add the stop byte
5529 // either broadcast the data or send to a specific player
5531 multi_io_send_to_all_reliable(data, packet_size);
5533 multi_io_send_reliable(p, data, packet_size);
5537 void process_player_settings_packet(ubyte *data, header *hinfo)
5539 int offset,player_num;
5540 net_player_info bogus,*ptr;
5544 offset = HEADER_LENGTH;
5546 // read in the data for all the players
5548 while(stop != 0xff){
5549 // lookup the player
5550 GET_SHORT(player_id);
5551 player_num = find_player_id(player_id);
5553 // make sure this is a valid player
5554 if(player_num == -1){
5557 ptr = &Net_players[player_num].p_info;
5561 GET_INT(ptr->ship_index);
5562 GET_INT(ptr->ship_class);
5569 // update the server with my new state
5570 // MWA -- 3/31/98 -- check for in mission instead of state.
5571 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5572 if( !(Game_mode & GM_IN_MISSION) ) {
5573 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5574 send_netplayer_update_packet();
5578 // display some cool text
5579 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5582 void send_deny_packet(net_addr *addr, int code)
5585 int packet_size = 0;
5587 // build the header and add the rejection code
5593 psnet_send(addr, data, packet_size);
5596 void process_deny_packet(ubyte *data, header *hinfo)
5600 // get the denial code
5601 offset = HEADER_LENGTH;
5605 // if there is already a dialog active, do nothing - who cares at this point.
5610 // display the appropriate dialog
5612 case JOIN_DENY_JR_STATE :
5613 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));
5615 case JOIN_DENY_JR_TRACKER_INVAL :
5616 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));
5618 case JOIN_DENY_JR_PASSWD :
5619 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5621 case JOIN_DENY_JR_CLOSED :
5622 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));
5624 case JOIN_DENY_JR_TEMP_CLOSED :
5625 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));
5627 case JOIN_DENY_JR_RANK_HIGH :
5628 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));
5630 case JOIN_DENY_JR_RANK_LOW :
5631 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));
5633 case JOIN_DENY_JR_DUP :
5634 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5636 case JOIN_DENY_JR_FULL :
5637 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5639 case JOIN_DENY_JR_BANNED :
5640 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5642 case JOIN_DENY_JR_NOOBS :
5643 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5645 case JOIN_DENY_JR_INGAME_JOIN :
5646 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));
5648 case JOIN_DENY_JR_BAD_VERSION :
5649 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));
5651 case JOIN_DENY_JR_TYPE :
5652 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5656 // call this so that the join request timestamp automatically expires when we hear back from the server
5657 multi_join_reset_join_stamp();
5660 // this packet will consist of
5661 // 1.) netplayer ship classes (85 bytes max)
5662 // 2.) ship weapon state data (241 bytes max)
5663 // 3.) player settings et. al. (133 bytes max)
5664 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5665 void send_post_sync_data_packet(net_player *p, int std_request)
5667 ubyte data[MAX_PACKET_SIZE], val;
5672 ushort sval, ship_ets;
5673 int idx, player_index;
5674 int packet_size = 0;
5678 BUILD_HEADER(POST_SYNC_DATA);
5680 // some header information for standalone packet routing purposes
5681 val = (ubyte)std_request;
5684 // the standalone has two situations
5685 // 1.) sending a request to the host to distribute this block of data
5686 // 2.) having recevied this block of data from the host, it redistributes it
5687 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5688 // case 1, send the request
5689 multi_io_send_reliable(Netgame.host, data, packet_size);
5692 // case 2 for the standalone is below (as normal)
5694 // otherwise build the data now
5696 // add all deleted ships
5697 val = (ubyte)Multi_ts_num_deleted;
5699 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5700 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5706 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5707 shipp = &Ships[Objects[so->objnum].instance];
5709 // don't process non player wing ships
5710 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5716 // # of ships - used multiple times in the packet
5717 val = (ubyte)ship_count;
5720 // add ship class information (85 bytes max)
5721 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5722 shipp = &Ships[Objects[so->objnum].instance];
5724 // don't process non player wing ships
5725 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5728 // add the net signature of the object for look up
5729 ADD_USHORT( Objects[so->objnum].net_signature );
5731 // add the ship info index
5732 val = (ubyte)(shipp->ship_info_index);
5735 // add the ships's team select index
5736 val = (ubyte)shipp->ts_index;
5740 // add weapon state information for all starting ships (241 bytes max)
5741 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5742 shipp = &Ships[Objects[so->objnum].instance];
5744 // don't process non player wing ships
5745 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5748 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5750 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5751 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5752 if(player_index == -1){
5755 pl = &Net_players[player_index];
5759 // add the net signature and other weapon information
5760 ADD_USHORT( Objects[so->objnum].net_signature );
5762 // add number of primary and secondary banks
5763 bval = (char)(shipp->weapons.num_primary_banks);
5765 bval = (char)(shipp->weapons.num_secondary_banks);
5768 // add weapon bank status
5769 bval = (char)(shipp->weapons.current_primary_bank);
5771 pl->s_info.cur_primary_bank = bval;
5773 // SDL_assert(bval != -1);
5776 bval = (char)(shipp->weapons.current_secondary_bank);
5778 pl->s_info.cur_secondary_bank = bval;
5780 // SDL_assert(bval != -1);
5783 // primary weapon info
5784 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5786 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5789 // secondary weapon info
5790 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5792 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5793 ADD_SHORT(val_short);
5794 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5796 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5797 ADD_SHORT(val_short);
5798 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5800 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5801 ADD_SHORT(val_short);
5803 // send primary and secondary weapon link status
5805 if(shipp->flags & SF_PRIMARY_LINKED){
5807 pl->s_info.cur_link_status |= (1<<0);
5811 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5813 pl->s_info.cur_link_status |= (1<<1);
5817 // if this is a player ship add (1<<2)
5818 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5823 // add a ship ets value
5826 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5828 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5830 ship_ets |= ((ushort)shipp->engine_recharge_index);
5831 ADD_USHORT(ship_ets);
5835 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5836 // or if I'm the server as well as the host, I should be sending this to all players
5837 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5838 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5841 multi_io_send_to_all_reliable(data, packet_size);
5843 // send to a specific player
5845 multi_io_send_reliable(p, data, packet_size);
5848 multi_io_send_reliable(Net_player, data, packet_size);
5855 multi_io_send_to_all_reliable(data, packet_size);
5857 // send to a specific player
5859 multi_io_send_reliable(p, data, packet_size);
5864 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5866 ubyte val, sinfo_index, ts_index;
5868 ushort net_sig, ship_ets, sval;
5872 int offset = HEADER_LENGTH;
5876 // packet routing information
5879 // 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
5880 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5883 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5884 multi_ts_create_wings();
5886 // send to the standalone through my socket
5887 send_post_sync_data_packet(Net_player);
5893 // add all deleted ships
5895 Multi_ts_num_deleted = (int)val;
5896 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5897 // get the ship's objnum
5900 objp = multi_get_network_object(sval);
5902 // delete the ship appropriately
5903 // mark the object as having been deleted
5904 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5907 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5908 obj_delete(Multi_ts_deleted_objnums[idx]);
5909 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5911 Multi_ts_num_deleted--;
5912 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5920 // process ship class information
5921 for(idx=0; idx<ship_count; idx++){
5922 // get the object's net signature
5923 GET_USHORT(net_sig);
5924 GET_DATA(sinfo_index);
5927 // attempt to get the object
5928 objp = multi_get_network_object(net_sig);
5930 // make sure we found a ship
5931 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5933 // set the ship to be the right class
5934 change_ship_type(objp->instance,(int)sinfo_index);
5936 // set the ship's team select index
5937 Ships[objp->instance].ts_index = (int)ts_index;
5940 // process ship weapon state info
5941 for(idx=0; idx<ship_count; idx++){
5942 // get the object's net signature
5943 GET_USHORT(net_sig);
5945 // attempt to get the object
5946 objp = multi_get_network_object(net_sig);
5948 // make sure we found a ship
5949 SDL_assert((objp != NULL) && (objp->type == OBJ_SHIP));
5951 // get a pointer to the ship
5952 shipp = &Ships[objp->instance];
5954 // get number of primary and secondary banks;
5956 SDL_assert( b != -1 );
5957 shipp->weapons.num_primary_banks = (int)b;
5960 SDL_assert( b != -1 );
5961 shipp->weapons.num_secondary_banks = (int)b;
5963 // get bank selection info
5968 shipp->weapons.current_primary_bank = (int)b;
5974 shipp->weapons.current_secondary_bank = (int)b;
5976 // primary weapon info
5978 shipp->weapons.primary_bank_weapons[0] = (int)b;
5981 shipp->weapons.primary_bank_weapons[1] = (int)b;
5983 // secondary weapon info
5985 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5986 GET_SHORT(val_short);
5987 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5990 shipp->weapons.secondary_bank_weapons[1] = (int)b;
5991 GET_SHORT(val_short);
5992 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
5995 shipp->weapons.secondary_bank_weapons[2] = (int)b;
5996 GET_SHORT(val_short);
5997 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
6004 shipp->flags |= SF_PRIMARY_LINKED;
6007 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
6009 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
6010 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
6012 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
6014 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
6018 GET_USHORT(ship_ets);
6020 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
6022 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
6024 shipp->engine_recharge_index = (ship_ets & 0x000f);
6029 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
6030 send_netplayer_update_packet();
6032 // the standalone server will receive this packet from the host of the game, to be applied locally and
6033 // also to be rebroadcast.
6034 if(Game_mode & GM_STANDALONE_SERVER){
6035 // update player ets settings
6036 for(idx=0;idx<MAX_PLAYERS;idx++){
6037 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
6038 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
6042 send_post_sync_data_packet(NULL,0);
6046 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
6048 ubyte data[MAX_PACKET_SIZE],val;
6051 int packet_size = 0;
6054 BUILD_HEADER(WSS_SLOTS_DATA);
6056 // some header information for standalone packet routing purposes
6057 val = (ubyte)std_request;
6061 val = (ubyte)team_num;
6064 // add whether this is the final packet or not
6068 // the standalone has two situations
6069 // 1.) sending a request to the host to distribute this block of data
6070 // 2.) having recevied this block of data from the host, it redistributes it
6071 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
6072 // case 1, send the request
6073 multi_io_send_reliable(Netgame.host, data, packet_size);
6076 // case 2 for the standalone is below (as normal)
6078 // add all the slots
6079 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6080 // add the ship class
6081 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
6085 for(i = 0;i<MAX_WL_WEAPONS;i++){
6086 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
6090 // add the weapon counts
6091 for(i = 0;i<MAX_WL_WEAPONS;i++){
6092 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
6093 ADD_SHORT(val_short);
6097 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
6098 // or if I'm the server as well as the host, I should be sending this to all players
6099 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
6100 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6103 multi_io_send_to_all_reliable(data, packet_size);
6105 // send to a specific player
6107 multi_io_send_reliable(p, data, packet_size);
6110 multi_io_send_reliable(Net_player, data, packet_size);
6117 multi_io_send_to_all_reliable(data, packet_size);
6119 // send to a specific player
6121 multi_io_send_reliable(p, data, packet_size);
6126 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6128 ubyte val,team_num,final;
6130 int offset = HEADER_LENGTH;
6133 // packet routing information
6139 // get whether this is the final packet or not
6142 // 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
6143 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6146 // send to the standalone through my socket
6147 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6151 // read in all the slot data
6152 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6153 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6155 // get the ship class
6157 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6160 for(i = 0;i<MAX_WL_WEAPONS;i++){
6162 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6164 // check for signed/unsigned problems
6165 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6166 Wss_slots_teams[team_num][idx].wep[i] = -1;
6170 // get the weapon counts
6171 for(i = 0;i<MAX_WL_WEAPONS;i++){
6172 GET_SHORT(val_short);
6173 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6178 // update my netplayer state if this is the final packet
6180 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6181 send_netplayer_update_packet();
6184 // the standalone server will receive this packet from the host of the game, to be applied locally and
6185 // also to be rebroadcast.
6186 if(Game_mode & GM_STANDALONE_SERVER){
6187 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6189 // add some mission sync text
6190 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6194 #define OBJ_VISIBILITY_DOT 0.6f
6196 // send and receive packets for shield explosion information
6197 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6200 ubyte data[MAX_PACKET_SIZE], utri_num;
6203 // SDL_assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6205 SDL_assert( tri_num < UCHAR_MAX );
6206 utri_num = (ubyte)tri_num;
6208 // for each player, determine if this object is behind the player -- if so, don't
6210 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6211 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6213 vector eye_to_obj_vec, diff, eye_pos;
6216 eye_pos = Net_players[i].s_info.eye_pos;
6217 eye_orient = Net_players[i].s_info.eye_orient;
6219 // check for same vectors
6220 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6221 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6225 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6226 dot = vm_vec_dot(&eye_orient.v.fvec, &eye_to_obj_vec);
6228 if ( dot < OBJ_VISIBILITY_DOT ){
6232 BUILD_HEADER(SHIELD_EXPLOSION);
6234 ADD_USHORT( Objects[objnum].net_signature );
6237 multi_io_send(&Net_players[i], data, packet_size);
6242 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6244 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6251 // get the shield hit data
6252 offset = HEADER_LENGTH;
6253 GET_USHORT(signature);
6255 //GET_DATA(hit_pos);
6258 // find the object with this signature. If found, then do a shield explosion
6259 objp = multi_get_network_object( signature );
6262 shield_info *shieldp;
6267 // given the tri num, find the local position which is the average of the
6268 // three vertices of the triangle affected. Use this average point as the hit
6270 // SDL_assert( objp->type == OBJ_SHIP );
6271 if(objp->type != OBJ_SHIP){
6275 pm = model_get(Ships[objp->instance].modelnum);
6276 shieldp = &pm->shield;
6277 SDL_assert( utri_num < shieldp->ntris );
6278 stri = shieldp->tris[utri_num];
6279 vm_vec_zero(&hit_pos);
6280 for ( i = 0; i < 3; i++ ) {
6281 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6283 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6284 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6288 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6291 ubyte data[MAX_PACKET_SIZE], val;
6293 int packet_size = 0;
6298 sc = &pl->player->stats;
6301 BUILD_HEADER(PLAYER_STATS);
6303 // add the player id
6304 ADD_SHORT(pl->player_id);
6306 // add the byte indicating whether these stats are all-time or not
6307 val = (ubyte)stats_code;
6310 // kill information - alltime
6314 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6315 u_tmp = sc->kills[idx];
6318 // medal information
6319 for(idx=0;idx<NUM_MEDALS;idx++){
6320 i_tmp = sc->medals[idx];
6326 ADD_INT(sc->assists);
6327 ADD_INT(sc->kill_count);
6328 ADD_INT(sc->kill_count_ok);
6329 ADD_UINT(sc->p_shots_fired);
6330 ADD_UINT(sc->s_shots_fired);
6331 ADD_UINT(sc->p_shots_hit);
6332 ADD_UINT(sc->s_shots_hit);
6333 ADD_UINT(sc->p_bonehead_hits);
6334 ADD_UINT(sc->s_bonehead_hits);
6335 ADD_INT(sc->bonehead_kills);
6337 ADD_UINT(sc->missions_flown);
6338 ADD_UINT(sc->flight_time);
6339 ADD_INT(sc->last_flown);
6340 ADD_INT(sc->last_backup);
6345 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6346 u_tmp = sc->m_okKills[idx];
6350 ADD_INT(sc->m_score);
6351 ADD_INT(sc->m_assists);
6352 ADD_INT(sc->m_kill_count);
6353 ADD_INT(sc->m_kill_count_ok);
6354 ADD_UINT(sc->mp_shots_fired);
6355 ADD_UINT(sc->ms_shots_fired);
6356 ADD_UINT(sc->mp_shots_hit);
6357 ADD_UINT(sc->ms_shots_hit);
6358 ADD_UINT(sc->mp_bonehead_hits);
6359 ADD_UINT(sc->ms_bonehead_hits);
6360 ADD_INT(sc->m_bonehead_kills);
6361 ADD_INT(sc->m_player_deaths);
6362 ADD_INT(sc->m_medal_earned);
6365 case STATS_MISSION_KILLS:
6366 ADD_INT(sc->m_kill_count);
6367 ADD_INT(sc->m_kill_count_ok);
6368 ADD_INT(sc->m_assists);
6371 case STATS_DOGFIGHT_KILLS:
6372 for(idx=0; idx<MAX_PLAYERS; idx++){
6374 u_tmp = sc->m_dogfight_kills[idx];
6380 ADD_INT(sc->m_kill_count);
6381 ADD_INT(sc->m_kill_count_ok);
6382 ADD_INT(sc->m_assists);
6386 SDL_assert(packet_size < MAX_PACKET_SIZE);
6388 // if we're a client, always send the data to the server
6389 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6390 multi_io_send_reliable(Net_player, data, packet_size);
6392 // otherwise do server specific stuff
6394 // send to a specific target
6396 multi_io_send_reliable(target, data, packet_size);
6398 // otherwise, send to everyone
6400 multi_io_send_to_all_reliable(data, packet_size);
6405 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6409 scoring_struct *sc,bogus;
6411 int offset = HEADER_LENGTH;
6415 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6417 // get the player who these stats are for
6418 GET_SHORT(player_id);
6419 player_num = find_player_id(player_id);
6420 if (player_num == -1) {
6421 nprintf(("Network", "Couldn't find player for stats update!\n"));
6422 ml_string("Couldn't find player for stats update!\n");
6427 sc = &Net_players[player_num].player->stats;
6430 // get the stats code
6434 ml_string("Received STATS_ALLTIME\n");
6437 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6439 sc->kills[idx] = u_tmp;
6442 // read in the stats
6443 for (idx=0; idx<NUM_MEDALS; idx++) {
6445 sc->medals[idx] = i_tmp;
6450 GET_INT(sc->assists);
6451 GET_INT(sc->kill_count);
6452 GET_INT(sc->kill_count_ok);
6453 GET_UINT(sc->p_shots_fired);
6454 GET_UINT(sc->s_shots_fired);
6455 GET_UINT(sc->p_shots_hit);
6456 GET_UINT(sc->s_shots_hit);
6457 GET_UINT(sc->p_bonehead_hits);
6458 GET_UINT(sc->s_bonehead_hits);
6459 GET_INT(sc->bonehead_kills);
6461 GET_UINT(sc->missions_flown);
6462 GET_UINT(sc->flight_time);
6463 GET_INT(sc->last_flown);
6464 GET_INT(sc->last_backup);
6468 ml_string("Received STATS_MISSION\n");
6470 // kills - mission OK
6471 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6473 sc->m_okKills[idx] = u_tmp;
6476 GET_INT(sc->m_score);
6477 GET_INT(sc->m_assists);
6478 GET_INT(sc->m_kill_count);
6479 GET_INT(sc->m_kill_count_ok);
6480 GET_UINT(sc->mp_shots_fired);
6481 GET_UINT(sc->ms_shots_fired);
6482 GET_UINT(sc->mp_shots_hit);
6483 GET_UINT(sc->ms_shots_hit);
6484 GET_UINT(sc->mp_bonehead_hits);
6485 GET_UINT(sc->ms_bonehead_hits);
6486 GET_INT(sc->m_bonehead_kills);
6487 GET_INT(sc->m_player_deaths);
6488 GET_INT(sc->m_medal_earned);
6491 case STATS_MISSION_KILLS:
6492 ml_string("Received STATS_MISSION_KILLS\n");
6494 GET_INT(sc->m_kill_count);
6495 GET_INT(sc->m_kill_count_ok);
6496 GET_INT(sc->m_assists);
6499 case STATS_DOGFIGHT_KILLS:
6500 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6501 if(player_num >= 0){
6502 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6504 for(idx=0; idx<MAX_PLAYERS; idx++){
6507 sc->m_dogfight_kills[idx] = u_tmp;
6508 if(player_num >= 0){
6509 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6513 GET_INT(sc->m_kill_count);
6514 GET_INT(sc->m_kill_count_ok);
6515 GET_INT(sc->m_assists);
6520 // if I'm the server of the game, I should always rebroadcast these stats
6521 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6522 // make sure these are alltime stats
6523 SDL_assert(val == STATS_ALLTIME);
6525 multi_broadcast_stats(STATS_ALLTIME);
6529 // called to create asteroid stuff
6530 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6533 ubyte data[MAX_PACKET_SIZE];
6534 ubyte packet_type, atype;
6538 if (relvec != NULL )
6541 BUILD_HEADER( ASTEROID_INFO );
6542 packet_type = ASTEROID_CREATE;
6544 SDL_assert( asteroid_type < UCHAR_MAX );
6545 atype = (ubyte)asteroid_type;
6547 ADD_DATA( packet_type );
6548 ADD_USHORT( parent_objp->net_signature );
6549 ADD_USHORT( new_objp->net_signature );
6552 add_vector_data( data, &packet_size, vec );
6554 multi_io_send_to_all(data, packet_size);
6557 void send_asteroid_throw( object *objp )
6560 ubyte data[MAX_PACKET_SIZE], packet_type;
6562 BUILD_HEADER( ASTEROID_INFO );
6564 // this packet type is an asteroid throw
6565 packet_type = ASTEROID_THROW;
6566 ADD_DATA( packet_type );
6567 ADD_USHORT( objp->net_signature );
6568 //ADD_DATA( objp->pos );
6569 add_vector_data( data, &packet_size, objp->pos );
6570 //ADD_DATA( objp->phys_info.vel );
6571 add_vector_data( data, &packet_size, objp->phys_info.vel );
6573 multi_io_send_to_all(data, packet_size);
6576 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6579 ubyte data[MAX_PACKET_SIZE], packet_type;
6583 if ( hitpos != NULL )
6586 // build up an asteroid hit packet
6587 BUILD_HEADER( ASTEROID_INFO );
6588 packet_type = ASTEROID_HIT;
6589 ADD_DATA( packet_type );
6590 ADD_USHORT( objp->net_signature );
6592 if(other_objp == NULL){
6593 ushort invalid_sig = 0xffff;
6594 ADD_USHORT(invalid_sig);
6596 ADD_USHORT( other_objp->net_signature );
6599 add_vector_data( data, &packet_size, vec );
6600 ADD_FLOAT( damage );
6602 multi_io_send_to_all(data, packet_size);
6605 void process_asteroid_info( ubyte *data, header *hinfo )
6610 offset = HEADER_LENGTH;
6611 GET_DATA( packet_type );
6613 // based on the packet type, do something interesting with an asteroid!
6614 switch( packet_type ) {
6616 case ASTEROID_CREATE: {
6617 ushort psignature, signature;
6619 vector relvec = ZERO_VECTOR;
6620 object *parent_objp;
6622 GET_USHORT( psignature );
6623 GET_USHORT( signature );
6625 //GET_DATA( relvec );
6626 get_vector_data( data, &offset, relvec );
6628 // after getting the values, set the next network signature, and call the create sub function
6629 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6630 parent_objp = multi_get_network_object( psignature );
6631 if ( parent_objp ) {
6632 asteroid_sub_create( parent_objp, atype, &relvec );
6634 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6641 // asteroid throw packet -- asteroid has wrapped bounds
6642 case ASTEROID_THROW: {
6644 vector pos = ZERO_VECTOR, vel = ZERO_VECTOR;
6647 GET_USHORT( signature );
6649 get_vector_data( data, &offset, pos );
6651 get_vector_data( data, &offset, vel );
6652 objp = multi_get_network_object( signature );
6654 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6658 objp->phys_info.vel = vel;
6659 objp->phys_info.desired_vel = vel;
6663 case ASTEROID_HIT: {
6664 ushort signature, osignature;
6665 object *objp, *other_objp;
6666 vector hitpos = ZERO_VECTOR;
6669 GET_USHORT( signature );
6670 GET_USHORT( osignature );
6671 //GET_DATA( hitpos );
6672 get_vector_data( data, &offset, hitpos );
6673 GET_FLOAT( damage );
6675 objp = multi_get_network_object( signature );
6676 if(osignature == 0xffff){
6679 other_objp = multi_get_network_object( osignature );
6682 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6686 if ( IS_VEC_NULL(&hitpos) ){
6687 asteroid_hit( objp, other_objp, NULL, damage );
6689 asteroid_hit( objp, other_objp, &hitpos, damage );
6692 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6693 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6694 weapon_hit( other_objp, objp, &hitpos );
6707 void send_host_restr_packet(const char *callsign, int code, int mode)
6709 ubyte data[MAX_PACKET_SIZE],val;
6710 int packet_size = 0;
6712 // build the header and add the opcode
6713 BUILD_HEADER(HOST_RESTR_QUERY);
6720 ADD_STRING(callsign);
6722 // if I'm the standalone server, I should be sending this to the game host
6723 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6724 multi_io_send_reliable(Netgame.host, data, packet_size);
6726 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6728 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6729 multi_io_send_reliable(Net_player, data, packet_size);
6733 void process_host_restr_packet(ubyte *data, header *hinfo)
6737 int offset = HEADER_LENGTH;
6739 // get the opcode and the callsign
6742 GET_STRING(callsign);
6745 // do code specific operations
6747 // query to the host from standalone
6749 SDL_assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6751 // set the join mode
6752 Multi_join_restr_mode = mode;
6754 // set the timestamp
6755 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6757 // notify the host of the event
6758 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6759 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6762 // affirmative reply from the host to the standalone
6764 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6766 // let the player join if the timestamp has not already elapsed on the server
6767 if(Multi_restr_query_timestamp != -1){
6768 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6774 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
6775 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6776 Multi_restr_query_timestamp = -1;
6781 void send_netgame_end_error_packet(int notify_code,int err_code)
6785 int packet_size = 0;
6787 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6788 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6790 // build the header and add the notification and error codes
6791 BUILD_HEADER(NETGAME_END_ERROR);
6792 code = (char)notify_code;
6794 code = (char)err_code;
6798 multi_io_send_to_all_reliable(data, packet_size);
6801 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6803 int offset = HEADER_LENGTH;
6804 char notify_code,error_code;
6806 // get the error and notification codes
6807 GET_DATA(notify_code);
6808 GET_DATA(error_code);
6812 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6815 // sends info that a countermeasure succeeded.
6816 void send_countermeasure_success_packet( int objnum )
6818 int pnum, packet_size;
6819 ubyte data[MAX_PACKET_SIZE];
6821 pnum = multi_find_player_by_object( &Objects[objnum] );
6823 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6827 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6828 multi_io_send(&Net_players[pnum], data, packet_size);
6831 // start the flashing of my hud gauge
6832 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6836 offset = HEADER_LENGTH;
6839 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6840 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6843 #define UPDATE_IS_PAUSED (1<<0)
6844 #define UPDATE_HULL_INFO (1<<1)
6846 void send_client_update_packet(net_player *pl)
6848 ubyte data[MAX_PACKET_SIZE],val;
6849 int packet_size = 0;
6852 BUILD_HEADER(CLIENT_UPDATE);
6856 // add the pause status
6857 if ( Multi_pause_status ) {
6858 val |= UPDATE_IS_PAUSED;
6859 } 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) ) {
6860 val |= UPDATE_HULL_INFO;
6861 SDL_assert( Player_ship ); // I"d better have one of these!!!!
6866 // if paused, add the net address of the guy who paused
6867 if(val & UPDATE_IS_PAUSED){
6868 SDL_assert(Multi_pause_pauser != NULL);
6869 ADD_SHORT(Multi_pause_pauser->player_id);
6872 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6873 if ( val & UPDATE_HULL_INFO ) {
6875 ubyte percent, ns, threats;
6878 ship_subsys *subsysp;
6881 // get the object for the player
6882 SDL_assert( pl->player->objnum != -1 );
6884 objp = &Objects[pl->player->objnum];
6886 SDL_assert ( objp->type == OBJ_SHIP );
6887 shipp = &Ships[objp->instance];
6888 sip = &Ship_info[shipp->ship_info_index];
6890 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6891 // percentage value since that should be close enough
6892 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6896 percent = (ubyte)temp;
6898 ADD_DATA( percent );
6900 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6901 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6902 ADD_DATA( percent );
6905 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6906 // both machines. Added as percent since that number <= 100
6908 // also write out the number of subsystems. We do this because the client might not know
6909 // about the object he is getting data for. (i.e. he killed the object already).
6910 ns = (ubyte)sip->n_subsystems;
6913 // now the subsystems.
6914 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6915 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6916 ADD_DATA( percent );
6919 // compute the threats for this player. Only compute the threats if this player is actually
6920 // playing (i.e. he has a ship)
6921 hud_update_reticle( pl->player );
6922 threats = (ubyte)pl->player->threat_flags;
6923 ADD_DATA( threats );
6925 // add his energy level for guns
6926 ADD_FLOAT(shipp->weapon_energy);
6928 // add his secondary bank ammo
6929 ADD_INT(shipp->weapons.num_secondary_banks);
6930 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6931 ADD_INT(shipp->weapons.secondary_bank_ammo[i]);
6936 ADD_INT(pl->sv_last_pl);
6938 // send the packet reliably to the player
6939 multi_io_send(pl, data, packet_size);
6942 void process_client_update_packet(ubyte *data, header *hinfo)
6947 int is_paused, have_hull_info;
6950 float weapon_energy;
6951 int offset = HEADER_LENGTH;
6953 // get the header byte containing useful information
6956 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6957 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6959 // if we are paused, get who paused
6962 player_index = find_player_id(pauser);
6963 if(player_index != -1){
6964 Multi_pause_pauser = &Net_players[player_index];
6966 Multi_pause_pauser = NULL;
6970 // if we have hull information, then read it in.
6971 if ( have_hull_info ) {
6975 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6977 ship_subsys *subsysp;
6981 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6982 // percentage value since that should be close enough
6983 GET_DATA( hull_percent );
6985 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6987 shield_percent[i] = ub_tmp;
6990 // get the data for the subsystems
6991 GET_DATA( n_subsystems );
6992 for ( i = 0; i < n_subsystems; i++ ){
6994 subsystem_percent[i] = ub_tmp;
6997 GET_DATA( threats );
6999 // add his energy level for guns
7000 GET_FLOAT(weapon_energy);
7002 // add his secondary bank ammo
7003 GET_INT(ammo_count);
7004 for(i=0; i<ammo_count; i++){
7008 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
7009 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
7010 // UDP client update packets. Only read this info if I have a ship.
7011 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
7012 shipp = Player_ship;
7014 sip = &Ship_info[shipp->ship_info_index];
7016 val = hull_percent * sip->initial_hull_strength / 100.0f;
7017 objp->hull_strength = val;
7019 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
7020 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
7021 objp->shields[i] = val;
7024 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
7025 // then don't read these in.
7026 if ( n_subsystems == sip->n_subsystems ) {
7028 n_subsystems = 0; // reuse this variable
7029 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
7032 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
7033 subsysp->current_hits = val;
7035 // add the value just generated (it was zero'ed above) into the array of generic system types
7036 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
7037 SDL_assert ( subsys_type < SUBSYSTEM_MAX );
7038 shipp->subsys_info[subsys_type].current_hits += val;
7042 ship_recalc_subsys_strength( shipp );
7044 shipp->weapon_energy = weapon_energy;
7045 for(i=0; i<ammo_count; i++){
7046 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
7049 // update my threat flags.
7050 // temporarily commented out until tested.
7051 Net_player->player->threat_flags = threats;
7058 if(Net_player != NULL){
7059 Net_player->cl_last_pl = pl;
7063 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
7064 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
7066 multi_pause_pause();
7068 multi_pause_unpause();
7073 void send_countdown_packet(int time)
7077 int packet_size = 0;
7079 // build the header and add the time
7080 BUILD_HEADER(COUNTDOWN);
7084 // if we're the server, we should broadcast to everyone
7085 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
7086 multi_io_send_to_all_reliable(data, packet_size);
7088 // otherwise we'de better be a host sending to the standalone
7090 SDL_assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
7091 multi_io_send_reliable(Net_player, data, packet_size);
7095 void process_countdown_packet(ubyte *data, header *hinfo)
7097 int offset = HEADER_LENGTH;
7104 // if we're not in the post sync data screen, ignore it
7105 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
7109 // if we're the standalone, this should be a -1 telling us to start the countdown
7110 if(Game_mode & GM_STANDALONE_SERVER){
7111 SDL_assert((int)time == -1);
7113 // start the countdown
7114 multi_sync_start_countdown();
7116 // otherwise if we're clients, just bash the countdown
7118 Multi_sync_countdown = (int)time;
7122 // packets for debriefing information
7123 void send_debrief_info( int stage_count[], int *stages[] )
7125 ubyte data[MAX_PACKET_SIZE];
7126 int packet_size, i, j;
7129 BUILD_HEADER(DEBRIEF_INFO);
7131 // add the data for the teams
7132 for ( i = 0; i < Num_teams; i++ ) {
7135 count = stage_count[i];
7137 for ( j = 0; j < count; j++ ) {
7138 i_tmp = stages[i][j];
7143 multi_io_send_to_all_reliable(data, packet_size);
7146 // process a debrief info packet from the server
7147 void process_debrief_info( ubyte *data, header *hinfo )
7150 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7153 offset = HEADER_LENGTH;
7154 for ( i = 0; i < Num_teams; i++ ) {
7158 stage_counts[i] = count;
7159 stages[i] = active_stages[i];
7160 for ( j = 0; j < count; j++ ) {
7162 active_stages[i][j] = i_tmp;
7167 // now that we have the stage data for the debriefing stages, call debrief function with the
7168 // data so that clients can now see the debriefing stuff. Do it only for my team.
7169 SDL_assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7170 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7173 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7174 // sends homing_object and homing_subsystem to all clients.
7175 void send_homing_weapon_info( int weapon_num )
7177 ubyte data[MAX_PACKET_SIZE];
7180 object *homing_object;
7181 ushort homing_signature;
7184 wp = &Weapons[weapon_num];
7186 // be sure that this weapon object is a homing object.
7187 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7190 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7191 // homing signature.
7192 homing_signature = 0;
7193 homing_object = wp->homing_object;
7194 if ( homing_object != NULL ) {
7195 homing_signature = homing_object->net_signature;
7197 // get the subsystem index.
7199 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7202 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7203 SDL_assert( s_index < CHAR_MAX ); // better be less than this!!!!
7204 t_subsys = (char)s_index;
7208 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7209 ADD_USHORT( Objects[wp->objnum].net_signature );
7210 ADD_USHORT( homing_signature );
7211 ADD_DATA( t_subsys );
7213 multi_io_send_to_all(data, packet_size);
7216 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7217 // packet contains information for multiple weapons (like hornets).
7218 void process_homing_weapon_info( ubyte *data, header *hinfo )
7221 ushort weapon_signature, homing_signature;
7223 object *homing_object, *weapon_objp;
7226 offset = HEADER_LENGTH;
7228 // get the data for the packet
7229 GET_USHORT( weapon_signature );
7230 GET_USHORT( homing_signature );
7231 GET_DATA( h_subsys );
7234 // deal with changing this weapons homing information
7235 weapon_objp = multi_get_network_object( weapon_signature );
7236 if ( weapon_objp == NULL ) {
7237 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7240 SDL_assert( weapon_objp->type == OBJ_WEAPON );
7241 wp = &Weapons[weapon_objp->instance];
7243 // be sure that we can find these weapons and
7244 homing_object = multi_get_network_object( homing_signature );
7245 if ( homing_object == NULL ) {
7246 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7250 if ( homing_object->type == OBJ_WEAPON ) {
7251 SDL_assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7254 wp->homing_object = homing_object;
7255 wp->homing_subsys = NULL;
7256 wp->target_num = OBJ_INDEX(homing_object);
7257 wp->target_sig = homing_object->signature;
7258 if ( h_subsys != -1 ) {
7259 SDL_assert( homing_object->type == OBJ_SHIP );
7260 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7263 if ( homing_object->type == OBJ_SHIP ) {
7264 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7268 void send_emp_effect(ushort net_sig, float intensity, float time)
7273 SDL_assert(MULTIPLAYER_MASTER);
7275 // build the packet and add the opcode
7276 BUILD_HEADER(EMP_EFFECT);
7277 ADD_USHORT(net_sig);
7278 ADD_FLOAT(intensity);
7281 // send it to the player
7282 multi_io_send_to_all(data, packet_size);
7285 void process_emp_effect(ubyte *data, header *hinfo)
7287 float intensity, time;
7290 int offset = HEADER_LENGTH;
7292 // read in the EMP effect data
7293 GET_USHORT(net_sig);
7294 GET_FLOAT(intensity);
7298 // try and find the object
7299 objp = multi_get_network_object(net_sig);
7300 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7301 // if i'm not an observer and I have a valid ship, play the EMP effect
7302 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7303 emp_start_local(intensity, time);
7306 // start the effect for the ship itself
7307 emp_start_ship(objp, intensity, time);
7311 // tells whether or not reinforcements are available
7312 void send_reinforcement_avail( int rnum )
7317 BUILD_HEADER(REINFORCEMENT_AVAIL);
7319 multi_io_send_to_all_reliable(data, packet_size);
7322 void process_reinforcement_avail( ubyte *data, header *hinfo )
7327 offset = HEADER_LENGTH;
7331 // sanity check for a valid reinforcement number
7332 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7333 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7337 void send_change_iff_packet(ushort net_signature, int new_team)
7339 ubyte data[MAX_PACKET_SIZE];
7340 int packet_size = 0;
7342 if(Net_player == NULL){
7345 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7349 // build the packet and add the data
7350 BUILD_HEADER(CHANGE_IFF);
7351 ADD_USHORT(net_signature);
7354 // send to all players
7355 multi_io_send_to_all_reliable(data, packet_size);
7358 void process_change_iff_packet( ubyte *data, header *hinfo)
7360 int offset = HEADER_LENGTH;
7361 ushort net_signature;
7366 GET_USHORT(net_signature);
7370 // lookup the object
7371 objp = multi_get_network_object(net_signature);
7372 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7373 Ships[objp->instance].team = new_team;
7377 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7379 int packet_size, objnum;
7380 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7383 net_player *ignore = NULL;
7385 // sanity checking for now
7386 SDL_assert ( banks_fired <= 3 );
7388 // get an object pointer for this ship.
7389 objnum = shipp->objnum;
7390 objp = &Objects[objnum];
7392 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7393 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7397 // just in case nothing got fired
7398 if(banks_fired <= 0){
7402 // ubanks_fired = (ubyte)banks_fired;
7403 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7404 // SDL_assert( current_bank <= 3 );
7406 // insert the current primary bank into this byte
7407 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7409 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7410 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7411 // ubanks_fired |= (1<<7);
7414 // determine if its a player ship and don't send to him if we're in "client firing" mode
7415 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7416 if(MULTIPLAYER_MASTER){
7417 np_index = multi_find_player_by_net_signature(objp->net_signature);
7418 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7419 ignore = &Net_players[np_index];
7423 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7424 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7425 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7426 // and server in sync w.r.t. weapon energy for player ship
7427 BUILD_HEADER( PRIMARY_FIRED_NEW );
7428 ADD_USHORT(objp->net_signature);
7429 // ADD_DATA(ubanks_fired);
7431 // if I'm a server, broadcast to all players
7432 if(MULTIPLAYER_MASTER){
7433 multi_io_send_to_all(data, packet_size, ignore);
7436 multi_rate_add(1, "wfi", packet_size);
7438 // otherwise just send to the server
7440 multi_io_send(Net_player, data, packet_size);
7444 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7446 int offset; // linked;
7447 // ubyte banks_fired, current_bank;
7452 // read all packet info
7453 offset = HEADER_LENGTH;
7454 GET_USHORT(shooter_sig);
7455 // GET_DATA(banks_fired);
7458 // find the object this fired packet is operating on
7459 objp = multi_get_network_object( shooter_sig );
7460 if ( objp == NULL ) {
7461 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7464 // if this object is not actually a valid ship, don't do anything
7465 if(objp->type != OBJ_SHIP){
7468 if(objp->instance < 0){
7471 // shipp = &Ships[objp->instance];
7473 // get the link status of the primary banks
7475 // if ( banks_fired & (1<<7) ) {
7477 // banks_fired ^= (1<<7);
7480 // get the current primary bank
7481 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7482 // current_bank &= 0x3;
7483 // SDL_assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7484 // shipp->weapons.current_primary_bank = current_bank;
7486 // strip off all remaining bits and just keep which banks were actually fired.
7487 // banks_fired &= 0x3;
7489 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7492 // shipp->flags &= ~SF_PRIMARY_LINKED;
7494 // shipp->flags |= SF_PRIMARY_LINKED;
7497 // if we're in client firing mode, ignore ones for myself
7498 if((Player_obj != NULL) && (Player_obj == objp)){
7502 ship_fire_primary( objp, 0, 1 );
7505 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7507 ubyte data[MAX_PACKET_SIZE];
7510 net_player *ignore = NULL;
7512 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7513 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7517 SDL_assert ( cmeasure_count < UCHAR_MAX );
7518 BUILD_HEADER(COUNTERMEASURE_NEW);
7519 ADD_USHORT( objp->net_signature );
7520 ADD_INT( rand_val );
7522 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7524 // determine if its a player ship and don't send to him if we're in "client firing" mode
7525 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7526 if(MULTIPLAYER_MASTER){
7527 np_index = multi_find_player_by_net_signature(objp->net_signature);
7528 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7529 ignore = &Net_players[np_index];
7533 // if I'm the server, send to all players
7534 if(MULTIPLAYER_MASTER){
7535 multi_io_send_to_all(data, packet_size, ignore);
7537 // otherwise send to the server
7539 multi_io_send(Net_player, data, packet_size);
7543 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7550 offset = HEADER_LENGTH;
7551 GET_USHORT( signature );
7552 GET_INT( rand_val );
7555 objp = multi_get_network_object( signature );
7556 if ( objp == NULL ) {
7557 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7560 if(objp->type != OBJ_SHIP){
7564 // if we're in client firing mode, ignore ones for myself
7565 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7566 if((Player_obj != NULL) && (Player_obj == objp)){
7570 // make it so ship can fire right away!
7571 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7572 if ( objp == Player_obj ){
7573 nprintf(("network", "firing countermeasure from my ship\n"));
7575 ship_launch_countermeasure( objp, rand_val );
7578 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7580 ubyte data[MAX_PACKET_SIZE];
7581 int packet_size = 0;
7586 // only the server should ever be doing this
7587 SDL_assert(MULTIPLAYER_MASTER);
7589 // setup outgoing data
7590 SDL_assert(shooter != NULL);
7591 SDL_assert(turret != NULL);
7592 SDL_assert(target != NULL);
7593 SDL_assert(override != NULL);
7594 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7597 u_beam_info = (ubyte)beam_info_index;
7598 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7599 SDL_assert(subsys_index >= 0);
7600 if(subsys_index < 0){
7604 // swap the beam_info override info into little endian byte order
7605 b_info.dir_a.xyz.x = INTEL_FLOAT(override->dir_a.xyz.x);
7606 b_info.dir_a.xyz.y = INTEL_FLOAT(override->dir_a.xyz.y);
7607 b_info.dir_a.xyz.z = INTEL_FLOAT(override->dir_a.xyz.z);
7609 b_info.dir_b.xyz.x = INTEL_FLOAT(override->dir_b.xyz.x);
7610 b_info.dir_b.xyz.y = INTEL_FLOAT(override->dir_b.xyz.y);
7611 b_info.dir_b.xyz.z = INTEL_FLOAT(override->dir_b.xyz.z);
7613 b_info.delta_ang = INTEL_FLOAT(override->delta_ang);
7614 b_info.shot_count = override->shot_count;
7616 for (int i = 0; i < b_info.shot_count; i++) {
7617 b_info.shot_aim[i] = INTEL_FLOAT(override->shot_aim[i]);
7621 BUILD_HEADER(BEAM_FIRED);
7622 ADD_USHORT(shooter->net_signature);
7623 ADD_DATA(subsys_index);
7624 ADD_USHORT(target->net_signature);
7625 ADD_DATA(u_beam_info);
7626 ADD_DATA(b_info); // FIXME: This is still wrong, we shouldn't be sending an entire struct over the wire - taylor
7628 // send to all clients
7629 multi_io_send_to_all_reliable(data, packet_size);
7632 void process_beam_fired_packet(ubyte *data, header *hinfo)
7635 ushort shooter_sig, target_sig;
7639 beam_fire_info fire_info;
7641 // only clients should ever get this
7642 SDL_assert(MULTIPLAYER_CLIENT);
7644 // read in packet data
7645 offset = HEADER_LENGTH;
7646 GET_USHORT(shooter_sig);
7647 GET_DATA(subsys_index);
7648 GET_USHORT(target_sig);
7649 GET_DATA(u_beam_info);
7654 // swap the beam_info override info into native byte order
7655 b_info.dir_a.xyz.x = INTEL_FLOAT( b_info.dir_a.xyz.x );
7656 b_info.dir_a.xyz.y = INTEL_FLOAT( b_info.dir_a.xyz.y );
7657 b_info.dir_a.xyz.z = INTEL_FLOAT( b_info.dir_a.xyz.z );
7658 b_info.dir_b.xyz.x = INTEL_FLOAT( b_info.dir_b.xyz.x );
7659 b_info.dir_b.xyz.y = INTEL_FLOAT( b_info.dir_b.xyz.y );
7660 b_info.dir_b.xyz.z = INTEL_FLOAT( b_info.dir_b.xyz.z );
7661 b_info.delta_ang = INTEL_FLOAT( b_info.delta_ang );
7663 for (i = 0; i < MAX_BEAM_SHOTS; i++) {
7664 b_info.shot_aim[i] = INTEL_FLOAT(b_info.shot_aim[i]);
7667 // lookup all relevant data
7668 fire_info.beam_info_index = (int)u_beam_info;
7669 fire_info.shooter = NULL;
7670 fire_info.target = NULL;
7671 fire_info.turret = NULL;
7672 fire_info.target_subsys = NULL;
7673 fire_info.beam_info_override = NULL;
7674 fire_info.shooter = multi_get_network_object(shooter_sig);
7675 fire_info.target = multi_get_network_object(target_sig);
7676 fire_info.beam_info_override = &b_info;
7677 fire_info.accuracy = 1.0f;
7678 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)){
7679 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7682 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7683 if(fire_info.turret == NULL){
7684 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7689 beam_fire(&fire_info);
7692 void send_sw_query_packet(ubyte code, char *txt)
7694 ubyte data[MAX_PACKET_SIZE];
7695 int packet_size = 0;
7697 // build the packet and add the code
7698 BUILD_HEADER(SW_STD_QUERY);
7700 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7704 // if I'm the host, send to standalone
7705 if(MULTIPLAYER_HOST){
7706 SDL_assert(!MULTIPLAYER_MASTER);
7707 SDL_assert(code == SW_STD_START);
7708 multi_io_send_reliable(Net_player, data, packet_size);
7710 // otherwise standalone sends back to host
7712 SDL_assert(Game_mode & GM_STANDALONE_SERVER);
7713 SDL_assert(code != SW_STD_START);
7714 SDL_assert(Netgame.host != NULL);
7715 if(Netgame.host != NULL){
7716 multi_io_send_reliable(Netgame.host, data, packet_size);
7721 void process_sw_query_packet(ubyte *data, header *hinfo)
7725 void send_event_update_packet(int event)
7727 ubyte data[MAX_PACKET_SIZE];
7728 ushort u_event = (ushort)event;
7729 int packet_size = 0;
7731 // build the header and add the event
7732 BUILD_HEADER(EVENT_UPDATE);
7733 ADD_USHORT(u_event);
7734 ADD_INT(Mission_events[event].flags);
7735 ADD_INT(Mission_events[event].formula);
7736 ADD_INT(Mission_events[event].result);
7737 ADD_INT(Mission_events[event].count);
7739 // send to all players
7740 multi_io_send_to_all_reliable(data, packet_size);
7743 void process_event_update_packet(ubyte *data, header *hinfo)
7745 int offset = HEADER_LENGTH;
7750 GET_USHORT(u_event);
7751 store_flags = Mission_events[u_event].flags;
7752 GET_INT(Mission_events[u_event].flags);
7753 GET_INT(Mission_events[u_event].formula);
7754 GET_INT(Mission_events[u_event].result);
7755 GET_INT(Mission_events[u_event].count);
7758 // went from non directive special to directive special
7759 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7760 mission_event_set_directive_special(u_event);
7762 // if we went directive special to non directive special
7763 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7764 mission_event_unset_directive_special(u_event);
7768 // weapon detonate packet
7769 void send_weapon_detonate_packet(object *objp)
7771 ubyte data[MAX_PACKET_SIZE];
7772 int packet_size = 0;
7775 SDL_assert(MULTIPLAYER_MASTER);
7776 if(!MULTIPLAYER_MASTER){
7779 SDL_assert(objp != NULL);
7784 // build the header and add the data
7785 BUILD_HEADER(WEAPON_DET);
7786 ADD_USHORT(objp->net_signature);
7788 // send to all players
7789 multi_io_send_to_all(data, packet_size);
7792 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7795 int offset = HEADER_LENGTH;
7796 object *objp = NULL;
7798 // get the weapon signature
7799 GET_USHORT(net_sig);
7802 // lookup the weapon
7803 objp = multi_get_network_object(net_sig);
7804 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7805 weapon_detonate(objp);
7809 // flak fired packet
7810 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7813 ushort pnet_signature;
7814 ubyte data[MAX_PACKET_SIZE], cindex;
7820 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7824 // local setup -- be sure we are actually passing a weapon!!!!
7825 objp = &Objects[weapon_objnum];
7826 SDL_assert ( objp->type == OBJ_WEAPON );
7827 pnet_signature = Objects[ship_objnum].net_signature;
7829 SDL_assert( subsys_index < UCHAR_MAX );
7830 cindex = (ubyte)subsys_index;
7832 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7837 // build the fire turret packet.
7838 BUILD_HEADER(FLAK_FIRED);
7839 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.v.fvec);
7840 ADD_USHORT( pnet_signature );
7842 val = (short)ssp->submodel_info_1.angs.h;
7844 val = (short)ssp->submodel_info_2.angs.p;
7846 ADD_FLOAT( flak_range );
7848 multi_io_send_to_all(data, packet_size);
7850 multi_rate_add(1, "flk", packet_size);
7853 void process_flak_fired_packet(ubyte *data, header *hinfo)
7855 int offset, weapon_objnum, wid;
7856 ushort pnet_signature;
7864 short pitch, heading;
7867 // get the data for the turret fired packet
7868 offset = HEADER_LENGTH;
7869 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7870 GET_USHORT( pnet_signature );
7871 GET_DATA( turret_index );
7872 GET_SHORT( heading );
7874 GET_FLOAT( flak_range );
7875 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7878 objp = multi_get_network_object( pnet_signature );
7879 if ( objp == NULL ) {
7880 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7884 // if this isn't a ship, do nothing
7885 if ( objp->type != OBJ_SHIP ){
7889 // make an orientation matrix from the o_fvec
7890 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7892 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7893 // hack, but should be suitable.
7894 shipp = &Ships[objp->instance];
7895 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7899 wid = ssp->system_info->turret_weapon_type;
7900 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7904 // bash the position and orientation of the turret
7905 ssp->submodel_info_1.angs.h = (float)heading;
7906 ssp->submodel_info_2.angs.p = (float)pitch;
7908 // get the world position of the weapon
7909 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7911 // create the weapon object
7912 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7913 if (weapon_objnum != -1) {
7914 if ( Weapon_info[wid].launch_snd != -1 ) {
7915 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7918 // create a muzzle flash from a flak gun based upon firing position and weapon type
7919 flak_muzzle_flash(&pos, &dir, wid);
7921 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7922 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7926 #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);
7927 #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);
7929 // player pain packet
7930 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7932 ubyte data[MAX_PACKET_SIZE];
7935 int packet_size = 0;
7937 SDL_assert(MULTIPLAYER_MASTER);
7938 if(!MULTIPLAYER_MASTER){
7941 SDL_assert(pl != NULL);
7946 // build the packet and add the code
7947 BUILD_HEADER(NETPLAYER_PAIN);
7948 windex = (ubyte)weapon_info_index;
7950 udamage = (ushort)damage;
7951 ADD_USHORT(udamage);
7952 //ADD_DATA((*force));
7953 add_vector_data( data, &packet_size, *force );
7954 //ADD_DATA((*hitpos));
7955 add_vector_data( data, &packet_size, *hitpos );
7957 // send to the player
7958 multi_io_send(pl, data, packet_size);
7960 multi_rate_add(1, "pai", packet_size);
7963 void process_player_pain_packet(ubyte *data, header *hinfo)
7968 vector force = ZERO_VECTOR;
7969 vector local_hit_pos = ZERO_VECTOR;
7972 // get the data for the pain packet
7973 offset = HEADER_LENGTH;
7975 GET_USHORT(udamage);
7977 get_vector_data( data, &offset, force );
7978 //GET_DATA(local_hit_pos);
7979 get_vector_data( data, &offset, local_hit_pos );
7982 mprintf(("PAIN!\n"));
7984 // get weapon info pointer
7985 //SDL_assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)); // always true
7986 if(! ((windex != 255) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7989 wip = &Weapon_info[windex];
7991 // play the weapon hit sound
7992 SDL_assert(Player_obj != NULL);
7993 if(Player_obj == NULL){
7996 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
7998 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
7999 ship_hit_pain((float)udamage);
8002 ship_apply_whack(&force, &local_hit_pos, Player_obj);
8006 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
8008 ubyte data[MAX_PACKET_SIZE];
8010 int packet_size = 0;
8012 // build the header and add the data
8013 BUILD_HEADER(LIGHTNING_PACKET);
8014 val = (char)bolt_type;
8016 //ADD_DATA((*start));
8017 add_vector_data( data, &packet_size, *start );
8018 //ADD_DATA((*strike));
8019 add_vector_data( data, &packet_size, *strike );
8021 // send to everyone unreliable for now
8022 multi_io_send_to_all(data, packet_size);
8025 void process_lightning_packet(ubyte *data, header *hinfo)
8029 vector start = ZERO_VECTOR, strike = ZERO_VECTOR;
8032 offset = HEADER_LENGTH;
8033 GET_DATA(bolt_type);
8035 get_vector_data(data, &offset, start);
8036 // GET_DATA(strike);
8037 get_vector_data(data, &offset, strike);
8046 nebl_bolt(bolt_type, &start, &strike);
8049 void send_bytes_recvd_packet(net_player *pl)
8051 // only clients should ever be doing this
8056 ubyte data[MAX_PACKET_SIZE];
8057 int packet_size = 0;
8058 BUILD_HEADER(BYTES_SENT);
8059 ADD_INT(pl->cl_bytes_recvd);
8061 // send to the server
8062 multi_io_send_reliable(pl, data, packet_size);
8065 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
8069 net_player *pl = NULL;
8070 int offset = HEADER_LENGTH;
8076 if(Net_player == NULL){
8079 if(!MULTIPLAYER_MASTER){
8083 // make sure we know what player sent this
8084 pid = find_player_id(hinfo->id);
8085 if((pid < 0) || (pid >= MAX_PLAYERS)){
8088 pl = &Net_players[pid];
8091 pl->cl_bytes_recvd = bytes;
8095 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
8098 pl->sv_bytes_sent = 0;
8102 void send_host_captain_change_packet(short player_id, int captain_change)
8104 ubyte data[MAX_PACKET_SIZE];
8105 int packet_size = 0;
8108 BUILD_HEADER(TRANSFER_HOST);
8109 ADD_SHORT(player_id);
8110 ADD_INT(captain_change);
8113 multi_io_send_to_all_reliable(data, packet_size);
8116 void process_host_captain_change_packet(ubyte *data, header *hinfo)
8118 int offset = HEADER_LENGTH;
8119 int idx, found_player, captain_change;
8122 // get the player id
8123 GET_SHORT(player_id);
8124 GET_INT(captain_change);
8130 for(idx=0; idx<MAX_PLAYERS; idx++){
8131 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8132 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
8137 // unflag all old players
8138 for(idx=0; idx<MAX_PLAYERS; idx++){
8139 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
8144 for(idx=0; idx<MAX_PLAYERS; idx++){
8145 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
8146 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
8148 // spew to the HUD config
8149 if(Net_players[idx].player != NULL){
8150 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
8160 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
8165 void send_self_destruct_packet()
8167 ubyte data[MAX_PACKET_SIZE];
8168 int packet_size = 0;
8171 if(Net_player == NULL){
8175 // if i'm the server, I shouldn't be here
8176 SDL_assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8177 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8181 // only if this is valid
8182 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8187 if((Player_ship == NULL) || (Player_obj == NULL)){
8192 BUILD_HEADER(SELF_DESTRUCT);
8193 ADD_USHORT(Player_obj->net_signature);
8195 // send to the server
8196 multi_io_send_reliable(Net_player, data, packet_size);
8199 void process_self_destruct_packet(ubyte *data, header *hinfo)
8201 int offset = HEADER_LENGTH;
8205 // get the net signature
8206 GET_USHORT(net_sig);
8210 np_index = find_player_id(hinfo->id);
8214 if(MULTI_OBSERVER(Net_players[np_index])){
8217 if(Net_players[np_index].player == NULL){
8220 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8223 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8226 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8229 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8234 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);