2 * $Logfile: /Freespace2/code/Network/MultiMsgs.cpp $
7 * C file that holds functions for the building and processing of multiplayer packets
10 * Revision 1.2 2002/05/07 03:16:47 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:10 root
17 * 83 9/14/99 2:21p Dave
18 * Fixed observer mode joining and ingame stuff.
20 * 82 9/14/99 3:26a Dave
21 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
22 * respawn-too-early problem. Made a few crash points safe.
24 * 81 9/13/99 4:52p Dave
27 * 80 9/08/99 10:01p Dave
28 * Make sure game won't run in a drive's root directory. Make sure
29 * standalone routes suqad war messages properly to the host.
31 * 79 8/28/99 4:54p Dave
32 * Fixed directives display for multiplayer clients for wings with
33 * multiple waves. Fixed hud threat indicator rendering color.
35 * 78 8/27/99 12:32a Dave
36 * Allow the user to specify a local port through the launcher.
38 * 77 8/26/99 8:51p Dave
39 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
41 * 76 8/25/99 4:38p Dave
42 * Updated PXO stuff. Make squad war report stuff much more nicely.
44 * 75 8/24/99 1:50a Dave
45 * Fixed client-side afterburner stuttering. Added checkbox for no version
46 * checking on PXO join. Made button info passing more friendly between
49 * 74 8/22/99 5:53p Dave
50 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
51 * instead of ship designations for multiplayer players.
53 * 73 8/22/99 1:55p Dave
54 * Cleaned up host/team-captain leaving code.
56 * 72 8/22/99 1:19p Dave
57 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
58 * which d3d cards are detected.
60 * 71 8/19/99 10:59a Dave
61 * Packet loss detection.
63 * 70 8/17/99 1:12p Dave
64 * Send TvT update when a client has finished joining so he stays nice and
67 * 69 8/16/99 4:05p Dave
68 * Big honking checkin.
70 * 68 8/11/99 5:54p Dave
71 * Fixed collision problem. Fixed standalone ghost problem.
73 * 67 8/06/99 9:46p Dave
74 * Hopefully final changes for the demo.
76 * 66 8/05/99 2:06a Dave
79 * 65 7/30/99 7:01p Dave
80 * Dogfight escort gauge. Fixed up laser rendering in Glide.
82 * 64 7/29/99 5:41p Jefff
83 * Sound hooks for cmeasure success
85 * 63 7/28/99 5:34p Dave
86 * Nailed the missing stats bug to the wall. Problem was optimized build
87 * and using GET_DATA() with array elements. BLECH.
89 * 62 7/26/99 5:50p Dave
90 * Revised ingame join. Better? We'll see....
92 * 61 7/24/99 1:54p Dave
93 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
96 * 60 7/22/99 7:17p Dave
97 * Fixed excessive whacks in multiplayer.
99 * 59 7/08/99 10:53a Dave
100 * New multiplayer interpolation scheme. Not 100% done yet, but still
101 * better than the old way.
103 * 58 7/03/99 5:50p Dave
104 * Make rotated bitmaps draw properly in padlock views.
106 * 57 7/03/99 4:08p Dave
107 * Fixed wss_slots size issues. Fixed potentially nasty bug in low level
110 * 56 6/21/99 7:24p Dave
111 * netplayer pain packet. Added type E unmoving beams.
113 * 55 6/18/99 5:16p Dave
114 * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
115 * dialog to PXO screen.
117 * 54 6/16/99 4:06p Dave
118 * New pilot info popup. Added new draw-bitmap-as-poly function.
120 * 53 6/16/99 10:20a Dave
121 * Added send-message-list sexpression.
123 * 52 6/04/99 3:52p Anoop
124 * Removed bogus assert.
126 * 51 6/01/99 8:35p Dave
127 * Finished lockarm weapons. Added proper supercap weapons/damage. Added
128 * awacs-set-radius sexpression.
130 * 50 5/21/99 5:03p Andsager
131 * Add code to display engine wash death. Modify ship_kill_packet
133 * 49 5/18/99 1:30p Dave
134 * Added muzzle flash table stuff.
136 * 48 5/14/99 1:59p Andsager
137 * Multiplayer message for subsystem cargo revealed.
139 * 47 5/14/99 12:15p Andsager
140 * Add vaporized to kill packet
142 * 46 5/03/99 8:32p Dave
143 * New version of multi host options screen.
145 * 45 4/30/99 12:18p Dave
146 * Several minor bug fixes.
148 * 44 4/29/99 2:29p Dave
149 * Made flak work much better in multiplayer.
151 * 43 4/28/99 11:13p Dave
152 * Temporary checkin of artillery code.
154 * 42 4/16/99 5:54p Dave
155 * Support for on/off style "stream" weapons. Real early support for
156 * target-painting lasers.
158 * 41 4/12/99 2:22p Dave
159 * More checks for dogfight stats.
161 * 40 4/09/99 2:21p Dave
162 * Multiplayer beta stuff. CD checking.
164 * 39 4/02/99 9:55a Dave
165 * Added a few more options in the weapons.tbl for beam weapons. Attempt
166 * at putting "pain" packets into multiplayer.
168 * 38 4/01/99 3:41p Anoop
169 * Removed bogus Int3().
171 * 37 3/19/99 9:51a Dave
172 * Checkin to repair massive source safe crash. Also added support for
173 * pof-style nebulae, and some new weapons code.
175 * 38 3/12/99 2:32p Anoop
176 * Removed bogus asserts.
178 * 37 3/11/99 11:41a Neilk
179 * Don't do multi_io_* operations in single-player
181 * 36 3/10/99 6:50p Dave
182 * Changed the way we buffer packets for all clients. Optimized turret
183 * fired packets. Did some weapon firing optimizations.
185 * 35 3/09/99 6:24p Dave
186 * More work on object update revamping. Identified several sources of
187 * unnecessary bandwidth.
189 * 34 3/08/99 7:03p Dave
190 * First run of new object update system. Looks very promising.
192 * 33 3/04/99 6:09p Dave
193 * Added in sexpressions for firing beams and checking for if a ship is
196 * 32 3/01/99 10:00a Dave
197 * Fxied several dogfight related stats bugs.
199 * 31 2/24/99 2:25p Dave
200 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
201 * bug for dogfight more.
203 * 30 2/23/99 2:29p Dave
204 * First run of oldschool dogfight mode.
206 * 29 2/21/99 6:01p Dave
207 * Fixed standalone WSS packets.
209 * 28 2/21/99 1:48p Dave
210 * Some code for monitoring datarate for multiplayer in detail.
212 * 27 2/17/99 2:11p Dave
213 * First full run of squad war. All freespace and tracker side stuff
216 * 26 2/12/99 6:16p Dave
217 * Pre-mission Squad War code is 95% done.
219 * 25 2/11/99 3:08p Dave
220 * PXO refresh button. Very preliminary squad war support.
222 * 24 1/29/99 5:07p Dave
223 * Fixed multiplayer stuff. Put in multiplayer support for rapid fire
226 * 23 1/27/99 9:56a Dave
227 * Temporary checkin of beam weapons for Dan to make cool sounds.
229 * 22 1/26/99 6:33p Anoop
230 * Fixed multiplayer slot switching problem (be sure to remember that
231 * hinfo->id is player id# _not_ player index #)
233 * 21 1/24/99 11:37p Dave
234 * First full rev of beam weapons. Very customizable. Removed some bogus
235 * Int3()'s in low level net code.
237 * 20 1/15/99 4:37p Dave
238 * Potential fix for weapon pair problem.
240 * 19 1/14/99 6:06p Dave
241 * 100% full squad logo support for single player and multiplayer.
243 * 18 1/14/99 12:48a Dave
244 * Todo list bug fixes. Made a pass at putting briefing icons back into
245 * FRED. Sort of works :(
247 * 17 1/12/99 5:45p Dave
248 * Moved weapon pipeline in multiplayer to almost exclusively client side.
249 * Very good results. Bandwidth goes down, playability goes up for crappy
250 * connections. Fixed object update problem for ship subsystems.
252 * 16 1/08/99 4:56p Anoop
253 * Fixed a problem with wss request packets.
255 * 15 12/18/98 12:24p Markm
256 * Fixed a dumb bug where player image_filenames were not being passed
257 * properly in new players packet.
259 * 14 12/14/98 12:13p Dave
260 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
263 * 13 11/30/98 1:07p Dave
264 * 16 bit conversion, first run.
266 * 12 11/20/98 4:08p Dave
267 * Fixed flak effect in multiplayer.
269 * 11 11/19/98 4:19p Dave
270 * Put IPX sockets back in psnet. Consolidated all multiplayer config
273 * 10 11/19/98 8:04a Dave
274 * Full support for D3-style reliable sockets. Revamped packet lag/loss
275 * system, made it receiver side and at the lowest possible level.
277 * 9 11/17/98 11:12a Dave
278 * Removed player identification by address. Now assign explicit id #'s.
280 * 8 11/12/98 11:50a Dave
281 * Multiplayer clients set flak range to be very long.
283 * 7 11/12/98 12:13a Dave
284 * Tidied code up for multiplayer test. Put in network support for flak
287 * 6 11/05/98 5:55p Dave
288 * Big pass at reducing #includes
290 * 5 10/20/98 1:39p Andsager
291 * Make so sparks follow animated ship submodels. Modify
292 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
293 * submodel_num. Add submodel_num to multiplayer hit packet.
295 * 4 10/13/98 9:29a Dave
296 * Started neatening up freespace.h. Many variables renamed and
297 * reorganized. Added AlphaColors.[h,cpp]
299 * 3 10/07/98 6:27p Dave
300 * Globalized mission and campaign file extensions. Removed Silent Threat
301 * special code. Moved \cache \players and \multidata into the \data
304 * 2 10/07/98 10:53a Dave
307 * 1 10/07/98 10:50a Dave
309 * 506 10/02/98 3:22p Allender
310 * fix up the -connect option and fix the -port option
312 * 505 10/02/98 11:45a Dave
313 * Fixed stupid chat message bug.
315 * 504 9/29/98 1:33p Dave
316 * Remove standalone only conditional compiles for pre 1.04 stuff.
318 * 503 9/28/98 1:54p Dave
319 * Make sure French and German don't xfer builtin files they don't have
322 * 502 9/20/98 7:19p Dave
323 * Added CHANGE_IFF packet.
325 * 501 9/17/98 3:08p Dave
326 * PXO to non-pxo game warning popup. Player icon stuff in create and join
327 * game screens. Upped server count refresh time in PXO to 35 secs (from
335 #include <io.h> // for findfirst/findnext, etc
337 #include "multimsgs.h"
338 #include "multiutil.h"
341 #include "multiteamselect.h"
342 #include "linklist.h"
343 #include "gamesequence.h"
344 #include "hudmessage.h"
345 #include "hudsquadmsg.h"
346 #include "freespace.h"
350 #include "missiongoals.h"
351 #include "missionparse.h"
352 #include "missionlog.h"
353 #include "missionmessage.h"
354 #include "missionbrief.h"
356 #include "cmeasure.h"
357 #include "model.h" // for some limits
358 #include "afterburner.h"
359 #include "stand_gui.h"
360 #include "multi_xfer.h"
366 #include "managepilot.h"
367 #include "hudsquadmsg.h"
369 #include "missionweaponchoice.h"
370 #include "missionshipchoice.h"
371 #include "fireballs.h"
374 #include "multi_ingame.h"
375 #include "multiteamselect.h"
377 #include "multi_campaign.h"
378 #include "multi_team.h"
379 #include "multi_respawn.h"
380 #include "multi_observer.h"
381 #include "multi_voice.h"
382 #include "asteroid.h"
383 #include "multi_pmsg.h"
384 #include "multi_data.h"
385 #include "multi_options.h"
386 #include "objcollide.h"
387 #include "hudreticle.h"
388 #include "multi_pause.h"
389 #include "multi_endgame.h"
390 #include "missiondebrief.h"
391 #include "multi_obj.h"
392 #include "multi_log.h"
394 #include "multi_kick.h"
398 #include "multi_rate.h"
399 #include "neblightning.h"
400 #include "hudescort.h"
402 // #define _MULTI_SUPER_WACKY_COMPRESSION
404 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
406 #define MAX_CODE ( ( 1 << BITS ) - 1 )
407 #define TABLE_SIZE 35023L
408 #define END_OF_STREAM 256
409 #define BUMP_CODE 257
410 #define FLUSH_CODE 258
411 #define FIRST_CODE 259
420 static DICTIONARY dict[TABLE_SIZE];
421 static char decode_stack[TABLE_SIZE];
422 static uint next_code;
423 static int current_code_bits;
424 static uint next_bump_code;
426 typedef struct BitBuf {
432 void output_bits( BitBuf *bitbuf, uint code, int count )
436 mask = 1L << ( count - 1 );
439 bitbuf->rack |= bitbuf->mask;
441 if ( bitbuf->mask == 0 ) {
442 *bitbuf->data++=(ubyte)bitbuf->rack;
450 uint input_bits( BitBuf *bitbuf, int bit_count )
455 mask = 1L << ( bit_count - 1 );
458 if ( bitbuf->mask == 0x80 ) {
459 bitbuf->rack = *bitbuf->data++;
460 if ( bitbuf->rack == EOF )
461 return END_OF_STREAM;
463 if ( bitbuf->rack & bitbuf->mask )
464 return_value |= mask;
467 if ( bitbuf->mask == 0 )
470 return( return_value );
474 static void InitializeDictionary()
478 for ( i = 0 ; i < TABLE_SIZE ; i++ )
479 dict[i].code_value = UNUSED;
481 next_code = FIRST_CODE;
482 current_code_bits = 9;
483 next_bump_code = 511;
487 static uint find_child_node( int parent_code, int child_character )
492 index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
496 offset = TABLE_SIZE - index;
498 if ( dict[ index ].code_value == UNUSED )
499 return( (uint) index );
500 if ( dict[ index ].parent_code == parent_code &&
501 dict[ index ].character == (char) child_character )
503 if ( (int) index >= offset )
506 index += TABLE_SIZE - offset;
511 static uint decode_string( uint count, uint code )
513 while ( code > 255 ) {
514 decode_stack[ count++ ] = dict[ code ].character;
515 code = dict[ code ].parent_code;
517 decode_stack[ count++ ] = (char) code;
521 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size )
529 // Init output bit buffer
532 output.data = outputbuf;
534 InitializeDictionary();
536 string_code = *inputbuf++;
538 for ( i=1 ; i<input_size ; i++ ) {
539 character = *inputbuf++;
540 index = find_child_node( string_code, character );
541 if ( dict[ index ].code_value != - 1 )
542 string_code = dict[ index ].code_value;
544 dict[ index ].code_value = next_code++;
545 dict[ index ].parent_code = string_code;
546 dict[ index ].character = (char) character;
547 output_bits( &output, (unsigned long) string_code, current_code_bits );
548 string_code = character;
549 if ( next_code > MAX_CODE ) {
550 output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
551 InitializeDictionary();
552 } else if ( next_code > next_bump_code ) {
553 output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
555 next_bump_code <<= 1;
560 output_bits( &output, (unsigned long) string_code, current_code_bits );
561 output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
563 if ( output.mask != 0x80 )
564 *output.data++ = (ubyte)output.rack;
566 return output.data-outputbuf;
570 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf )
581 input.data = inputbuf;
585 InitializeDictionary();
586 old_code = (uint) input_bits( &input, current_code_bits );
587 if ( old_code == END_OF_STREAM )
589 character = old_code;
590 outputbuf[counter++] = ( ubyte )old_code;
592 new_code = (uint) input_bits( &input, current_code_bits );
593 if ( new_code == END_OF_STREAM )
595 if ( new_code == FLUSH_CODE )
597 if ( new_code == BUMP_CODE ) {
601 if ( new_code >= next_code ) {
602 decode_stack[ 0 ] = (char) character;
603 count = decode_string( 1, old_code );
605 count = decode_string( 0, new_code );
607 character = decode_stack[ count - 1 ];
609 outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
610 dict[ next_code ].parent_code = old_code;
611 dict[ next_code ].character = (char) character;
619 // send the specified data packet to all players
620 void multi_io_send(net_player *pl, ubyte *data, int len)
623 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
627 // don't do it for single player
628 if(!(Game_mode & GM_MULTIPLAYER)){
633 if(MULTIPLAYER_CLIENT){
634 // Assert(pl == Net_player);
635 if(pl != Net_player){
639 // Assert(pl != Net_player);
640 if(pl == Net_player){
645 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
646 if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
647 multi_io_send_force(pl);
648 pl->s_info.unreliable_buffer_size = 0;
651 Assert((pl->s_info.unreliable_buffer_size + len) <= MAX_PACKET_SIZE);
653 memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
654 pl->s_info.unreliable_buffer_size += len;
657 void multi_io_send_to_all(ubyte *data, int length, net_player *ignore)
660 Assert(MULTIPLAYER_MASTER);
662 // need to check for i > 1, hmmm... and connected. I don't know.
663 for (i = 0; i < MAX_PLAYERS; i++ ) {
664 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
668 // maybe ignore a player
669 if((ignore != NULL) && (&Net_players[i] == ignore)){
673 // ingame joiners not waiting to select a ship doesn't get any packets
674 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
679 multi_io_send(&Net_players[i], data, length);
683 void multi_io_send_force(net_player *pl)
686 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
690 // don't do it for single player
691 if(!(Game_mode & GM_MULTIPLAYER)){
695 // send everything in
696 if (MULTIPLAYER_MASTER) {
697 psnet_send(&pl->p_info.addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
699 // add the bytes sent to this player
700 pl->sv_bytes_sent += pl->s_info.unreliable_buffer_size;
702 psnet_send(&Netgame.server_addr, pl->s_info.unreliable_buffer, pl->s_info.unreliable_buffer_size, NET_PLAYER_NUM(pl));
704 pl->s_info.unreliable_buffer_size = 0;
707 // send the data packet to all players via their reliable sockets
708 void multi_io_send_reliable(net_player *pl, ubyte *data, int len)
711 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
715 // don't do it for single player
716 if(!(Game_mode & GM_MULTIPLAYER)){
721 if(MULTIPLAYER_CLIENT){
722 // Assert(pl == Net_player);
723 if(pl != Net_player){
727 // Assert(pl != Net_player);
728 if(pl == Net_player){
733 // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
734 if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
735 multi_io_send_reliable_force(pl);
736 pl->s_info.reliable_buffer_size = 0;
739 Assert((pl->s_info.reliable_buffer_size + len) <= MAX_PACKET_SIZE);
741 memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
742 pl->s_info.reliable_buffer_size += len;
745 void multi_io_send_to_all_reliable(ubyte* data, int length, net_player *ignore)
748 Assert(MULTIPLAYER_MASTER);
750 // need to check for i > 1, hmmm... and connected. I don't know.
751 for (i = 0; i < MAX_PLAYERS; i++ ) {
752 if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
756 // maybe ignore a player
757 if((ignore != NULL) && (&Net_players[i] == ignore)){
761 // ingame joiners not waiting to select a ship doesn't get any packets
762 if ( (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN) && !(Net_players[i].flags & INGAME_JOIN_FLAG_PICK_SHIP) ){
767 multi_io_send_reliable(&Net_players[i], data, length);
771 void multi_io_send_reliable_force(net_player *pl)
774 if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
778 // don't do it for single player
779 if(!(Game_mode & GM_MULTIPLAYER)){
783 // send everything in
784 if(MULTIPLAYER_MASTER) {
785 psnet_rel_send(pl->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
786 } else if(Net_player != NULL){
787 psnet_rel_send(Net_player->reliable_socket, pl->s_info.reliable_buffer, pl->s_info.reliable_buffer_size, NET_PLAYER_NUM(pl));
789 pl->s_info.reliable_buffer_size = 0;
792 // send all buffered packets
793 void multi_io_send_buffered_packets()
797 // don't do it for single player
798 if(!(Game_mode & GM_MULTIPLAYER)){
803 if(MULTIPLAYER_MASTER){
804 for(idx=0; idx<MAX_PLAYERS; idx++){
805 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
806 // force unreliable data
807 if(Net_players[idx].s_info.unreliable_buffer_size > 0){
808 multi_io_send_force(&Net_players[idx]);
809 Net_players[idx].s_info.unreliable_buffer_size = 0;
812 // force reliable data
813 if(Net_players[idx].s_info.reliable_buffer_size > 0){
814 multi_io_send_reliable_force(&Net_players[idx]);
815 Net_players[idx].s_info.reliable_buffer_size = 0;
821 else if(Net_player != NULL){
822 // force unreliable data
823 if(Net_player->s_info.unreliable_buffer_size > 0){
824 multi_io_send_force(Net_player);
825 Net_player->s_info.unreliable_buffer_size = 0;
828 // force reliable data
829 if(Net_player->s_info.reliable_buffer_size > 0){
830 multi_io_send_reliable_force(Net_player);
831 Net_player->s_info.reliable_buffer_size = 0;
836 // 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)
837 void send_game_chat_packet(net_player *from, char *msg, int msg_mode, net_player *to, char *expr, int server_msg)
839 ubyte data[MAX_PACKET_SIZE],mode;
842 BUILD_HEADER(GAME_CHAT);
845 ADD_DATA(from->player_id);
847 // add the message mode and if in MSG_TARGET mode, add who the target is
848 ADD_DATA(server_msg);
849 mode = (ubyte)msg_mode;
852 case MULTI_MSG_TARGET:
854 ADD_DATA(to->player_id);
857 Assert(expr != NULL);
861 // add the message itself
864 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
866 // message all players
868 for(idx=0;idx<MAX_PLAYERS;idx++){
869 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
870 multi_io_send_reliable(&Net_players[idx], data, packet_size);
875 // message only friendly players
876 case MULTI_MSG_FRIENDLY:
877 for(idx=0;idx<MAX_PLAYERS;idx++){
878 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)){
879 multi_io_send_reliable(&Net_players[idx], data, packet_size);
884 // message only hostile players
885 case MULTI_MSG_HOSTILE:
886 for(idx=0;idx<MAX_PLAYERS;idx++){
887 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)){
888 multi_io_send_reliable(&Net_players[idx], data, packet_size);
893 // message the player's target
894 case MULTI_MSG_TARGET:
896 if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
897 multi_io_send_reliable(to, data, packet_size);
901 // message all players who match the expression string
903 Assert(expr != NULL);
904 for(idx=0;idx<MAX_PLAYERS;idx++){
905 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
906 multi_io_send_reliable(&Net_players[idx], data, packet_size);
912 // send to the server, who will take care of routing it
914 multi_io_send_reliable(Net_player, data, packet_size);
918 // process a general game chat packet, if we're the standalone we should rebroadcast
919 void process_game_chat_packet( ubyte *data, header *hinfo )
923 int color_index,player_index,to_player_index,should_display,server_msg;
924 char msg[MULTI_MSG_MAX_TEXT_LEN+CALLSIGN_LEN+2];
928 offset = HEADER_LENGTH;
930 // get the id of the sender
933 // determine if this is a server message
934 GET_DATA(server_msg);
939 // if targeting a specific player, get the address
942 case MULTI_MSG_TARGET:
949 // get the message itself
953 // get the index of the sending player
954 color_index = find_player_id(from);
955 player_index = color_index;
957 // if we couldn't find the player - bail
958 if(player_index == -1){
959 nprintf(("Network","Could not find player for processing game chat packet!\n"));
965 // if we're the server, determine what to do with the packet here
966 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
967 // if he's targeting a specific player, find out who it is
968 if(mode == MULTI_MSG_TARGET){
969 to_player_index = find_player_id(to);
971 to_player_index = -1;
974 // if we couldn't find who sent the message or who should be getting the message, the bail
975 if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
979 // determine if _I_ should be seeing the text
980 if(Game_mode & GM_STANDALONE_SERVER){
983 // check against myself for several specific cases
985 if((mode == MULTI_MSG_ALL) ||
986 ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
987 ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
988 ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
989 ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
994 // if we're the server of a game, we need to rebroadcast to all other players
996 // individual target mission
997 case MULTI_MSG_TARGET:
998 // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
999 if(to_player_index != MY_NET_PLAYER_NUM){
1000 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
1004 case MULTI_MSG_EXPR:
1005 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
1009 send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
1013 // if a client receives this packet, its always ok for him to display it
1018 // if we're not on a standalone
1020 if(server_msg == 2){
1023 multi_display_chat_msg(msg, player_index, !server_msg);
1028 // broadcast a hud message to all players
1029 void send_hud_msg_to_all( char* msg )
1031 ubyte data[MAX_PACKET_SIZE];
1034 // only the server should be sending this packet
1035 BUILD_HEADER(HUD_MSG);
1039 multi_io_send_to_all( data, packet_size );
1042 // process an incoming hud message packet
1043 void process_hud_message(ubyte* data, header* hinfo)
1046 char msg_buffer[255];
1048 offset = HEADER_LENGTH;
1050 GET_STRING(msg_buffer);
1053 // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
1054 if(Game_mode & GM_IN_MISSION){
1055 HUD_printf(msg_buffer);
1059 // send a join packet request to the specified address (should be a server)
1060 void send_join_packet(net_addr* addr,join_request *jr)
1062 ubyte data[MAX_PACKET_SIZE];
1065 // build the header and add the request
1069 psnet_send(addr, data, packet_size);
1072 // process an incoming join request packet
1073 void process_join_packet(ubyte* data, header* hinfo)
1078 int host_restr_mode;
1079 // int team0_avail,team1_avail;
1080 char join_string[255];
1083 // only the server of the game should ever receive this packet
1084 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) )
1087 offset = HEADER_LENGTH;
1089 // read in the request info
1090 memset(&jr,0,sizeof(join_request));
1096 // fill in the address information of where this came from
1097 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
1099 // determine if we should accept this guy, or return a reason we should reject him
1100 // see the DENY_* codes in multi.h
1101 ret_code = multi_eval_join_request(&jr,&addr);
1103 // evaluate the return code
1105 // he should be accepted
1109 // we have to query the host because this is a restricted game
1110 case JOIN_QUERY_RESTRICTED :
1111 if(!(Game_mode & GM_STANDALONE_SERVER)){
1112 // notify the host of the event
1113 snd_play(&Snds[SND_CUE_VOICE]);
1116 // set the query timestamp
1117 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
1118 Netgame.flags |= NG_FLAG_INGAME_JOINING;
1120 // determine what mode we're in
1121 host_restr_mode = -1;
1122 memset(join_string,0,255);
1123 // if(Netgame.type == NG_TYPE_TEAM){
1124 // multi_player_ships_available(&team0_avail,&team1_avail);
1126 // if(team0_avail && team1_avail){
1127 // host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
1128 // sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
1129 // } else if(team0_avail && !team1_avail){
1130 // host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
1131 // sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
1132 // } else if(!team0_avail && team1_avail){
1133 // host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
1134 // sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
1136 // } else if(Netgame.mode == NG_MODE_RESTRICTED){
1137 host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
1138 sprintf(join_string,XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
1140 Assert(host_restr_mode != -1);
1142 // store the request info
1143 memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
1144 memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
1145 Multi_join_restr_mode = host_restr_mode;
1147 // if i'm the standalone server, I need to send a query to the host
1148 if(Game_mode & GM_STANDALONE_SERVER){
1149 send_host_restr_packet(jr.callsign,0,Multi_join_restr_mode);
1151 HUD_printf(join_string);
1155 ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
1159 // he'e being denied for some reason
1161 // send him the reason he is being denied
1162 send_deny_packet(&addr,ret_code);
1166 // process the rest of the request
1167 multi_process_valid_join_request(&jr,&addr);
1170 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1171 void send_new_player_packet(int new_player_num,net_player *target)
1173 ubyte data[MAX_PACKET_SIZE], val;
1174 int packet_size = 0;
1176 BUILD_HEADER( NOTIFY_NEW_PLAYER );
1178 // add the new player's info
1179 ADD_DATA(new_player_num);
1180 ADD_DATA(Net_players[new_player_num].p_info.addr);
1181 ADD_DATA(Net_players[new_player_num].player_id);
1182 ADD_DATA(Net_players[new_player_num].flags);
1183 ADD_STRING(Net_players[new_player_num].player->callsign);
1184 ADD_STRING(Net_players[new_player_num].player->image_filename);
1185 ADD_STRING(Net_players[new_player_num].player->squad_filename);
1186 ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1188 val = (ubyte)Net_players[new_player_num].p_info.team;
1191 // broadcast the data
1193 multi_io_send_reliable(target, data, packet_size);
1195 multi_io_send_to_all_reliable(data, packet_size);
1199 // process a notification for a new player who has joined the game
1200 void process_new_player_packet(ubyte* data, header* hinfo)
1202 int already_in_game = 0;
1203 int offset, new_player_num,player_num,new_flags;
1205 char new_player_name[CALLSIGN_LEN+2] = "";
1206 char new_player_image[MAX_FILENAME_LEN+1] = "";
1207 char new_player_squad[MAX_FILENAME_LEN+1] = "";
1208 char new_player_pxo_squad[LOGIN_LEN+1] = "";
1209 char notify_string[256];
1213 offset = HEADER_LENGTH;
1215 // get the new players information
1216 GET_DATA(new_player_num);
1219 GET_DATA(new_flags);
1220 GET_STRING(new_player_name);
1221 GET_STRING(new_player_image);
1222 GET_STRING(new_player_squad);
1223 GET_STRING(new_player_pxo_squad);
1227 player_num = multi_find_open_player_slot();
1228 Assert(player_num != -1);
1230 // note that this new code does not check for duplicate IPs. It merely checks to see if
1231 // the slot referenced by new_player_num is already occupied by a connected player
1232 if(MULTI_CONNECTED(Net_players[new_player_num])){
1236 // if he's not alreayd in the game for one reason or another
1237 if ( !already_in_game ) {
1238 if ( Game_mode & GM_IN_MISSION ){
1239 HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1242 // create the player
1243 memcpy(new_addr.net_id, Psnet_my_addr.net_id, 4);
1245 if(new_flags & NETINFO_FLAG_OBSERVER){
1246 multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1247 Net_players[new_player_num].flags |= new_flags;
1249 multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1250 Net_players[new_player_num].flags |= new_flags;
1253 // copy in the filename
1254 if(strlen(new_player_image) > 0){
1255 strcpy(Net_players[new_player_num].player->image_filename, new_player_image);
1257 strcpy(Net_players[new_player_num].player->image_filename, "");
1259 // copy his pilot squad filename
1260 Net_players[new_player_num].player->insignia_texture = -1;
1261 player_set_squad_bitmap(Net_players[new_player_num].player, new_player_squad);
1263 // copy in his pxo squad name
1264 strcpy(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad);
1266 // since we just created the player, set the last_heard_time here.
1267 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1269 Net_players[new_player_num].p_info.team = team;
1271 Net_players[new_player_num].player_id = new_id;
1273 // zero out this players ping
1274 multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1276 // add a chat message
1277 if(Net_players[new_player_num].player->callsign != NULL){
1278 sprintf(notify_string,XSTR("<%s has joined>",717),Net_players[new_player_num].player->callsign);
1279 multi_display_chat_msg(notify_string,0,0);
1284 ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].player->callsign);
1286 // let the current ui screen know someone joined
1287 switch(gameseq_get_state()){
1288 case GS_STATE_MULTI_HOST_SETUP :
1289 multi_create_handle_join(&Net_players[new_player_num]);
1291 case GS_STATE_MULTI_CLIENT_SETUP :
1292 multi_jw_handle_join(&Net_players[new_player_num]);
1297 #define PLAYER_DATA_SLOP 100
1299 void send_accept_player_data( net_player *npp, int is_ingame )
1303 ubyte data[MAX_PACKET_SIZE], stop;
1305 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1307 // add in the netplayer data for all players
1309 for (i=0; i<MAX_PLAYERS; i++) {
1310 // skip non connected players
1311 if ( !MULTI_CONNECTED(Net_players[i]) ){
1315 // skip this new player's entry
1316 if ( npp->player_id == Net_players[i].player_id ){
1320 // add the stop byte
1323 // add the player's number
1326 // add the player's address
1327 ADD_DATA(Net_players[i].p_info.addr);
1330 ADD_DATA(Net_players[i].player_id);
1333 ADD_STRING(Net_players[i].player->callsign);
1335 // add his image filename
1336 ADD_STRING(Net_players[i].player->image_filename);
1338 // add his squad filename
1339 ADD_STRING(Net_players[i].player->squad_filename);
1341 // add his PXO squad name
1342 ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1345 ADD_DATA(Net_players[i].flags);
1347 // add his object's net sig
1349 ADD_DATA( Objects[Net_players[i].player->objnum].net_signature );
1352 if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1353 stop = APD_END_PACKET;
1355 multi_io_send_reliable( npp, data, packet_size );
1356 BUILD_HEADER(ACCEPT_PLAYER_DATA);
1362 // add the stop byte
1363 stop = APD_END_DATA;
1365 multi_io_send_reliable(npp, data, packet_size);
1368 // send an accept packet to a client in response to a request to join the game
1369 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1372 ubyte data[MAX_PACKET_SIZE],val;
1373 char notify_string[256];
1376 Assert(new_player_num >= 0);
1378 // setup his "reliable" socket
1379 Net_players[new_player_num].last_heard_time = timer_get_fixed_seconds();
1381 // build the packet header
1383 BUILD_HEADER(ACCEPT);
1385 // add the accept code
1388 // add code specific accept data
1389 if (code & ACCEPT_INGAME) {
1390 // the game filename
1391 ADD_STRING(Game_current_mission_filename);
1393 // if he is joining on a specific team, mark it here
1394 if(ingame_join_team != -1){
1397 val = (ubyte)ingame_join_team;
1405 if (code & ACCEPT_OBSERVER) {
1406 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1409 if (code & ACCEPT_HOST) {
1410 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1413 if (code & ACCEPT_CLIENT) {
1414 Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1417 // add the current skill level setting on the host
1418 ADD_DATA(Game_skill_level);
1420 // add this guys player num
1421 ADD_DATA(new_player_num);
1423 // add his player id
1424 ADD_DATA(Net_players[new_player_num].player_id);
1426 // add netgame type flags
1427 ADD_DATA(Netgame.type_flags);
1430 // char buffer[100];
1431 // nprintf(("Network", "About to send accept packet to %s on port %d\n", get_text_address(buffer, addr->addr), addr->port ));
1434 // actually send the packet
1435 psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1437 // if he's not an observer, inform all the other players in the game about him
1438 // inform the other players in the game about this new player
1439 for (i=0; i<MAX_PLAYERS; i++) {
1440 // skip unconnected players as well as this new guy himself
1441 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])) {
1445 // send the new packet
1446 send_new_player_packet(new_player_num,&Net_players[i]);
1449 // add a chat message
1450 if(Net_players[new_player_num].player->callsign != NULL){
1451 sprintf(notify_string,XSTR("<%s has joined>",717), Net_players[new_player_num].player->callsign);
1452 multi_display_chat_msg(notify_string, 0, 0);
1455 // handle any team vs. team details
1456 if (!(code & ACCEPT_OBSERVER)) {
1457 multi_team_handle_join(&Net_players[new_player_num]);
1461 if(Net_players[new_player_num].tracker_player_id >= 0){
1462 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);
1464 ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].player->callsign);
1469 // process the player data from the server
1470 void process_accept_player_data( ubyte *data, header *hinfo )
1472 int offset, player_num, player_slot_num, new_flags;
1473 char name[CALLSIGN_LEN + 1] = "";
1474 char image_name[MAX_FILENAME_LEN + 1] = "";
1475 char squad_name[MAX_FILENAME_LEN + 1] = "";
1476 char pxo_squad_name[LOGIN_LEN+1] = "";
1480 ushort ig_signature;
1482 offset = HEADER_LENGTH;
1485 while ( stop == APD_NEXT ) {
1486 player_slot_num = multi_find_open_player_slot();
1487 Assert(player_slot_num != -1);
1489 // get the player's number
1490 GET_DATA(player_num);
1492 // add the player's address
1495 // get the player's id#
1496 GET_DATA(player_id);
1501 // add his image filename
1502 GET_STRING(image_name);
1504 // get his squad logo filename
1505 GET_STRING(squad_name);
1507 // get his PXO squad name
1508 GET_STRING(pxo_squad_name);
1511 GET_DATA(new_flags);
1513 if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1514 if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1519 // the error handling here is less than stellar. We should probably put up a popup and go
1520 // back to the main menu. But then again, this should never ever happen!
1521 if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1526 // copy his image filename
1527 strcpy(Net_players[player_num].player->image_filename, image_name);
1529 // copy his pilot squad filename
1530 Net_players[player_num].player->insignia_texture = -1;
1531 player_set_squad_bitmap(Net_players[player_num].player, squad_name);
1533 // copy his pxo squad name
1534 strcpy(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name);
1536 // set his player id#
1537 Net_players[player_num].player_id = player_id;
1539 // mark him as being connected
1540 Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1541 Net_players[player_num].flags |= new_flags;
1543 // set the server pointer
1544 if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1545 Netgame.server = &Net_players[player_num];
1546 Netgame.server->last_heard_time = timer_get_fixed_seconds();
1548 // also - always set the server address to be where this data came from, NOT from
1549 // the data in the packet
1550 fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->net_id, hinfo->port);
1553 // set the host pointer
1554 if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1555 Netgame.host = &Net_players[player_num];
1558 // read in the player's object net signature and store as his objnum for now
1559 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME ) {
1560 GET_DATA( ig_signature );
1561 Net_players[player_num].player->objnum = ig_signature;
1564 // get the stop byte
1569 if ( stop == APD_END_DATA ) {
1570 // if joining a game automatically, set the connect address to NULl so we don't try and
1571 // do this next time we enter a game
1572 if (Cmdline_connect_addr != NULL) {
1573 Cmdline_connect_addr = NULL;
1576 // send my stats to the server if I'm not in observer mode
1577 if (!(Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER)) {
1578 send_player_stats_block_packet(Net_player, STATS_ALLTIME);
1581 // if i'm being accepted as a host, then move into the host setup state
1582 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_HOST) {
1583 // set my permission bits
1584 Net_player->flags |= NETINFO_FLAG_GAME_HOST;
1585 Net_player->state = NETPLAYER_STATE_STD_HOST_SETUP;
1587 gameseq_post_event(GS_EVENT_MULTI_START_GAME);
1590 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_OBSERVER) {
1591 Net_player->flags |= NETINFO_FLAG_OBSERVER;
1593 // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1594 if ( !(Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) ) {
1595 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1599 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_CLIENT) {
1600 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
1603 if ( Net_player->flags & NETINFO_FLAG_ACCEPT_INGAME) {
1604 // flag myself as being an ingame joiner
1605 Net_player->flags |= NETINFO_FLAG_INGAME_JOIN;
1607 // move myself into the ingame join mission sync state
1608 Multi_sync_mode = MULTI_SYNC_INGAME;
1609 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
1612 // update my options on the server
1613 multi_options_update_local();
1615 // if we're in PXO mode, mark it down in our player struct
1616 if(MULTI_IS_TRACKER_GAME){
1617 Player->flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1618 Player->save_flags |= PLAYER_FLAGS_HAS_PLAYED_PXO;
1623 // process an accept packet from the server
1624 extern int Select_default_ship;
1626 void process_accept_packet(ubyte* data, header* hinfo)
1628 int code, my_player_num, offset;
1632 // get the accept code
1633 offset = HEADER_LENGTH;
1637 // read in the accept code specific data
1639 if (code & ACCEPT_INGAME) {
1640 // the game filename
1641 GET_STRING(Game_current_mission_filename);
1642 Select_default_ship = 0;
1644 // determine if I'm being placed on a team
1651 if (code & ACCEPT_OBSERVER) {
1652 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1655 if (code & ACCEPT_HOST) {
1656 Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1659 if (code & ACCEPT_CLIENT) {
1660 Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1663 // fill in the netgame server address
1664 fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->net_id, hinfo->port );
1666 // get the skill level setting
1667 GET_DATA(Game_skill_level);
1669 // get my netplayer number
1670 GET_DATA(my_player_num);
1673 GET_DATA(player_id);
1675 // get netgame type flags
1676 GET_DATA(Netgame.type_flags);
1678 // setup the Net_players structure for myself first
1679 Net_player = &Net_players[my_player_num];
1680 Net_player->flags = 0;
1681 Net_player->tracker_player_id = Multi_tracker_id;
1682 Net_player->player_id = player_id;
1683 Net_player->s_info.xfer_handle = -1;
1684 // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1685 stuff_netplayer_info( Net_player, &Psnet_my_addr, 0, Player );
1686 multi_options_local_load(&Net_player->p_info.options, Net_player);
1688 Net_player->p_info.team = team;
1691 // determine if I have a CD
1693 Net_player->flags |= NETINFO_FLAG_HAS_CD;
1696 // set accept code in netplayer for this guy
1697 if ( code & ACCEPT_INGAME ){
1698 Net_player->flags |= NETINFO_FLAG_ACCEPT_INGAME;
1700 if ( code & ACCEPT_OBSERVER ){
1701 Net_player->flags |= NETINFO_FLAG_ACCEPT_OBSERVER;
1703 if ( code & ACCEPT_HOST ){
1704 Net_player->flags |= NETINFO_FLAG_ACCEPT_HOST;
1706 if ( code & ACCEPT_CLIENT ){
1707 Net_player->flags |= NETINFO_FLAG_ACCEPT_CLIENT;
1710 // if I have hacked data
1711 if(game_hacked_data()){
1712 Net_player->flags |= NETINFO_FLAG_HAXOR;
1715 // if we're supposed to flush our local data cache, do so now
1716 if(Net_player->p_info.options.flags & MLO_FLAG_FLUSH_CACHE){
1717 multi_flush_multidata_cache();
1720 Net_player->sv_bytes_sent = 0;
1721 Net_player->sv_last_pl = -1;
1722 Net_player->cl_bytes_recvd = 0;
1723 Net_player->cl_last_pl = -1;
1725 // intiialize endgame stuff
1726 multi_endgame_init();
1730 // make a call to psnet to initialize and try to connect with the server.
1731 psnet_rel_connect_to_server( &Net_player->reliable_socket, &Netgame.server_addr );
1732 if ( Net_player->reliable_socket == INVALID_SOCKET ) {
1733 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONNECT_FAIL);
1737 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1738 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1740 ubyte data[MAX_PACKET_SIZE];
1742 int packet_size = 0;
1744 BUILD_HEADER(LEAVE_GAME);
1746 // add a flag indicating whether he was kicked or not
1747 val = (char)kicked_reason;
1750 if (player_id < 0) {
1751 ADD_DATA(Net_player->player_id);
1753 // inform the host that we are leaving the game
1754 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1755 multi_io_send_to_all_reliable(data, packet_size);
1757 multi_io_send_reliable(Net_player, data, packet_size);
1760 // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1761 // so he has to tell everyone that this guy left
1763 nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1765 // a couple of important checks
1766 Assert(player_id != Net_player->player_id);
1767 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1769 // add the id of the guy to be kicked
1770 ADD_DATA(player_id);
1772 // broadcast to everyone
1773 if (target == NULL) {
1774 multi_io_send_to_all_reliable(data, packet_size);
1776 multi_io_send_reliable(target, data, packet_size);
1781 // process a notification the a player has left the game
1782 void process_leave_game_packet(ubyte* data, header* hinfo)
1790 offset = HEADER_LENGTH;
1792 // get whether he was kicked
1793 GET_DATA(kicked_reason);
1795 // get the address of the guy who is to leave
1796 GET_DATA(deader_id);
1799 // determine who is dropping and printf out a notification
1800 player_num = find_player_id(deader_id);
1801 if (player_num == -1) {
1802 nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1806 nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].player->callsign));
1809 // a hook to display that a player was kicked
1810 if (kicked_reason >= 0){
1811 // if it was me that was kicked, leave the game
1812 if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1815 switch(kicked_reason){
1816 case KICK_REASON_BAD_XFER:
1817 notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1819 case KICK_REASON_CANT_XFER:
1820 notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1822 case KICK_REASON_INGAME_ENDED:
1823 notify_code = MULTI_END_NOTIFY_KICKED_INGAME_ENDED;
1826 notify_code = MULTI_END_NOTIFY_KICKED;
1830 multi_quit_game(PROMPT_NONE, notify_code);
1833 // otherwise indicate someone was kicked
1835 nprintf(("Network","%s was kicked\n",Net_players[player_num].player->callsign));
1837 // display the result
1838 memset(str, 0, 512);
1839 multi_kick_get_text(&Net_players[player_num], kicked_reason, str);
1840 multi_display_chat_msg(str, player_num, 0);
1844 // first of all, if we're the master, we should be rebroadcasting this packet
1845 if (Net_player->flags & NETINFO_FLAG_AM_MASTER) {
1848 sprintf(msg, XSTR("%s has left the game",719), Net_players[player_num].player->callsign );
1850 if (!(Game_mode & GM_STANDALONE_SERVER)){
1851 HUD_sourced_printf(HUD_SOURCE_HIDDEN, msg);
1854 send_hud_msg_to_all(msg);
1855 multi_io_send_to_all_reliable(data, offset);
1858 // leave the game if the host and/or master has dropped
1860 if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1861 nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1864 ml_string(NOX("Host and/or server has left the game"));
1866 // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1867 if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1868 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1871 delete_player(player_num);
1874 delete_player(player_num);
1876 // OSAPI GUI stuff (if standalone)
1877 if (Game_mode & GM_STANDALONE_SERVER) {
1878 // returns true if we should reset the standalone
1879 if (std_remove_player(&Net_players[player_num])) {
1880 nprintf(("Network", "Should reset!!\n"));
1884 // update these gui vals
1885 std_connect_set_host_connect_status();
1886 std_connect_set_connect_count();
1890 // send information about this currently active game to the specified address
1891 void send_game_active_packet(net_addr* addr)
1895 ubyte data[MAX_PACKET_SIZE],val;
1897 // build the header and add the data
1898 BUILD_HEADER(GAME_ACTIVE);
1900 // add the server version and compatible version #
1901 val = MULTI_FS_SERVER_VERSION;
1903 val = MULTI_FS_SERVER_COMPATIBLE_VERSION;
1906 ADD_STRING(Netgame.name);
1907 ADD_STRING(Netgame.mission_name);
1908 ADD_STRING(Netgame.title);
1909 val = (ubyte)multi_num_players();
1912 // add the proper flags
1914 if((Netgame.mode == NG_MODE_PASSWORD) || ((Game_mode & GM_STANDALONE_SERVER) && (multi_num_players() == 0) && (std_is_host_passwd()))){
1915 flags |= AG_FLAG_PASSWD;
1918 // proper netgame type flags
1919 if(Netgame.type_flags & NG_TYPE_TEAM){
1920 flags |= AG_FLAG_TEAMS;
1921 } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
1922 flags |= AG_FLAG_DOGFIGHT;
1924 flags |= AG_FLAG_COOP;
1927 // proper netgame state flags
1928 switch(Netgame.game_state){
1929 case NETGAME_STATE_FORMING:
1930 flags |= AG_FLAG_FORMING;
1933 case NETGAME_STATE_BRIEFING:
1934 case NETGAME_STATE_MISSION_SYNC:
1935 case NETGAME_STATE_HOST_SETUP:
1936 flags |= AG_FLAG_BRIEFING;
1939 case NETGAME_STATE_IN_MISSION:
1940 flags |= AG_FLAG_IN_MISSION;
1943 case NETGAME_STATE_PAUSED:
1944 flags |= AG_FLAG_PAUSE;
1947 case NETGAME_STATE_ENDGAME:
1948 case NETGAME_STATE_DEBRIEF:
1949 flags |= AG_FLAG_DEBRIEF;
1953 // if this is a standalone
1954 if(Game_mode & GM_STANDALONE_SERVER){
1955 flags |= AG_FLAG_STANDALONE;
1958 // if we're in campaign mode
1959 if(Netgame.campaign_mode == MP_CAMPAIGN){
1960 flags |= AG_FLAG_CAMPAIGN;
1963 // add the data about the connection speed of the host machine
1964 Assert( (Multi_connection_speed >= 0) && (Multi_connection_speed <= 4) );
1965 flags |= (Multi_connection_speed << AG_FLAG_CONNECTION_BIT);
1970 psnet_send(addr, data, packet_size);
1973 // process information about an active game
1974 void process_game_active_packet(ubyte* data, header* hinfo)
1979 int modes_compatible;
1981 fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->net_id, hinfo->port);
1983 // read this game into a temporary structure
1984 offset = HEADER_LENGTH;
1986 // get the server version and compatible version
1987 GET_DATA(ag.version);
1988 GET_DATA(ag.comp_version);
1990 GET_STRING(ag.name);
1991 GET_STRING(ag.mission_name);
1992 GET_STRING(ag.title);
1994 ag.num_players = val;
1999 modes_compatible = 1;
2001 if((ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo){
2002 modes_compatible = 0;
2004 if(!(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo){
2005 modes_compatible = 0;
2009 // if this is a compatible version, and our modes are compatible, register it
2010 if( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ){
2011 multi_update_active_games(&ag);
2015 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2016 // is used to change the current mission, current state, etc.
2017 void send_netgame_update_packet(net_player *pl)
2021 ubyte data[MAX_PACKET_SIZE];
2024 BUILD_HEADER(GAME_UPDATE);
2026 // with new mission description field, this becomes way to large
2027 // so we must add every element piece by piece except the
2028 ADD_STRING(Netgame.name);
2029 ADD_STRING(Netgame.mission_name);
2030 ADD_STRING(Netgame.title);
2031 ADD_STRING(Netgame.campaign_name);
2032 ADD_DATA(Netgame.campaign_mode);
2033 ADD_DATA(Netgame.max_players);
2034 ADD_DATA(Netgame.security);
2035 ADD_DATA(Netgame.respawn);
2036 ADD_DATA(Netgame.flags);
2037 ADD_DATA(Netgame.type_flags);
2038 ADD_DATA(Netgame.version_info);
2039 ADD_DATA(Netgame.debug_flags);
2041 // only the server should ever send the netgame state (standalone situation)
2042 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2043 ADD_DATA(Netgame.game_state);
2046 // if we're the host on a standalone, send to the standalone and let him rebroadcast
2047 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2049 multi_io_send_to_all_reliable(data, packet_size);
2051 for(idx=0; idx<MAX_PLAYERS; idx++){
2052 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2053 send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2057 multi_io_send_reliable(pl, data, packet_size);
2058 send_netgame_descript_packet( &pl->p_info.addr , 1 );
2061 Assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2062 multi_io_send_reliable(Net_player, data, packet_size);
2065 // host should always send a netgame options update as well
2066 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2067 multi_options_update_netgame();
2071 // process information about the netgame sent from the server/host
2072 void process_netgame_update_packet( ubyte *data, header *hinfo )
2074 int offset,old_flags;
2077 Assert(!(Game_mode & GM_STANDALONE_SERVER));
2078 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
2080 // read in the netgame information
2081 offset = HEADER_LENGTH;
2082 GET_STRING(Netgame.name);
2083 GET_STRING(Netgame.mission_name);
2084 GET_STRING(Netgame.title);
2085 GET_STRING(Netgame.campaign_name);
2086 GET_DATA(Netgame.campaign_mode);
2087 GET_DATA(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2088 GET_DATA(Netgame.security);
2089 GET_DATA(Netgame.respawn);
2091 // be sure not to blast the quitting flag because of the "one frame extra" problem
2092 old_flags = Netgame.flags;
2093 GET_DATA(Netgame.flags);
2094 GET_DATA(Netgame.type_flags);
2095 GET_DATA(Netgame.version_info);
2096 GET_DATA(Netgame.debug_flags);
2103 // now compare the passed in game state to our current known state. If it has changed, then maybe
2104 // do something interesting.
2105 // move from the forming or debriefing state to the mission sync state
2106 if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2107 // if coming from the forming state
2108 if( (Netgame.game_state == NETGAME_STATE_FORMING) ||
2109 ((Netgame.game_state != NETGAME_STATE_FORMING) && ((gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP) || (gameseq_get_state() == GS_STATE_MULTI_CLIENT_SETUP))) ){
2110 // do any special processing for forced state transitions
2111 multi_handle_state_special();
2113 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2114 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2115 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2117 // if coming from the debriefing state
2118 else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2119 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2121 // do any special processing for forced state transitions
2122 multi_handle_state_special();
2124 multi_flush_mission_stuff();
2126 Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING;
2127 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2128 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
2131 // move from mission sync to team select
2132 else if ( ng_state == NETGAME_STATE_BRIEFING ){
2133 if( (Netgame.game_state == NETGAME_STATE_MISSION_SYNC) ||
2134 ((Netgame.game_state != NETGAME_STATE_MISSION_SYNC) && (gameseq_get_state() == GS_STATE_MULTI_MISSION_SYNC) && (Multi_sync_mode != MULTI_SYNC_POST_BRIEFING)) ){
2136 // do any special processing for forced state transitions
2137 multi_handle_state_special();
2139 strncpy( Game_current_mission_filename, Netgame.mission_name, MAX_FILENAME_LEN );
2140 gameseq_post_event(GS_EVENT_START_BRIEFING);
2143 // move from the debriefing to the create game screen
2144 else if ( ng_state == NETGAME_STATE_FORMING ){
2145 if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2146 ((Netgame.game_state != NETGAME_STATE_DEBRIEF) && ((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ) ){
2147 // do any special processing for forced state transitions
2148 multi_handle_state_special();
2150 multi_flush_mission_stuff();
2152 // move to the proper screen
2153 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
2154 gameseq_post_event(GS_EVENT_MULTI_HOST_SETUP);
2156 gameseq_post_event(GS_EVENT_MULTI_CLIENT_SETUP);
2161 Netgame.game_state = ng_state;
2164 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2165 void send_netgame_descript_packet(net_addr *addr, int code)
2167 ubyte data[MAX_PACKET_SIZE],val;
2169 int packet_size = 0;
2172 BUILD_HEADER(UPDATE_DESCRIPT);
2178 // add as much of the description as we dare
2179 len = strlen(The_mission.mission_desc);
2180 if(len > MAX_PACKET_SIZE - 10){
2181 len = MAX_PACKET_SIZE - 10;
2183 memcpy(data+packet_size,The_mission.mission_desc,len);
2186 ADD_STRING(The_mission.mission_desc);
2190 Assert(addr != NULL);
2192 psnet_send(addr, data, packet_size);
2196 // process an incoming netgame description packet
2197 void process_netgame_descript_packet( ubyte *data, header *hinfo )
2201 char mission_desc[MISSION_DESC_LENGTH+2];
2204 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2206 // read this game into a temporary structure
2207 offset = HEADER_LENGTH;
2210 // if this is a request for mission description
2212 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2217 // send an update to this guy
2218 send_netgame_descript_packet(&addr, 1);
2220 memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2221 GET_STRING(mission_desc);
2223 // only display if we're in the proper state
2224 state = gameseq_get_state();
2226 case GS_STATE_MULTI_JOIN_GAME:
2227 case GS_STATE_MULTI_CLIENT_SETUP:
2228 case GS_STATE_MULTI_HOST_SETUP:
2229 multi_common_set_text(mission_desc);
2237 // broadcast a query for active games. IPX will use net broadcast and TCP will either request from the MT or from the specified list
2238 void broadcast_game_query()
2242 server_item *s_moveup;
2243 ubyte data[MAX_PACKET_SIZE];
2245 BUILD_HEADER(GAME_QUERY);
2247 // go through the server list and query each of those as well
2248 s_moveup = Game_server_head;
2249 if(s_moveup != NULL){
2251 send_server_query(&s_moveup->server_addr);
2252 s_moveup = s_moveup->next;
2253 } while(s_moveup != Game_server_head);
2256 fill_net_addr(&addr, Psnet_my_addr.addr, Psnet_my_addr.net_id, DEFAULT_GAME_PORT);
2258 // send out a broadcast if our options allow us
2259 if(Net_player->p_info.options.flags & MLO_FLAG_LOCAL_BROADCAST){
2260 psnet_broadcast( &addr, data, packet_size);
2264 // send an individual query to an address to see if there is an active game
2265 void send_server_query(net_addr *addr)
2268 ubyte data[MAX_PACKET_SIZE];
2270 // build the header and send the data
2271 BUILD_HEADER(GAME_QUERY);
2272 psnet_send(addr, data, packet_size);
2275 // process a query from a client looking for active freespace games
2276 void process_game_query(ubyte* data, header* hinfo)
2281 offset = HEADER_LENGTH;
2285 // check to be sure that we don't capture our own broadcast message
2286 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
2287 if ( psnet_same( &addr, &Psnet_my_addr) ){
2291 // if I am not a server of a game, don't send a reply!!!
2292 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
2296 // if the game options are being selected, then ignore the request
2297 // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2298 if((Netgame.game_state == NETGAME_STATE_STD_HOST_SETUP) || (Netgame.game_state == NETGAME_STATE_HOST_SETUP) || (Netgame.game_state == 0) || (Netgame.max_players == -1)){
2302 // send information about this active game
2303 send_game_active_packet(&addr);
2306 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2307 void send_netplayer_update_packet( net_player *pl )
2309 int packet_size,idx;
2310 ubyte data[MAX_PACKET_SIZE],val;
2312 BUILD_HEADER(NETPLAYER_UPDATE);
2314 // if I'm the server of the game, I should send an update for _all_players in the game
2315 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2316 for(idx=0;idx<MAX_PLAYERS;idx++){
2317 // only send info for connected players
2318 if(MULTI_CONNECTED(Net_players[idx])){
2323 // add the net player's information
2324 ADD_DATA(Net_players[idx].player_id);
2325 ADD_DATA(Net_players[idx].state);
2326 ADD_DATA(Net_players[idx].p_info.ship_class);
2327 ADD_DATA(Net_players[idx].tracker_player_id);
2329 if(Net_players[idx].flags & NETINFO_FLAG_HAS_CD){
2337 // add the final stop byte
2341 // broadcast the packet
2342 if(!(Game_mode & GM_IN_MISSION)){
2344 multi_io_send_to_all_reliable(data, packet_size);
2346 multi_io_send_reliable(pl, data, packet_size);
2350 multi_io_send_to_all(data, packet_size);
2352 multi_io_send(pl, data, packet_size);
2360 // add my current state in the netgame to this packet
2361 ADD_DATA(Net_player->player_id);
2362 ADD_DATA(Net_player->state);
2363 ADD_DATA(Net_player->p_info.ship_class);
2364 ADD_DATA(Multi_tracker_id);
2366 // add if I have a CD or not
2374 // add a final stop byte
2378 // send the packet to the server
2379 Assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2380 if(!(Game_mode & GM_IN_MISSION)){
2381 multi_io_send_reliable(Net_player, data, packet_size);
2383 multi_io_send(Net_player, data, packet_size);
2388 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2389 void process_netplayer_update_packet( ubyte *data, header *hinfo )
2391 int offset, player_num;
2397 offset = HEADER_LENGTH;
2399 // get the first stop byte
2402 while(stop != 0xff){
2403 // look the player up
2404 GET_DATA(player_id);
2405 player_num = find_player_id(player_id);
2406 // if we couldn't find him, read in the bogus data
2407 if((player_num == -1) || (Net_player == &Net_players[player_num])){
2408 GET_DATA(bogus.state);
2409 GET_DATA(bogus.p_info.ship_class);
2410 GET_DATA(bogus.tracker_player_id);
2414 // otherwise read in the data correctly
2416 GET_DATA(new_state);
2417 GET_DATA(Net_players[player_num].p_info.ship_class);
2418 GET_DATA(Net_players[player_num].tracker_player_id);
2421 Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2423 Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2426 // if he's changing state to joined, send a team update
2427 if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2428 multi_team_send_update();
2432 Net_players[player_num].state = new_state;
2435 // get the next stop byte
2441 // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2442 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2443 send_netplayer_update_packet(NULL);
2446 // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2447 if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2448 switch(Net_players[player_num].state){
2449 case NETPLAYER_STATE_STD_HOST_SETUP:
2450 Netgame.game_state = NETGAME_STATE_STD_HOST_SETUP;
2453 case NETPLAYER_STATE_HOST_SETUP:
2454 // check for race conditions
2455 if(Netgame.game_state != NETGAME_STATE_MISSION_SYNC){
2456 Netgame.game_state = NETGAME_STATE_FORMING;
2463 #define EXTRA_DEATH_VAPORIZED (1<<0)
2464 #define EXTRA_DEATH_WASHED (1<<1)
2465 // send a packet indicating a ship has been killed
2466 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2468 int packet_size, model;
2469 ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2470 ushort debris_signature;
2474 // only sendable from the master
2475 Assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
2478 vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2480 extra_death_info = 0;
2482 extra_death_info |= EXTRA_DEATH_VAPORIZED;
2485 if ( Ships[objp->instance].wash_killed ) {
2486 extra_death_info |= EXTRA_DEATH_WASHED;
2489 // find out the next network signature that will be used for the debris pieces.
2490 model = Ships[objp->instance].modelnum;
2491 pm = model_get(model);
2492 debris_signature = 0;
2493 if ( pm && !vaporized ) {
2494 debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2495 multi_set_network_signature( (ushort)(debris_signature + pm->num_debris_objects), MULTI_SIG_DEBRIS );
2496 Ships[objp->instance].arrival_distance = debris_signature;
2499 BUILD_HEADER(SHIP_KILL);
2500 ADD_DATA(objp->net_signature);
2502 // ships which are initially killed get the rest of the data sent. self destructed ships and
2503 if ( other_objp == NULL ) {
2508 nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2510 ADD_DATA( other_objp->net_signature );
2513 ADD_DATA( debris_signature );
2514 ADD_DATA( percent_killed );
2515 sd = (ubyte)self_destruct;
2517 ADD_DATA( extra_death_info );
2519 // if the ship who died is a player, then send some extra info, like who killed him, etc.
2521 if ( objp->flags & OF_PLAYER_SHIP ) {
2525 pnum = multi_find_player_by_object( objp );
2528 ADD_DATA( was_player );
2530 Assert(Net_players[pnum].player->killer_objtype < CHAR_MAX);
2531 temp = (char)Net_players[pnum].player->killer_objtype;
2534 Assert(Net_players[pnum].player->killer_species < CHAR_MAX);
2535 temp = (char)Net_players[pnum].player->killer_species;
2538 Assert(Net_players[pnum].player->killer_weapon_index < CHAR_MAX);
2539 temp = (char)Net_players[pnum].player->killer_weapon_index;
2542 ADD_STRING( Net_players[pnum].player->killer_parent_name );
2544 ADD_DATA( was_player );
2547 ADD_DATA( was_player );
2550 // send the packet reliably!!!
2551 multi_io_send_to_all_reliable(data, packet_size);
2554 // process a packet indicating that a ship has been killed
2555 void process_ship_kill_packet( ubyte *data, header *hinfo )
2558 ushort ship_sig, other_sig, debris_sig;
2559 object *sobjp, *oobjp;
2560 float percent_killed;
2561 ubyte was_player, extra_death_info, sd;
2562 char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = SPECIES_TERRAN, killer_weapon_index = -1;
2564 offset = HEADER_LENGTH;
2567 GET_DATA( other_sig );
2568 GET_DATA( debris_sig );
2569 GET_DATA( percent_killed );
2571 GET_DATA( extra_death_info );
2572 GET_DATA( was_player );
2575 // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2576 if ( was_player != 0 ) {
2577 GET_DATA( killer_objtype );
2578 GET_DATA( killer_species );
2579 GET_DATA( killer_weapon_index );
2580 GET_STRING( killer_name );
2585 sobjp = multi_get_network_object( ship_sig );
2587 // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2588 // another message from the server that this happened!
2589 if ( sobjp == NULL ) {
2590 nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2594 // set this ship's hull value to 0
2595 sobjp->hull_strength = 0.0f;
2597 // maybe set vaporized
2598 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2599 Ships[sobjp->instance].flags |= SF_VAPORIZE;
2602 // maybe set wash_killed
2603 if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2604 Ships[sobjp->instance].wash_killed = 1;
2607 oobjp = multi_get_network_object( other_sig );
2609 if ( was_player != 0 ) {
2612 pnum = multi_find_player_by_object( sobjp );
2614 Net_players[pnum].player->killer_objtype = killer_objtype;
2615 Net_players[pnum].player->killer_species = killer_species;
2616 Net_players[pnum].player->killer_weapon_index = killer_weapon_index;
2617 strcpy( Net_players[pnum].player->killer_parent_name, killer_name );
2621 // check to see if I need to respawn myself
2622 multi_respawn_check(sobjp);
2624 // store the debris signature in the arrival distance which will never get used for player ships
2625 Ships[sobjp->instance].arrival_distance = debris_sig;
2627 // set this bit so that we don't accidentally start switching targets when we die
2628 if(sobjp == Player_obj){
2629 Game_mode |= GM_DEAD_DIED;
2632 nprintf(("Network", "Killing off %s\n", Ships[sobjp->instance].ship_name));
2634 // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2635 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2636 ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2638 extern void ship_destroyed( int shipnum );
2639 ship_destroyed( sobjp->instance );
2640 sobjp->flags |= OF_SHOULD_BE_DEAD;
2641 obj_delete( OBJ_INDEX(sobjp) );
2645 // send a packet indicating a ship should be created
2646 void send_ship_create_packet( object *objp, int is_support )
2649 ubyte data[MAX_PACKET_SIZE];
2651 // We will pass the ship to create by name.
2652 BUILD_HEADER(SHIP_CREATE);
2653 ADD_DATA(objp->net_signature);
2654 ADD_DATA( is_support );
2656 ADD_DATA( objp->pos );
2659 // broadcast the packet
2660 multi_io_send_to_all_reliable(data, packet_size);
2663 // process a packet indicating a ship should be created
2664 void process_ship_create_packet( ubyte *data, header *hinfo )
2666 int offset, objnum, is_support;
2669 vector pos = ZERO_VECTOR;
2671 Assert ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
2672 offset = HEADER_LENGTH;
2673 GET_DATA(signature);
2674 GET_DATA( is_support );
2681 // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2682 if ( !is_support ) {
2683 objp = mission_parse_get_arrival_ship( signature );
2684 if ( objp != NULL ) {
2685 objnum = parse_create_object(objp);
2687 nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2690 Assert( Arriving_support_ship );
2691 if(Arriving_support_ship == NULL){
2694 Arriving_support_ship->pos = pos;
2695 Arriving_support_ship->net_signature = signature;
2696 objnum = parse_create_object( Arriving_support_ship );
2697 Assert( objnum != -1 );
2699 mission_parse_support_arrived( objnum );
2704 // send a packet indicating a wing of ships should be created
2705 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2707 int packet_size, index, ship_instance;
2708 ubyte data[MAX_PACKET_SIZE];
2712 // for creating wing -- we just send the index into the wing array of this wing.
2713 // all players load the same mission, and so their array's should all match. We also
2714 // need to send the signature of the first ship that was created. We can find this by
2715 // looking num_to_create places back in the ship_index field in the wing structure.
2717 index = WING_INDEX(wingp);
2718 ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2719 signature = Objects[Ships[ship_instance].objnum].net_signature;
2721 BUILD_HEADER( WING_CREATE );
2723 ADD_DATA(num_to_create);
2724 ADD_DATA(signature);
2725 ADD_DATA(pre_create_count);
2726 val = wingp->current_wave - 1;
2729 multi_io_send_to_all_reliable(data, packet_size);
2732 // process a packet saying that a wing should be created
2733 void process_wing_create_packet( ubyte *data, header *hinfo )
2735 int offset, index, num_to_create;
2737 int total_arrived_count, current_wave;
2739 offset = HEADER_LENGTH;
2741 GET_DATA(num_to_create);
2742 GET_DATA(signature);
2743 GET_DATA(total_arrived_count);
2744 GET_DATA(current_wave);
2748 // do a sanity check on the wing to be sure that we are actually working on a valid wing
2749 if ( (index < 0) || (index >= num_wings) || (Wings[index].num_waves == -1) ) {
2750 nprintf(("Network", "invalid index %d for wing create packet\n"));
2753 if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2754 nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2759 Wings[index].current_count = 0;
2760 Wings[index].total_arrived_count = total_arrived_count;
2761 Wings[index].current_wave = current_wave;
2763 // set the network signature that was passed. The client should create ships in the same order
2764 // as the server -- so all ships should get the same sigs as assigned by the server. We also
2765 // need to set some timestamps and cues correctly to be sure that these things get created on
2766 // the clients correctly
2767 multi_set_network_signature( signature, MULTI_SIG_SHIP );
2768 parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2771 // packet indicating a ship is departing
2772 void send_ship_depart_packet( object *objp )
2774 ubyte data[MAX_PACKET_SIZE];
2778 signature = objp->net_signature;
2780 BUILD_HEADER(SHIP_DEPART);
2781 ADD_DATA( signature );
2783 multi_io_send_to_all_reliable(data, packet_size);
2786 // process a packet indicating a ship is departing
2787 void process_ship_depart_packet( ubyte *data, header *hinfo )
2793 offset = HEADER_LENGTH;
2794 GET_DATA( signature );
2797 // find the object which is departing
2798 objp = multi_get_network_object( signature );
2799 if ( objp == NULL ) {
2800 nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2804 // start warping him out
2805 shipfx_warpout_start( objp );
2808 // packet to tell clients cargo of a ship was revealed to all
2809 void send_cargo_revealed_packet( ship *shipp )
2811 ubyte data[MAX_PACKET_SIZE];
2814 // build the header and add the data
2815 BUILD_HEADER(CARGO_REVEALED);
2816 ADD_DATA( Objects[shipp->objnum].net_signature );
2818 // server sends to all players
2819 if(MULTIPLAYER_MASTER){
2820 multi_io_send_to_all_reliable(data, packet_size);
2822 // clients just send to the server
2824 multi_io_send_reliable(Net_player, data, packet_size);
2828 // process a cargo revealed packet
2829 void process_cargo_revealed_packet( ubyte *data, header *hinfo )
2835 offset = HEADER_LENGTH;
2836 GET_DATA(signature);
2839 // get a ship pointer and call the ship function to reveal the cargo
2840 objp = multi_get_network_object( signature );
2841 if ( objp == NULL ) {
2842 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2846 // Assert( objp->type == OBJ_SHIP );
2847 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2851 // this will take care of re-routing to all other clients
2852 ship_do_cargo_revealed( &Ships[objp->instance], 1);
2854 // server should rebroadcast
2855 if(MULTIPLAYER_MASTER){
2856 send_cargo_revealed_packet(&Ships[objp->instance]);
2860 // defines used for secondary fire packet
2861 #define SFPF_ALLOW_SWARM (1<<7)
2862 #define SFPF_DUAL_FIRE (1<<6)
2863 #define SFPF_TARGET_LOCKED (1<<5)
2865 // send a packet indicating a secondary weapon was fired
2866 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2868 int packet_size, net_player_num;
2869 ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2871 ushort target_signature;
2875 // Assert ( starting_count < UCHAR_MAX );
2877 // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
2878 // we might send the info to the other player different than the one who fired
2879 objp = &Objects[shipp->objnum];
2880 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2881 if ( num_fired == 0 ) {
2886 aip = &Ai_info[shipp->ai_index];
2888 current_bank = (ubyte)shipp->weapons.current_secondary_bank;
2889 Assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );
2891 // build up the header portion
2892 BUILD_HEADER( SECONDARY_FIRED_AI );
2894 ADD_DATA( Objects[shipp->objnum].net_signature );
2895 ADD_DATA( starting_sig );
2897 // add a couple of bits for swarm missiles and dual fire secondary weaspons
2900 sinfo = current_bank;
2903 sinfo |= SFPF_ALLOW_SWARM;
2906 if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
2907 sinfo |= SFPF_DUAL_FIRE;
2910 if ( aip->current_target_is_locked ){
2911 sinfo |= SFPF_TARGET_LOCKED;
2916 // add the ship's target and any targeted subsystem
2917 target_signature = 0;
2919 if ( aip->target_objnum != -1) {
2920 target_signature = Objects[aip->target_objnum].net_signature;
2921 if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
2924 s_index = ship_get_index_from_subsys( aip->targeted_subsys, aip->target_objnum );
2925 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
2926 t_subsys = (char)s_index;
2929 if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
2930 Assert(Weapon_info[Weapons[Objects[aip->target_objnum].instance].weapon_info_index].wi_flags & WIF_BOMB);
2935 ADD_DATA( target_signature );
2936 ADD_DATA( t_subsys );
2938 // just send this packet to everyone, then bail if an AI ship fired.
2939 if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2940 multi_io_send_to_all(data, packet_size);
2944 net_player_num = multi_find_player_by_object( objp );
2946 // getting here means a player fired. Send the current packet to all players except the player
2947 // who fired. If nothing got fired, then don't send to the other players -- we will just send
2948 // a packet to the player who will find out that he didn't fire anything
2949 if ( num_fired > 0 ) {
2950 multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
2953 // if I (the master) fired, then return
2954 if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
2958 // now build up the packet to send to the player who actually fired.
2959 BUILD_HEADER( SECONDARY_FIRED_PLR );
2960 ADD_DATA(starting_sig);
2963 // add the targeting information so that the player's weapons will always home on the correct
2965 ADD_DATA( target_signature );
2966 ADD_DATA( t_subsys );
2968 multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
2971 /// process a packet indicating a secondary weapon was fired
2972 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
2974 int offset, allow_swarm, target_objnum_save;
2975 ushort net_signature, starting_sig, target_signature;
2976 ubyte sinfo, current_bank;
2977 object* objp, *target_objp;
2981 ship_subsys *targeted_subsys_save;
2983 offset = HEADER_LENGTH; // size of the header
2985 // if from_player is false, it means that the secondary weapon info in this packet was
2986 // fired by an ai object (or another player). from_player == 1 means tha me (the person
2987 // receiving this packet) fired the secondary weapon
2988 if ( !from_player ) {
2989 GET_DATA( net_signature );
2990 GET_DATA( starting_sig );
2991 GET_DATA( sinfo ); // are we firing swarm missiles
2993 GET_DATA( target_signature );
2994 GET_DATA( t_subsys );
2998 // find the object (based on network signatures) for the object that fired
2999 objp = multi_get_network_object( net_signature );
3000 if ( objp == NULL ) {
3001 nprintf(("Network", "Could not find ship for fire secondary packet!"));
3005 // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3006 // of the next fire time of this bank to 0 so we can fire right away
3007 shipp = &Ships[objp->instance];
3010 GET_DATA( starting_sig );
3013 GET_DATA( target_signature );
3014 GET_DATA( t_subsys );
3018 // get the object and ship
3020 shipp = Player_ship;
3023 // check the allow swarm bit
3025 if ( sinfo & SFPF_ALLOW_SWARM ){
3029 // set the dual fire properties of the ship
3030 if ( sinfo & SFPF_DUAL_FIRE ){
3031 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3033 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3036 // determine whether current target is locked
3037 Assert( shipp->ai_index != -1 );
3038 aip = &Ai_info[shipp->ai_index];
3039 if ( sinfo & SFPF_TARGET_LOCKED ) {
3040 aip->current_target_is_locked = 1;
3042 aip->current_target_is_locked = 0;
3045 // find out the current bank
3046 current_bank = (ubyte)(sinfo & 0x3);
3047 Assert( (current_bank >= 0) && (current_bank < MAX_SECONDARY_BANKS) );
3048 shipp->weapons.current_secondary_bank = current_bank;
3050 // make it so we can fire this ship's secondary bank immediately!!!
3051 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(0);
3052 shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3054 // set this ship's target and subsystem information. We will save and restore target and
3055 // targeted subsystem so that we do not accidentally change targets for this player or
3056 // any AI ships on his system.
3057 target_objnum_save = aip->target_objnum;
3058 targeted_subsys_save = aip->targeted_subsys;
3060 // reset these variables for accuracy. They will get reassigned at the end of this fuction
3061 aip->target_objnum = -1;
3062 aip->targeted_subsys = NULL;
3064 target_objp = multi_get_network_object( target_signature );
3065 if ( target_objp != NULL ) {
3066 aip->target_objnum = OBJ_INDEX(target_objp);
3068 if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3069 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3073 if ( starting_sig != 0 ){
3074 multi_set_network_signature( starting_sig, MULTI_SIG_NON_PERMANENT );
3076 shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3079 ship_fire_secondary( objp, allow_swarm );
3081 // restore targeted object and targeted subsystem
3082 aip->target_objnum = target_objnum_save;
3083 aip->targeted_subsys = targeted_subsys_save;
3086 // send a packet indicating a countermeasure was fired
3087 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3089 ubyte data[MAX_PACKET_SIZE];
3094 Assert ( cmeasure_count < UCHAR_MAX );
3095 BUILD_HEADER(COUNTERMEASURE_FIRED);
3096 ADD_DATA( objp->net_signature );
3097 ADD_DATA( rand_val );
3099 multi_io_send_to_all(data, packet_size);
3102 // process a packet indicating a countermeasure was fired
3103 void process_countermeasure_fired_packet( ubyte *data, header *hinfo )
3105 int offset, rand_val;
3111 offset = HEADER_LENGTH;
3113 GET_DATA( signature );
3114 GET_DATA( rand_val );
3117 objp = multi_get_network_object( signature );
3118 if ( objp == NULL ) {
3119 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3122 if(objp->type != OBJ_SHIP){
3125 // Assert ( objp->type == OBJ_SHIP );
3127 // make it so ship can fire right away!
3128 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
3129 if ( objp == Player_obj ){
3130 nprintf(("network", "firing countermeasure from my ship\n"));
3133 ship_launch_countermeasure( objp, rand_val );
3136 // send a packet indicating that a turret has been fired
3137 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3140 ushort pnet_signature;
3141 ubyte data[MAX_PACKET_SIZE], cindex;
3148 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3152 // local setup -- be sure we are actually passing a weapon!!!!
3153 objp = &Objects[weapon_objnum];
3154 Assert ( objp->type == OBJ_WEAPON );
3155 if(Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE){
3159 pnet_signature = Objects[ship_objnum].net_signature;
3161 Assert( subsys_index < UCHAR_MAX );
3162 cindex = (ubyte)subsys_index;
3164 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3169 // build the fire turret packet.
3170 BUILD_HEADER(FIRE_TURRET_WEAPON);
3171 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.fvec);
3172 ADD_DATA( has_sig );
3173 ADD_DATA( pnet_signature );
3175 ADD_DATA( objp->net_signature );
3178 val = (short)ssp->submodel_info_1.angs.h;
3180 val = (short)ssp->submodel_info_2.angs.p;
3183 multi_io_send_to_all(data, packet_size);
3185 multi_rate_add(1, "tur", packet_size);
3188 // process a packet indicating a turret has been fired
3189 void process_turret_fired_packet( ubyte *data, header *hinfo )
3191 int offset, weapon_objnum, wid;
3192 ushort pnet_signature, wnet_signature;
3201 short pitch, heading;
3203 // get the data for the turret fired packet
3204 offset = HEADER_LENGTH;
3205 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3206 GET_DATA( has_sig );
3207 GET_DATA( pnet_signature );
3209 GET_DATA( wnet_signature );
3213 GET_DATA( turret_index );
3214 GET_DATA( heading );
3216 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3219 objp = multi_get_network_object( pnet_signature );
3220 if ( objp == NULL ) {
3221 nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3225 // if this isn't a ship, do nothing
3226 if ( objp->type != OBJ_SHIP ){
3230 // make an orientation matrix from the o_fvec
3231 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3233 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3234 // hack, but should be suitable.
3235 shipp = &Ships[objp->instance];
3236 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3240 wid = ssp->system_info->turret_weapon_type;
3242 // bash the position and orientation of the turret
3243 ssp->submodel_info_1.angs.h = (float)heading;
3244 ssp->submodel_info_2.angs.p = (float)pitch;
3246 // get the world position of the weapon
3247 ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3249 // create the weapon object
3250 if(wnet_signature != 0){
3251 multi_set_network_signature( wnet_signature, MULTI_SIG_NON_PERMANENT );
3253 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
3254 if (weapon_objnum != -1) {
3255 if ( Weapon_info[wid].launch_snd != -1 ) {
3256 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3261 // send a mission log item packet
3262 void send_mission_log_packet( int num )
3265 ubyte data[MAX_PACKET_SIZE];
3270 Assert ( (Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3272 // get the data from the log
3273 entry = &log_entries[num];
3274 type = (ubyte)entry->type; // do the type casting thing to save on packet space
3275 sindex = (ushort)entry->index;
3277 BUILD_HEADER(MISSION_LOG_ENTRY);
3279 ADD_DATA(entry->flags);
3281 ADD_DATA(entry->timestamp);
3282 ADD_STRING(entry->pname);
3283 ADD_STRING(entry->sname);
3285 // broadcast the packet to all players
3286 multi_io_send_to_all_reliable(data, packet_size);
3289 // process a mission log item packet
3290 void process_mission_log_packet( ubyte *data, header *hinfo )
3295 char pname[NAME_LENGTH], sname[NAME_LENGTH];
3298 Assert ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3300 offset = HEADER_LENGTH;
3304 GET_DATA(timestamp);
3310 mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3313 // send a mission message packet
3314 void send_mission_message_packet( int id, char *who_from, int priority, int timing, int source, int builtin_type, int multi_target, int multi_team_filter)
3317 ubyte data[MAX_PACKET_SIZE], up, us, utime;
3319 Assert ( Net_player->flags & NETINFO_FLAG_AM_MASTER );
3320 Assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3321 Assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3323 up = (ubyte) priority;
3324 us = (ubyte) source;
3325 utime = (ubyte)timing;
3327 BUILD_HEADER(MISSION_MESSAGE);
3329 ADD_STRING(who_from);
3333 ADD_DATA(builtin_type);
3334 ADD_DATA(multi_team_filter);
3336 if (multi_target == -1){
3337 multi_io_send_to_all_reliable(data, packet_size);
3339 multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3343 // process a mission message packet
3344 void process_mission_message_packet( ubyte *data, header *hinfo )
3346 int offset, id, builtin_type;
3347 ubyte priority, source, utiming;
3348 char who_from[NAME_LENGTH];
3349 int multi_team_filter;
3351 Assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
3353 offset = HEADER_LENGTH;
3355 GET_STRING(who_from);
3359 GET_DATA(builtin_type);
3360 GET_DATA(multi_team_filter);
3364 // filter out builtin ones in TvT
3365 if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)){
3369 // maybe filter this out
3370 if(!message_filter_multi(id)){
3371 // send the message as if it came from an sexpression
3372 message_queue_message( id, priority, utiming, who_from, source, 0, 0, builtin_type );
3376 // just send them a pong back as fast as possible
3377 void process_ping_packet(ubyte *data, header *hinfo)
3382 offset = HEADER_LENGTH;
3385 // get the address to return the pong to
3386 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3392 // right now it just routes the pong through to the standalone gui, which is the only
3393 // system which uses ping and pong right now.
3394 void process_pong_packet(ubyte *data, header *hinfo)
3400 offset = HEADER_LENGTH;
3402 fill_net_addr(&addr, hinfo->addr, hinfo->net_id, hinfo->port);
3406 // if we're connected , see who sent us this pong
3407 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
3408 lookup = find_player_id(hinfo->id);
3413 p = &Net_players[lookup];
3415 // evaluate the ping
3416 multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3418 // put in calls to any functions which may want to know about the ping times from
3420 if(Game_mode & GM_STANDALONE_SERVER){
3421 std_update_player_ping(p);
3424 // mark his socket as still alive (extra precaution)
3425 psnet_mark_received(Net_players[lookup].reliable_socket);
3427 // otherwise, do any special processing
3429 // if we're in the join game state, see if this pong came from a server on our
3431 if(gameseq_get_state() == GS_STATE_MULTI_JOIN_GAME){
3432 multi_join_eval_pong(&addr, timer_get_fixed_seconds());
3437 // send a ping packet
3438 void send_ping(net_addr *addr)
3440 unsigned char data[8];
3443 // build the header and send the packet
3444 BUILD_HEADER( PING );
3445 psnet_send(addr, &data[0], packet_size);
3448 // send a pong packet
3449 void send_pong(net_addr *addr)
3451 unsigned char data[8];
3454 // build the header and send the packet
3456 psnet_send(addr, &data[0], packet_size);
3459 // sent from host to master. give me the list of missions you have.
3460 // this will be used only in a standalone mode
3461 void send_mission_list_request( int what )
3463 ubyte data[MAX_PACKET_SIZE];
3466 // build the header and ask for a list of missions or campaigns (depending
3467 // on the 'what' flag).
3468 BUILD_HEADER(MISSION_REQUEST);
3470 multi_io_send_reliable(Net_player, data, packet_size);
3473 // maximum number of bytes that we can send in a mission items packet.
3474 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3476 // defines used to tell what type of packets are being sent
3477 #define MISSION_LIST_ITEMS 1
3478 #define CAMPAIGN_LIST_ITEMS 2
3480 // send an individual mission file item
3481 void send_mission_items( net_player *pl )
3483 ubyte data[MAX_PACKET_SIZE];
3488 BUILD_HEADER(MISSION_ITEM);
3490 // send the list of missions and campaigns avilable on the server. Stop when
3491 // reaching a certain maximum
3492 type = MISSION_LIST_ITEMS;
3494 for (i = 0; i < Multi_create_mission_count; i++ ) {
3498 ADD_STRING( Multi_create_mission_list[i].filename );
3499 ADD_STRING( Multi_create_mission_list[i].name );
3500 ADD_DATA( Multi_create_mission_list[i].flags );
3501 ADD_DATA( Multi_create_mission_list[i].max_players );
3502 ADD_DATA( Multi_create_mission_list[i].respawn );
3505 ADD_DATA( Multi_create_mission_list[i].valid_status );
3507 if ( packet_size > MAX_MISSION_ITEMS_BYTES ) {
3510 multi_io_send_reliable(pl, data, packet_size);
3511 BUILD_HEADER( MISSION_ITEM );
3517 multi_io_send_reliable(pl, data, packet_size);
3519 // send the campaign information
3520 type = CAMPAIGN_LIST_ITEMS;
3521 BUILD_HEADER(MISSION_ITEM);
3523 for (i = 0; i < Multi_create_campaign_count; i++ ) {
3527 ADD_STRING( Multi_create_campaign_list[i].filename );
3528 ADD_STRING( Multi_create_campaign_list[i].name );
3529 ADD_DATA( Multi_create_campaign_list[i].flags );
3530 ADD_DATA( Multi_create_campaign_list[i].max_players );
3532 if ( packet_size > MAX_MISSION_ITEMS_BYTES ) {
3535 multi_io_send_reliable(pl, data, packet_size);
3536 BUILD_HEADER( MISSION_ITEM );
3542 multi_io_send_reliable(pl, data, packet_size);
3545 // process a request for a list of missions
3546 void process_mission_request_packet(ubyte *data, header *hinfo)
3548 int player_num,offset;
3550 offset = HEADER_LENGTH;
3553 // fill in the address information of where this came from
3554 player_num = find_player_id(hinfo->id);
3555 if(player_num == -1){
3556 nprintf(("Network","Could not find player to send mission list items to!\n"));
3560 send_mission_items( &Net_players[player_num] );
3563 // process an individual mission file item
3564 void process_mission_item_packet(ubyte *data,header *hinfo)
3567 char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3568 ubyte stop, type,max_players;
3571 Assert(gameseq_get_state() == GS_STATE_MULTI_HOST_SETUP);
3572 offset = HEADER_LENGTH;
3577 GET_STRING( filename );
3580 GET_DATA( max_players );
3582 // missions also have respawns and a crc32 associated with them
3583 if(type == MISSION_LIST_ITEMS){
3587 GET_DATA(valid_status);
3589 if ( Multi_create_mission_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3590 strcpy(Multi_create_mission_list[Multi_create_mission_count].filename, filename );
3591 strcpy(Multi_create_mission_list[Multi_create_mission_count].name, name );
3592 Multi_create_mission_list[Multi_create_mission_count].flags = flags;
3593 Multi_create_mission_list[Multi_create_mission_count].respawn = respawn;
3594 Multi_create_mission_list[Multi_create_mission_count].max_players = max_players;
3597 Multi_create_mission_list[Multi_create_mission_count].valid_status = valid_status;
3599 Multi_create_mission_count++;
3601 } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3602 if ( Multi_create_campaign_count < MULTI_CREATE_MAX_LIST_ITEMS ) {
3603 strcpy(Multi_create_campaign_list[Multi_create_campaign_count].filename, filename );
3604 strcpy(Multi_create_campaign_list[Multi_create_campaign_count].name, name );
3605 Multi_create_campaign_list[Multi_create_campaign_count].flags = flags;
3606 Multi_create_campaign_list[Multi_create_campaign_count].respawn = 0;
3607 Multi_create_campaign_list[Multi_create_campaign_count].max_players = max_players;
3608 Multi_create_campaign_count++;
3617 // this will cause whatever list to get resorted (although they should be appearing in order)
3618 multi_create_setup_list_data(-1);
3621 // send a request to the server to pause or unpause the game
3622 void send_multi_pause_packet(int pause)
3624 ubyte data[MAX_PACKET_SIZE];
3626 int packet_size = 0;
3628 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
3631 BUILD_HEADER(MULTI_PAUSE_REQUEST);
3632 val = (ubyte) pause;
3634 // add the pause info
3637 // send the request to the server
3638 multi_io_send_reliable(Net_player, data, packet_size);
3641 // process a pause update packet (pause, unpause, etc)
3642 void process_multi_pause_packet(ubyte *data, header *hinfo)
3648 offset = HEADER_LENGTH;
3654 // get who sent the packet
3655 player_index = find_player_id(hinfo->id);
3656 // if we don't know who sent the packet, don't do anything
3657 if(player_index == -1){
3661 // if we're the server, we should evaluate whether this guy is allowed to send the packet
3662 multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3665 // send a game information update
3666 void send_game_info_packet()
3669 ubyte data[MAX_PACKET_SIZE], paused;
3671 // set the paused variable
3672 paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3674 BUILD_HEADER(GAME_INFO);
3675 ADD_DATA( Missiontime );
3678 multi_io_send_to_all(data, packet_size);
3681 // process a game information update
3682 void process_game_info_packet( ubyte *data, header *hinfo )
3688 offset = HEADER_LENGTH;
3690 // get the mission time -- we should examine our time and the time from the server. If off by some delta
3691 // time, set our time to server time (should take ping time into account!!!)
3692 GET_DATA( mission_time );
3697 // send an ingame nak packet
3698 void send_ingame_nak(int state, net_player *p)
3700 ubyte data[MAX_PACKET_SIZE];
3703 BUILD_HEADER(INGAME_NAK);
3707 multi_io_send_reliable(p, data, packet_size);
3710 // process an ingame nak packet
3711 void process_ingame_nak(ubyte *data, header *hinfo)
3713 int offset,state,pid;
3716 offset = HEADER_LENGTH;
3720 pid = find_player_id(hinfo->id);
3724 pl = &Net_players[pid];
3727 case ACK_FILE_ACCEPTED :
3728 Assert(Net_player->flags & NETINFO_FLAG_INGAME_JOIN);
3729 nprintf(("Network","Mission file rejected by server, aborting...\n"));
3730 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_FILE_REJECTED);
3735 // send a packet telling players to end the mission
3736 void send_endgame_packet(net_player *pl)
3738 ubyte data[MAX_PACKET_SIZE];
3742 BUILD_HEADER(MISSION_END);
3744 // sending to a specific player?
3746 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
3747 multi_io_send_reliable(pl, data, packet_size);
3751 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3752 // send all player stats here
3753 multi_broadcast_stats(STATS_MISSION);
3755 // if in dogfight mode, send all dogfight stats as well
3756 ml_string("Before dogfight stats!");
3757 if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
3758 ml_string("Sending dogfight stats!");
3760 multi_broadcast_stats(STATS_DOGFIGHT_KILLS);
3762 ml_string("After dogfight stats!");
3764 // tell everyone to leave the game
3765 multi_io_send_to_all_reliable(data, packet_size);
3767 multi_io_send_reliable(Net_player, data, packet_size);
3771 // process a packet indicating we should end the current mission
3772 void process_endgame_packet(ubyte *data, header *hinfo)
3777 offset = HEADER_LENGTH;
3781 ml_string("Receiving endgame packet");
3783 // if I'm the server, I should evaluate whether the sender is authorized to end the game
3784 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3785 // determine who this came from and make sure he is allowed to end the game
3786 player_num = find_player_id(hinfo->id);
3787 Assert(player_num != -1);
3792 // if the player is allowed to end the mission
3793 if(!multi_can_end_mission(&Net_players[player_num])){
3797 // act as if we hit alt+j locally
3798 multi_handle_end_mission_request();
3800 // all clients process immediately
3802 // ingame joiners should quit when they receive an endgame packet since the game is over
3803 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
3804 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_EARLY_END);
3808 // do any special processing for being in a state other than the gameplay state
3809 multi_handle_state_special();
3811 // make sure we're not already in the debrief state
3812 if((gameseq_get_state() != GS_STATE_DEBRIEF) && (gameseq_get_state() != GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){
3813 multi_warpout_all_players();
3818 // send a position/orientation update for myself (if I'm an observer)
3819 void send_observer_update_packet()
3821 ubyte data[MAX_PACKET_SIZE];
3826 // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3827 // to send any update packets to anyone.
3828 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3832 if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3838 BUILD_HEADER(OBSERVER_UPDATE);
3840 ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3842 ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3845 // add targeting infomation
3846 if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3847 target_sig = Objects[Player_ai->target_objnum].net_signature;
3851 ADD_DATA(target_sig);
3853 multi_io_send(Net_player, data, packet_size);
3856 // process a position/orientation update from an observer
3857 void process_observer_update_packet(ubyte *data, header *hinfo)
3863 physics_info bogus_pi;
3866 offset = HEADER_LENGTH;
3868 obs_num = find_player_id(hinfo->id);
3870 memset(&bogus_pi,0,sizeof(physics_info));
3871 ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3873 ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3876 // targeting information
3877 GET_DATA(target_sig);
3880 if((obs_num < 0) || (Net_players[obs_num].player->objnum < 0)){
3884 // set targeting info
3885 if(target_sig == 0){
3886 Net_players[obs_num].s_info.target_objnum = -1;
3888 target_obj = multi_get_network_object(target_sig);
3889 Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
3892 Objects[Net_players[obs_num].player->objnum].pos = g_vec;
3893 Objects[Net_players[obs_num].player->objnum].orient = g_mat;
3894 Net_players[obs_num].s_info.eye_pos = g_vec;
3895 Net_players[obs_num].s_info.eye_orient = g_mat;
3898 void send_netplayer_slot_packet()
3900 ubyte data[MAX_PACKET_SIZE];
3901 int packet_size,idx;
3906 BUILD_HEADER(NETPLAYER_SLOTS_P);
3907 for(idx=0;idx<MAX_PLAYERS;idx++){
3908 if( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx])){
3910 ADD_DATA(Net_players[idx].player_id);
3911 ADD_DATA(Objects[Net_players[idx].player->objnum].net_signature);
3912 ADD_DATA(Net_players[idx].p_info.ship_class);
3913 ADD_DATA(Net_players[idx].p_info.ship_index);
3919 // standalone case or not
3920 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
3921 multi_io_send_to_all_reliable(data, packet_size);
3923 multi_io_send_reliable(Net_player, data, packet_size);
3927 void process_netplayer_slot_packet(ubyte *data, header *hinfo)
3930 int player_num,ship_class,ship_index;
3936 offset = HEADER_LENGTH;
3938 // first untag all of the player ships and make them OF_COULD_BE_PLAYER
3939 multi_untag_player_ships();
3943 GET_DATA(player_id);
3945 GET_DATA(ship_class);
3946 GET_DATA(ship_index);
3947 player_num = find_player_id(player_id);
3949 nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
3951 // call the function in multiutil.cpp to set up the player object stuff
3952 // being careful not to muck with the standalone object
3953 if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
3954 objp = multi_get_network_object(net_sig);
3955 Assert(objp != NULL);
3956 multi_assign_player_ship( player_num, objp, ship_class );
3957 Net_players[player_num].p_info.ship_index = ship_index;
3958 objp->flags &= ~(OF_COULD_BE_PLAYER);
3959 objp->flags |= OF_PLAYER_SHIP;
3966 // standalone should forward the packet and wait for a response
3967 if(Game_mode & GM_STANDALONE_SERVER){
3968 send_netplayer_slot_packet();
3971 Net_player->state = NETPLAYER_STATE_SLOT_ACK;
3972 send_netplayer_update_packet();
3975 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
3976 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
3977 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
3978 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
3980 ubyte data[MAX_PACKET_SIZE], utmp;
3983 BUILD_HEADER(SHIP_WSTATE_CHANGE);
3984 ADD_DATA( Objects[shipp->objnum].net_signature );
3985 utmp = (ubyte)(what);
3987 utmp = (ubyte)(new_bank);
3989 utmp = (ubyte)(link_status);
3992 // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
3993 multi_io_send_to_all_reliable(data, packet_size);
3996 void process_ship_weapon_change( ubyte *data, header *hinfo )
4000 ubyte what, new_bank, link_status;
4004 offset = HEADER_LENGTH;
4005 GET_DATA( signature );
4007 GET_DATA( new_bank );
4008 GET_DATA( link_status );
4011 objp = multi_get_network_object( signature );
4012 if ( objp == NULL ) {
4013 nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4016 // Assert( objp->type == OBJ_SHIP );
4017 if(objp->type != OBJ_SHIP){
4021 // if this is my data, do nothing since I already have my own data
4022 if ( objp == Player_obj ){
4026 // now, get the ship and set the new bank and link modes based on the 'what' value
4027 shipp = &Ships[objp->instance];
4028 if ( what == MULTI_PRIMARY_CHANGED ) {
4029 shipp->weapons.current_primary_bank = new_bank;
4031 shipp->flags |= SF_PRIMARY_LINKED;
4033 shipp->flags &= ~SF_PRIMARY_LINKED;
4036 shipp->weapons.current_secondary_bank = new_bank;
4038 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4040 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4045 // ship status change procedure
4046 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4048 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4049 // for added redundancy.
4050 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4051 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4052 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4053 // back to the client. Also sends multiple times for redundancy
4054 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4055 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4056 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4058 #define SHIP_STATUS_REPEAT 2
4059 void send_ship_status_packet(net_player *pl, button_info *bi, int id)
4062 ubyte data[MAX_PACKET_SIZE];
4063 int packet_size = 0;
4069 BUILD_HEADER(SHIP_STATUS_CHANGE);
4071 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4072 temp = bi->status[idx];
4076 // server should send reliably (response packet)
4077 if(MULTIPLAYER_MASTER){
4078 multi_io_send_reliable(pl, data, packet_size);
4080 multi_io_send(pl, data, packet_size);
4084 void process_ship_status_packet(ubyte *data, header *hinfo)
4088 int player_num,unique_id;
4092 offset = HEADER_LENGTH;
4094 // zero out the button info structure for good measure
4095 memset(&bi,0,sizeof(button_info));
4097 // read the button-info
4098 GET_DATA(unique_id);
4100 for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4102 bi.status[idx] = i_tmp;
4107 // this will be handled differently client and server side. Duh.
4108 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4109 // find which net-player has sent us butotn information
4110 player_num = find_player_id(hinfo->id);
4111 Assert(player_num >= 0);
4116 // don't process critical button information for observers
4117 // its a new button_info for this guy. apply and ack
4118 if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4119 // mark that he's pressed this button
4120 // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4122 // send a return packet
4123 send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4125 // apply the button presses to his ship as normal
4126 multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4128 // else ignore it as a repeat from the same guy
4129 } else { // CLIENT SIDE
4130 // this is the return from the server, so we should now apply them locally
4131 // if(lookup_ship_status(Net_player,unique_id,1)){
4132 multi_apply_ship_status(Net_player, &bi, 1);
4137 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4138 // for clients. Left all details to this function instead of higher level messaging
4140 void send_player_order_packet(int type, int index, int cmd)
4142 ubyte data[MAX_PACKET_SIZE];
4144 ushort target_signature;
4146 int packet_size = 0;
4148 BUILD_HEADER(PLAYER_ORDER_PACKET);
4151 ADD_DATA(val); // ship order or wing order, or message all fighters
4153 // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4154 if ( val != SQUAD_MSG_ALL ){
4155 ADD_DATA(index); // net signature of target ship
4158 ADD_DATA(cmd); // the command itself
4161 target_signature = 0;
4162 if ( Player_ai->target_objnum != -1 ){
4163 target_signature = Objects[Player_ai->target_objnum].net_signature;
4166 ADD_DATA( target_signature );
4169 if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4172 s_index = ship_get_index_from_subsys( Player_ai->targeted_subsys, Player_ai->target_objnum );
4173 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
4174 t_subsys = (char)s_index;
4178 multi_io_send_reliable(Net_player, data, packet_size);
4181 // brief explanation :
4182 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4183 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4184 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4185 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4186 void process_player_order_packet(ubyte *data, header *hinfo)
4188 int offset, player_num, command, index = 0, tobjnum_save;
4189 ushort target_signature;
4190 char t_subsys, type;
4191 object *objp, *target_objp;
4194 ship_subsys *tsubsys_save, *targeted_subsys;
4196 Assert(MULTIPLAYER_MASTER);
4198 // packet values - its easier to read all of these in first
4200 offset = HEADER_LENGTH;
4203 if ( type != SQUAD_MSG_ALL ){
4207 GET_DATA( command );
4208 GET_DATA( target_signature );
4209 GET_DATA( t_subsys );
4213 player_num = find_player_id(hinfo->id);
4214 if(player_num == -1){
4215 nprintf(("Network","Received player order packet from unknown player\n"));
4219 objp = &Objects[Net_players[player_num].player->objnum];
4220 if ( objp->type != OBJ_SHIP ) {
4221 nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4225 // HACK HACK HACK HACK HACK HACK
4226 // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4227 // the data is BOGUS. All people should be able to to these things as well.
4228 if(command == REARM_REPAIR_ME_ITEM){
4229 hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].player->objnum]);
4231 } else if(command == ABORT_REARM_REPAIR_ITEM){
4232 hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].player->objnum]);
4236 // if this player is not allowed to do messaging, quit here
4237 if( !multi_can_message(&Net_players[player_num]) ){
4238 nprintf(("Network","Recieved player order packet from player not allowed to give orders!!\n"));
4242 // check to see if the type of order is a reinforcement call. If so, intercept it, and
4243 // then call them in.
4244 if ( type == SQUAD_MSG_REINFORCEMENT ) {
4245 Assert( (index >= 0) && (index < Num_reinforcements) );
4246 hud_squadmsg_call_reinforcement(index, player_num);
4250 // set the player's ai information here
4251 shipp = &Ships[objp->instance];
4252 aip = &Ai_info[shipp->ai_index];
4254 // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4255 target_objp = multi_get_network_object( target_signature );
4256 if ( target_objp == NULL ) {
4260 targeted_subsys = NULL;
4261 if ( t_subsys != -1 ) {
4262 Assert( target_objp != NULL );
4263 targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4266 // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4268 tobjnum_save = aip->target_objnum;
4269 tsubsys_save = aip->targeted_subsys;
4271 if ( target_objp ) {
4272 aip->target_objnum = OBJ_INDEX(target_objp);
4274 aip->target_objnum = -1;
4277 aip->targeted_subsys = targeted_subsys;
4279 if ( type == SQUAD_MSG_SHIP ) {
4280 hud_squadmsg_send_ship_command(index, command, 1, player_num);
4281 } else if ( type == SQUAD_MSG_WING ) {
4282 hud_squadmsg_send_wing_command(index, command, 1, player_num);
4283 } else if ( type == SQUAD_MSG_ALL ) {
4284 hud_squadmsg_send_to_all_fighters( command, player_num );
4287 Assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4288 aip->target_objnum = tobjnum_save;
4289 aip->targeted_subsys = tsubsys_save;
4292 // FILE SIGNATURE stuff :
4293 // there are 2 cases for file signature sending which are handled very differently
4294 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4295 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4296 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4297 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4298 // would have to keep track of up to potentially 14 other ack handles (ouch).
4299 void send_file_sig_packet(ushort sum_sig,int length_sig)
4301 ubyte data[MAX_PACKET_SIZE];
4302 int packet_size = 0;
4304 BUILD_HEADER(FILE_SIG_INFO);
4306 ADD_DATA(length_sig);
4308 multi_io_send_reliable(Net_player, data, packet_size);
4311 void process_file_sig_packet(ubyte *data, header *hinfo)
4316 offset = HEADER_LENGTH;
4318 // should only be received on the server-side
4319 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4322 GET_DATA(length_sig);
4324 server_verify_filesig(hinfo->id, sum_sig, length_sig);
4327 void send_file_sig_request(char *file_name)
4329 ubyte data[MAX_PACKET_SIZE];
4330 int packet_size = 0;
4332 BUILD_HEADER(FILE_SIG_REQUEST);
4333 ADD_STRING(file_name);
4335 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4337 multi_io_send_to_all_reliable(data, packet_size);
4340 void process_file_sig_request(ubyte *data, header *hinfo)
4342 int offset = HEADER_LENGTH;
4344 // get the mission name
4345 GET_STRING(Netgame.mission_name);
4348 // set the current mission filename
4349 strcpy(Game_current_mission_filename,Netgame.mission_name);
4352 multi_get_mission_checksum(Game_current_mission_filename);
4354 if(!multi_endgame_ending()){
4355 // reply to the server
4356 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
4360 // functions to deal with subsystems getting whacked
4361 void send_subsystem_destroyed_packet( ship *shipp, int index, vector world_hitpos )
4363 ubyte data[MAX_PACKET_SIZE];
4366 vector tmp, local_hitpos;
4369 Assert ( index < UCHAR_MAX );
4370 uindex = (ubyte)(index);
4372 objp = &Objects[shipp->objnum];
4374 vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4375 vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4377 BUILD_HEADER(SUBSYSTEM_DESTROYED);
4378 ADD_DATA( Objects[shipp->objnum].net_signature );
4380 ADD_DATA( local_hitpos );
4382 multi_io_send_to_all_reliable(data, packet_size);
4385 void process_subsystem_destroyed_packet( ubyte *data, header *hinfo )
4391 vector local_hit_pos, world_hit_pos;
4393 offset = HEADER_LENGTH;
4395 GET_DATA( signature );
4397 GET_DATA( local_hit_pos );
4399 // get the network object. process it if we find it.
4400 objp = multi_get_network_object( signature );
4401 if ( objp != NULL ) {
4403 ship_subsys *subsysp;
4405 // be sure we have a ship!!!
4406 // Assert ( objp->type == OBJ_SHIP );
4407 if(objp->type != OBJ_SHIP){
4412 shipp = &Ships[objp->instance];
4414 // call to get the pointer to the subsystem we should be working on
4415 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4416 vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4417 vm_vec_add2( &world_hit_pos, &objp->pos );
4419 do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4420 if ( objp == Player_obj ) {
4421 hud_gauge_popup_start(HUD_DAMAGE_GAUGE, 5000);
4429 // packet to tell clients cargo of a ship was revealed to all
4430 void send_subsystem_cargo_revealed_packet( ship *shipp, int index )
4432 ubyte data[MAX_PACKET_SIZE], uindex;
4435 Assert ( index < UCHAR_MAX );
4436 uindex = (ubyte)(index);
4438 // build the header and add the data
4439 BUILD_HEADER(SUBSYS_CARGO_REVEALED);
4440 ADD_DATA( Objects[shipp->objnum].net_signature );
4443 // server sends to all players
4444 if(MULTIPLAYER_MASTER){
4445 multi_io_send_to_all_reliable(data, packet_size);
4447 // clients just send to the server
4449 multi_io_send_reliable(Net_player, data, packet_size);
4453 // process a subsystem cargo revealed packet
4454 void process_subsystem_cargo_revealed_packet( ubyte *data, header *hinfo )
4461 ship_subsys *subsysp;
4463 offset = HEADER_LENGTH;
4464 GET_DATA( signature );
4468 // get a ship pointer and call the ship function to reveal the cargo
4469 objp = multi_get_network_object( signature );
4470 if ( objp == NULL ) {
4471 nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4475 // Assert( objp->type == OBJ_SHIP );
4476 if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4480 shipp = &Ships[objp->instance];
4482 // call to get the pointer to the subsystem we should be working on
4483 subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4484 if (subsysp == NULL) {
4485 nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4489 // this will take care of re-routing to all other clients
4490 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network );
4491 ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4493 // server should rebroadcast
4494 if(MULTIPLAYER_MASTER){
4495 send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4499 void send_netplayer_load_packet(net_player *pl)
4501 ubyte data[MAX_PACKET_SIZE];
4502 int packet_size = 0;
4504 BUILD_HEADER(LOAD_MISSION_NOW);
4505 ADD_STRING(Netgame.mission_name);
4508 multi_io_send_to_all_reliable(data, packet_size);
4510 multi_io_send_reliable(pl, data, packet_size);
4514 void process_netplayer_load_packet(ubyte *data, header *hinfo)
4517 int offset = HEADER_LENGTH;
4522 strcpy(Netgame.mission_name,str);
4523 strcpy(Game_current_mission_filename,str);
4524 if(!Multi_mission_loaded){
4526 // MWA 2/3/98 -- ingame join changes!!!
4527 // everyone can go through the same mission loading path here!!!!
4528 nprintf(("Network","Loading mission..."));
4530 // notify everyone that I'm loading the mission
4531 Net_player->state = NETPLAYER_STATE_MISSION_LOADING;
4532 send_netplayer_update_packet();
4534 // do the load itself
4535 game_start_mission();
4537 // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4538 // code will remark the correct player ships
4539 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4540 multi_untag_player_ships();
4543 Net_player->flags |= NETINFO_FLAG_MISSION_OK;
4544 Net_player->state = NETPLAYER_STATE_MISSION_LOADED;
4545 send_netplayer_update_packet();
4547 Multi_mission_loaded = 1;
4548 nprintf(("Network","Finished loading mission\n"));
4552 void send_jump_into_mission_packet(net_player *pl)
4554 ubyte data[MAX_PACKET_SIZE];
4555 int packet_size = 0;
4557 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
4559 BUILD_HEADER(JUMP_INTO_GAME);
4561 // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4562 // and possible other things.
4564 if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4565 ADD_DATA(Netgame.game_state);
4571 multi_io_send_to_all_reliable(data, packet_size);
4573 // send to a specific player
4575 multi_io_send_reliable(pl, data, packet_size);
4579 void process_jump_into_mission_packet(ubyte *data, header *hinfo)
4581 int offset = HEADER_LENGTH;
4586 // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4587 // the game could be paused, so ingame joiner needs to deal with it.
4588 if ( Net_player->flags & NETINFO_FLAG_INGAME_JOIN ) {
4590 Netgame.game_state = state;
4595 // handle any special processing for being in a weird substate
4596 multi_handle_state_special();
4598 // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4599 if(Net_player->flags & NETINFO_FLAG_INGAME_JOIN){
4600 if(Net_player->flags & NETINFO_FLAG_OBSERVER){
4601 multi_ingame_observer_finish();
4603 gameseq_post_event(GS_EVENT_INGAME_PRE_JOIN);
4604 Net_player->state = NETPLAYER_STATE_INGAME_SHIP_SELECT;
4605 send_netplayer_update_packet();
4608 // start the mission!!
4609 if(!(Game_mode & GM_IN_MISSION) && !(Game_mode & GM_STANDALONE_SERVER)){
4610 Netgame.game_state = NETGAME_STATE_IN_MISSION;
4611 gameseq_post_event(GS_EVENT_ENTER_GAME);
4612 Net_player->state = NETPLAYER_STATE_IN_MISSION;
4613 send_netplayer_update_packet();
4617 extern int Player_multi_died_check;
4618 Player_multi_died_check = -1;
4620 // recalc all object pairs now
4621 extern void obj_reset_all_collisions();
4622 obj_reset_all_collisions();
4624 // display some cool text
4625 multi_common_add_text(XSTR("Received mission start\n",720),1);
4628 ml_string(NOX("Client received mission start from server - entering mission"));
4633 char *repair_text[] = {
4635 "REPAIR_INFO_BEGIN",
4637 "REPAIR_INFO_UPDATE",
4638 "REPAIR_INFO_QUEUE",
4639 "REPAIR_INFO_ABORT",
4640 "REPAIR_INFO_BROKEN",
4641 "REPAIR_INFO_WARP_ADD",
4642 "REPAIR_INFO_WARP_REMOVE",
4643 "REPAIR_INFO_ONWAY",
4644 "REPAIR_INFO_KILLED",
4645 "REPAIR_INFO_COMPLETE",
4650 // the following two routines deal with updating and sending information regarding players
4651 // rearming and repairing during the game. The process function calls the routines to deal with
4652 // setting flags and other interesting things.
4653 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4655 int packet_size = 0;
4656 ushort repaired_signature, repair_signature;
4657 ubyte data[MAX_PACKET_SIZE];
4660 // use the network signature of the destination object if there is one, -1 otherwise.
4661 // client will piece it all together
4662 repaired_signature = repaired_objp->net_signature;
4664 // the repair ship may be NULL here since it might have been destroyed
4665 repair_signature = 0;
4667 repair_signature = repair_objp->net_signature;
4670 BUILD_HEADER(CLIENT_REPAIR_INFO);
4673 ADD_DATA( repaired_signature );
4674 ADD_DATA( repair_signature );
4676 multi_io_send_to_all_reliable(data, packet_size);
4678 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));
4681 void process_repair_info_packet(ubyte *data, header *hinfo)
4683 int offset = HEADER_LENGTH;
4684 ushort repaired_signature, repair_signature;
4685 object *repaired_objp, *repair_objp;
4689 GET_DATA( repaired_signature );
4690 GET_DATA( repair_signature );
4693 repaired_objp = multi_get_network_object( repaired_signature );
4694 repair_objp = multi_get_network_object( repair_signature );
4696 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));
4698 if ( Net_player->flags & NETINFO_FLAG_WARPING_OUT ){
4702 if ( repaired_objp == NULL ) {
4703 Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4707 // the hope is to simply call the routine in the ai code to set/unset flags
4708 // based on the code value and everything else should happen..I hope....
4709 if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4711 ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4713 // set the dock flags when repair begins. Prevents problem in lagging docking
4714 // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4716 if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4717 ai_do_objects_docked_stuff( repaired_objp, repair_objp );
4718 Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4721 // if the repair is done (either by abort, or ending), mark the repair ship's goal
4723 if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4724 ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4727 if ( code == REPAIR_INFO_WARP_ADD ){
4728 mission_warp_in_support_ship( repaired_objp );
4730 mission_remove_scheduled_repair( repaired_objp );
4735 // sends information updating clients on certain AI information that clients will
4736 // need to know about to keep HUD information up to date. objp is the object that we
4737 // are updating, and what is the type of stuff that we are updating.
4738 void send_ai_info_update_packet( object *objp, char what )
4741 ushort other_signature;
4742 ubyte data[MAX_PACKET_SIZE];
4744 ubyte dock_index, dockee_index;
4746 // Assert( objp->type == OBJ_SHIP );
4747 if(objp->type != OBJ_SHIP){
4750 aip = &Ai_info[Ships[objp->instance].ai_index];
4753 if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4756 BUILD_HEADER( AI_INFO_UPDATE );
4757 ADD_DATA( objp->net_signature );
4760 // depending on the "what" value, we will send different information
4764 case AI_UPDATE_DOCK:
4765 // for docking ships, add the signature of the ship that we are docking with.
4766 Assert( aip->dock_objnum != -1 );
4767 other_signature = Objects[aip->dock_objnum].net_signature;
4768 dock_index = (ubyte)(aip->dock_index);
4769 dockee_index = (ubyte)(aip->dockee_index);
4770 ADD_DATA( other_signature );
4771 ADD_DATA(dock_index);
4772 ADD_DATA(dockee_index);
4775 case AI_UPDATE_UNDOCK:
4776 // for undocking ships, check the dock_objnum since we might or might not have it
4777 // depending on whether or not a ship was destroyed while we were docked.
4778 other_signature = 0;
4779 if ( aip->dock_objnum != -1 )
4780 other_signature = Objects[aip->dock_objnum].net_signature;
4781 ADD_DATA( other_signature );
4785 case AI_UPDATE_ORDERS: {
4788 // for orders, we only need to send a little bit of information here. Be sure that the
4789 // first order for this ship is active
4790 Assert( (aip->active_goal != AI_GOAL_NONE) && (aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) );
4791 ADD_DATA( aip->goals[0].ai_mode );
4792 ADD_DATA( aip->goals[0].ai_submode );
4794 if ( aip->goals[0].ship_name != NULL )
4795 shipnum = ship_name_lookup( aip->goals[0].ship_name );
4797 // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
4798 // have a valid shipnum, then don't sweat it since it may not really be a ship.
4799 if ( shipnum != -1 ) {
4800 Assert( Ships[shipnum].objnum != -1 );
4801 other_signature = Objects[Ships[shipnum].objnum].net_signature;
4803 other_signature = 0;
4805 ADD_DATA( other_signature );
4807 // for docking, add the dock and dockee index
4808 if ( aip->goals[0].ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4809 Assert( (aip->goals[0].docker.index >= 0) && (aip->goals[0].docker.index < UCHAR_MAX) );
4810 Assert( (aip->goals[0].dockee.index >= 0) && (aip->goals[0].dockee.index < UCHAR_MAX) );
4811 dock_index = (ubyte)aip->goals[0].docker.index;
4812 dockee_index = (ubyte)aip->goals[0].dockee.index;
4813 ADD_DATA( dock_index );
4814 ADD_DATA( dockee_index );
4823 multi_rate_add(1, "aiu", packet_size);
4824 multi_io_send_to_all_reliable(data, packet_size);
4827 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
4828 // information is mainly used to keep the clients HUD up to date with the appropriate information.
4829 void process_ai_info_update_packet( ubyte *data, header *hinfo)
4831 int offset = HEADER_LENGTH;
4833 ushort net_signature, other_net_signature;
4834 object *objp, *other_objp;
4837 ubyte dock_index = 0, dockee_index = 0;
4839 GET_DATA( net_signature ); // signature of the object that we are dealing with.
4840 GET_DATA( code ); // code of what we are doing.
4841 objp = multi_get_network_object( net_signature );
4843 nprintf(("Network", "Couldn't find object for ai update\n"));
4846 case AI_UPDATE_DOCK:
4847 GET_DATA( other_net_signature );
4848 GET_DATA( dock_index );
4849 GET_DATA( dockee_index );
4850 other_objp = multi_get_network_object( other_net_signature );
4852 nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
4854 // if we don't have an object to work with, break out of loop
4855 if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
4859 Assert( other_objp->type == OBJ_SHIP );
4860 Ai_info[Ships[objp->instance].ai_index].dock_index = dock_index;
4861 Ai_info[Ships[objp->instance].ai_index].dockee_index = dockee_index;
4863 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4864 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4866 ai_do_objects_docked_stuff( objp, other_objp );
4869 case AI_UPDATE_UNDOCK:
4870 GET_DATA( other_net_signature );
4871 other_objp = multi_get_network_object( other_net_signature );
4873 // if we don't have an object to work with, break out of loop
4877 ai_do_objects_undocked_stuff( objp, other_objp );
4880 case AI_UPDATE_ORDERS:
4882 GET_DATA( submode );
4883 GET_DATA( other_net_signature );
4884 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4885 GET_DATA(dock_index);
4886 GET_DATA(dockee_index);
4889 // be sure that we have a ship object!!!
4890 if ( !objp || (objp->type != OBJ_SHIP) )
4893 // set up the information in the first goal element of the object in question
4894 aip = &Ai_info[Ships[objp->instance].ai_index];
4895 aip->active_goal = 0;
4896 aip->goals[0].ai_mode = mode;
4897 aip->goals[0].ai_submode = submode;
4899 // for docking, add the dock and dockee index
4900 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4901 aip->dock_index = dock_index;
4902 aip->dockee_index = dockee_index;
4905 // get a shipname if we can.
4906 other_objp = multi_get_network_object( other_net_signature );
4907 if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
4908 // get a pointer to the shipname in question. Use the ship_name value in the
4909 // ship. We are only using this for HUD display, so I think that using this
4910 // method will be fine.
4911 aip->goals[0].ship_name = Ships[other_objp->instance].ship_name;
4913 // special case for destroy subsystem -- get the ai_info pointer to our target ship
4914 // so that we can properly set up what subsystem this ship is attacking.
4915 if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
4916 aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
4918 // if docking -- set the dock index and dockee index of this other ship
4919 if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
4920 Ai_info[Ships[other_objp->instance].ai_index].dock_index = dockee_index;
4921 Ai_info[Ships[other_objp->instance].ai_index].dockee_index = dock_index;
4928 Int3(); // this Int3() should be temporary
4929 nprintf(("Network", "Invalid code for ai update: %d\n", code));
4935 // tell the standalone to move into the MISSION_SYNC_STATE
4936 void send_mission_sync_packet(int mode,int start_campaign)
4938 ubyte data[MAX_PACKET_SIZE],is_campaign;
4939 int packet_size = 0;
4941 Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
4943 // build the header and add the sync mode (pre or post briefing)
4944 BUILD_HEADER(MISSION_SYNC_DATA);
4947 // if this is a campaign game
4948 if(mode == MULTI_SYNC_PRE_BRIEFING){
4949 if(Game_mode & GM_CAMPAIGN_MODE){
4950 // add a byte indicating campaign mode
4952 ADD_DATA(is_campaign);
4954 // add a byte indicating if we should be starting a campaign or continuing it
4955 is_campaign = (ubyte)start_campaign;
4956 ADD_DATA(is_campaign);
4958 // add the campaign filename
4959 ADD_STRING(Netgame.campaign_name);
4961 // otherwise if this is a single mission
4963 // add a byte indicating single mission mode
4965 ADD_DATA(is_campaign);
4967 // add the mission filename
4968 ADD_STRING(Game_current_mission_filename);
4971 multi_io_send_reliable(Net_player, data, packet_size);
4974 // move into the MISSION_SYNC state when this is received
4975 // this packet is sent only from a game host to a standalone
4976 void process_mission_sync_packet(ubyte *data, header *hinfo)
4979 ubyte campaign_flag;
4980 int offset = HEADER_LENGTH;
4982 Assert(Game_mode & GM_STANDALONE_SERVER);
4984 // if this is a team vs team situation, lock the players send a final team update
4985 if(Netgame.type_flags & NG_TYPE_TEAM){
4986 multi_team_host_lock_all();
4987 multi_team_send_update();
4990 // get the sync mode (pre or post briefing)
4993 if(mode == MULTI_SYNC_PRE_BRIEFING){
4994 // get the flag indicating if this is a single mission or a campaign mode
4995 GET_DATA(campaign_flag);
4997 // get the flag indicating whether we should be starting a new campaign
4998 GET_DATA(campaign_flag);
5000 // get the campaign filename
5001 GET_STRING(Netgame.campaign_name);
5003 // either start a new campaign or continue on to the next mission in the current campaign
5005 multi_campaign_start(Netgame.campaign_name);
5007 multi_campaign_next_mission();
5010 // make sure we remove the campaign mode flag
5011 Game_mode &= ~(GM_CAMPAIGN_MODE);
5013 // get the single mission filename
5014 GET_STRING(Game_current_mission_filename);
5015 strcpy(Netgame.mission_name,Game_current_mission_filename);
5020 // set the correct mode and m ove into the state
5021 Multi_sync_mode = mode;
5022 gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);
5025 // tell a player to merge his mission stats into his alltime stats
5026 void send_store_stats_packet(int accept)
5029 int packet_size = 0;
5031 BUILD_HEADER(STORE_MISSION_STATS);
5033 // add whether we're accepting or tossing
5034 val = (ubyte)accept;
5037 // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5038 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5039 multi_io_send_to_all_reliable(data, packet_size);
5041 multi_io_send_reliable(Net_player, data, packet_size);
5045 void process_store_stats_packet(ubyte *data, header *hinfo)
5047 int offset = HEADER_LENGTH;
5053 // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5054 if(Game_mode & GM_STANDALONE_SERVER){
5055 // rebroadcast the packet to all others in the game
5056 nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5057 multi_io_send_to_all_reliable(data, offset);
5060 // all players should mark the stats as being accepted in the debriefing
5061 multi_debrief_stats_accept();
5063 // all players should mark the stats as being "tossed" in the debriefing
5064 multi_debrief_stats_toss();
5069 void send_debris_update_packet(object *objp,int code)
5071 ubyte data[MAX_PACKET_SIZE];
5073 int packet_size = 0;
5075 BUILD_HEADER(DEBRIS_UPDATE);
5076 ADD_DATA(objp->net_signature);
5080 // add any extra relevant data
5082 case DEBRIS_UPDATE_UPDATE:
5083 ADD_DATA(objp->pos); // add position
5084 ADD_ORIENT(objp->orient); // add orientation
5085 ADD_DATA(objp->phys_info.vel); // add velocity
5086 ADD_DATA(objp->phys_info.rotvel); // add rotational velocity
5089 multi_io_send_to_all(data, packet_size);
5092 void process_debris_update_packet(ubyte *data, header *hinfo)
5096 object bogus_object;
5098 int offset = HEADER_LENGTH;
5104 objp = multi_get_network_object(net_sig);
5106 objp = &bogus_object;
5110 // update the object
5111 case DEBRIS_UPDATE_UPDATE:
5112 GET_DATA(objp->pos);
5113 GET_ORIENT(objp->orient);
5114 GET_DATA(objp->phys_info.vel);
5115 GET_DATA(objp->phys_info.rotvel);
5117 // simply remove it (no explosion)
5118 case DEBRIS_UPDATE_REMOVE:
5119 if(objp != &bogus_object){
5120 Assert(objp->type == OBJ_DEBRIS);
5121 obj_delete(OBJ_INDEX(objp));
5125 case DEBRIS_UPDATE_NUKE:
5126 if(objp != &bogus_object)
5127 debris_hit(objp,NULL,&objp->pos,1000000.0f);
5135 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)
5137 ubyte data[MAX_PACKET_SIZE];
5139 int packet_size = 0;
5141 BUILD_HEADER(WSS_REQUEST_PACKET);
5143 // add the request information
5144 ADD_DATA(player_id);
5145 ADD_DATA(from_slot);
5146 ADD_DATA(from_index);
5149 ADD_DATA(wl_ship_slot); // only used in weapons loadout
5150 ADD_DATA(ship_class);
5153 // a standard request
5155 multi_io_send_reliable(Net_player, data, packet_size);
5157 // being routed through the standalone to the host of the game
5159 Assert(Game_mode & GM_STANDALONE_SERVER);
5160 multi_io_send_reliable(p, data, packet_size);
5164 void process_wss_request_packet(ubyte *data, header *hinfo)
5166 int offset = HEADER_LENGTH;
5167 int from_slot,from_index;
5168 int to_slot,to_index;
5170 int wl_ship_slot,ship_class;
5174 // determine who this request is from
5175 GET_DATA(player_id);
5176 player_num = find_player_id(player_id);
5178 // read in the request data
5179 GET_DATA(from_slot);
5180 GET_DATA(from_index);
5183 GET_DATA(wl_ship_slot); // only used in weapons loadout
5184 GET_DATA(ship_class); // only used in multi team select
5188 Assert(player_num != -1);
5189 if(player_num == -1){
5193 // if we're the standalone, we have to route this packet to the host of the game
5194 if(Game_mode & GM_STANDALONE_SERVER){
5195 send_wss_request_packet(player_id, from_slot, from_index, to_slot, to_index, wl_ship_slot, ship_class, mode, Netgame.host);
5197 // otherwise we're the host and should process the request
5200 case WSS_WEAPON_SELECT :
5201 wl_drop(from_slot,from_index,to_slot,to_index,wl_ship_slot,player_num);
5203 case WSS_SHIP_SELECT :
5204 multi_ts_drop(from_slot,from_index,to_slot,to_index,ship_class,player_num);
5212 void send_wss_update_packet(int team_num,ubyte *wss_data,int size)
5214 ubyte data[MAX_PACKET_SIZE],team;
5215 int packet_size = 0;
5217 Assert(size <= (MAX_PACKET_SIZE - 10));
5219 BUILD_HEADER(WSS_UPDATE_PACKET);
5221 // add the team/pool # this is for
5222 team = (ubyte)team_num;
5225 // add the data block size
5228 // add the data itself
5229 memcpy(data + packet_size,wss_data,size);
5230 packet_size += size;
5232 // if we're also the master of the game (not on a standalone)
5233 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5234 multi_io_send_to_all_reliable(data, packet_size);
5236 // if we're only the host on the standalone, then send the packet to the standalone to be routed
5238 multi_io_send_reliable(Net_player, data, packet_size);
5242 void process_wss_update_packet(ubyte *data, header *hinfo)
5245 int size,player_index,idx;
5246 int offset = HEADER_LENGTH;
5248 // get the team/pool #
5251 // get the data size
5254 // if we're the standalone, then we should be routing this data to all the other clients
5255 if(Game_mode & GM_STANDALONE_SERVER){
5260 // determine where this came from
5261 player_index = find_player_id(hinfo->id);
5262 Assert(player_index != -1);
5263 if(player_index < 0){
5267 // route the packet (don't resend it to the host)
5268 for(idx=0;idx<MAX_PLAYERS;idx++){
5269 if(MULTI_CONNECTED(Net_players[idx]) && (&Net_players[idx] != Net_player) && (&Net_players[idx] != &Net_players[player_index]) ){
5270 multi_io_send_reliable(&Net_players[idx], data, offset);
5274 // set the proper pool pointers
5275 ss_set_team_pointers((int)team);
5277 // read in the block of data, and apply it to the weapons/ship pools
5278 offset += restore_wss_data(data + offset);
5281 // set the pool pointers back to my own team
5282 ss_set_team_pointers(Net_player->p_info.team);
5284 // sync the interface if this was for my own team
5285 if((int)team == Net_player->p_info.team){
5286 multi_ts_sync_interface();
5293 // function to send firing information from the client to the server once they reach
5294 // the final sync screen.
5295 void send_firing_info_packet()
5297 ubyte data[MAX_PACKET_SIZE];
5299 ubyte plinked, sdual;
5301 Assert( !(Net_player->flags & NETINFO_FLAG_AM_MASTER) );
5303 BUILD_HEADER(FIRING_INFO);
5304 plinked = (ubyte)((Player_ship->flags & SF_PRIMARY_LINKED)?1:0);
5305 sdual = (ubyte)((Player_ship->flags & SF_SECONDARY_DUAL_FIRE)?1:0);
5306 ADD_DATA( plinked );
5309 multi_io_send_reliable(Net_player, data, packet_size);
5312 void process_firing_info_packet( ubyte *data, header *hinfo )
5314 int offset, player_num;
5315 ubyte plinked, sdual;
5318 // only the master of the game should be dealing with these packets
5319 Assert( Net_player->flags & NETINFO_FLAG_AM_MASTER );
5321 offset = HEADER_LENGTH;
5322 GET_DATA( plinked );
5326 player_num = find_player_id(hinfo->id);
5328 nprintf(("Network","Received firing info packet from unknown player, ignoring\n"));
5332 // get the ship pointer for this player and set the flags accordingly.
5333 shipp = &(Ships[Objects[Net_players[player_num].player->objnum].instance]);
5335 shipp->flags |= SF_PRIMARY_LINKED;
5337 shipp->flags &= ~SF_PRIMARY_LINKED;
5340 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5342 shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
5345 // packet to deal with changing status of mission goals. used to be sent every so often from server
5346 // to clients, but with addition of reliable sockets, send when complete, invalid, etc.
5347 // goal_num is the index into mission_goals. new_status means failed, success, etc. -1 if not used.
5348 // valid means goal is changing to invalid(0) or valid(1). only applies if new_status == -1
5349 void send_mission_goal_info_packet( int goal_num, int new_status, int valid )
5351 ubyte data[MAX_PACKET_SIZE];
5354 BUILD_HEADER(MISSION_GOAL_INFO);
5357 ADD_DATA(new_status);
5360 multi_io_send_to_all_reliable(data, packet_size);
5363 void process_mission_goal_info_packet( ubyte *data, header *hinfo )
5365 int offset, goal_num, new_status, valid;
5367 offset = HEADER_LENGTH;
5369 GET_DATA(new_status);
5373 // if new_status != -1, then this is a change in goal status (i.e. goal failed, or is successful)
5374 if ( new_status != -1 ){
5375 mission_goal_status_change( goal_num, new_status );
5377 mission_goal_validation_change( goal_num, valid );
5381 void send_player_settings_packet(net_player *p)
5383 ubyte data[MAX_PACKET_SIZE];
5386 int packet_size = 0;
5389 BUILD_HEADER(PLAYER_SETTINGS);
5391 // add all the data for all the players
5393 for(idx=0;idx<MAX_PLAYERS;idx++){
5394 if(MULTI_CONNECTED(Net_players[idx])){
5396 ADD_DATA(Net_players[idx].player_id);
5398 // break the p_info structure by member, so we don't overwrite any absolute pointers
5399 // ADD_DATA(Net_players[idx].p_info);
5400 ADD_DATA(Net_players[idx].p_info.team);
5401 ADD_DATA(Net_players[idx].p_info.ship_index);
5402 ADD_DATA(Net_players[idx].p_info.ship_class);
5405 // add the stop byte
5409 // either broadcast the data or send to a specific player
5411 multi_io_send_to_all_reliable(data, packet_size);
5413 multi_io_send_reliable(p, data, packet_size);
5417 void process_player_settings_packet(ubyte *data, header *hinfo)
5419 int offset,player_num;
5420 net_player_info bogus,*ptr;
5424 offset = HEADER_LENGTH;
5426 // read in the data for all the players
5428 while(stop != 0xff){
5429 // lookup the player
5430 GET_DATA(player_id);
5431 player_num = find_player_id(player_id);
5433 // make sure this is a valid player
5434 if(player_num == -1){
5437 ptr = &Net_players[player_num].p_info;
5440 GET_DATA(ptr->team);
5441 GET_DATA(ptr->ship_index);
5442 GET_DATA(ptr->ship_class);
5449 // update the server with my new state
5450 // MWA -- 3/31/98 -- check for in mission instead of state.
5451 //if ( Netgame.game_state == NETGAME_STATE_MISSION_SYNC) {
5452 if( !(Game_mode & GM_IN_MISSION) ) {
5453 Net_player->state = NETPLAYER_STATE_SETTINGS_ACK;
5454 send_netplayer_update_packet();
5458 // display some cool text
5459 multi_common_add_text(XSTR("Received player settings packet\n",721),1);
5462 void send_deny_packet(net_addr *addr, int code)
5465 int packet_size = 0;
5467 // build the header and add the rejection code
5473 psnet_send(addr, data, packet_size);
5476 void process_deny_packet(ubyte *data, header *hinfo)
5480 // get the denial code
5481 offset = HEADER_LENGTH;
5485 // if there is already a dialog active, do nothing - who cares at this point.
5490 // display the appropriate dialog
5492 case JOIN_DENY_JR_STATE :
5493 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));
5495 case JOIN_DENY_JR_TRACKER_INVAL :
5496 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));
5498 case JOIN_DENY_JR_PASSWD :
5499 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this is a password protected game",724));
5501 case JOIN_DENY_JR_CLOSED :
5502 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));
5504 case JOIN_DENY_JR_TEMP_CLOSED :
5505 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));
5507 case JOIN_DENY_JR_RANK_HIGH :
5508 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));
5510 case JOIN_DENY_JR_RANK_LOW :
5511 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));
5513 case JOIN_DENY_JR_DUP :
5514 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because there is an identical player already in the game",729));
5516 case JOIN_DENY_JR_FULL :
5517 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because the game is full",730));
5519 case JOIN_DENY_JR_BANNED :
5520 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because you are banned from this server",731));
5522 case JOIN_DENY_JR_NOOBS :
5523 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been rejected because this game does not allow observers",732));
5525 case JOIN_DENY_JR_INGAME_JOIN :
5526 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));
5528 case JOIN_DENY_JR_BAD_VERSION :
5529 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));
5531 case JOIN_DENY_JR_TYPE :
5532 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You cannot join a game in progress unless it is a dogfight mission.",1433));
5536 // call this so that the join request timestamp automatically expires when we hear back from the server
5537 multi_join_reset_join_stamp();
5540 // this packet will consist of
5541 // 1.) netplayer ship classes (85 bytes max)
5542 // 2.) ship weapon state data (241 bytes max)
5543 // 3.) player settings et. al. (133 bytes max)
5544 // TOTAL 459 NOTE : keep this in mind when/if adding new data to this packet
5545 void send_post_sync_data_packet(net_player *p, int std_request)
5547 ubyte data[MAX_PACKET_SIZE], val;
5552 ushort sval, ship_ets;
5553 int idx, player_index;
5554 int packet_size = 0;
5558 BUILD_HEADER(POST_SYNC_DATA);
5560 // some header information for standalone packet routing purposes
5561 val = (ubyte)std_request;
5564 // the standalone has two situations
5565 // 1.) sending a request to the host to distribute this block of data
5566 // 2.) having recevied this block of data from the host, it redistributes it
5567 if((Game_mode & GM_STANDALONE_SERVER) && std_request && (Netgame.host != NULL)){
5568 // case 1, send the request
5569 multi_io_send_reliable(Netgame.host, data, packet_size);
5572 // case 2 for the standalone is below (as normal)
5574 // otherwise build the data now
5576 // add all deleted ships
5577 val = (ubyte)Multi_ts_num_deleted;
5579 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5580 sval = (ushort)Objects[Multi_ts_deleted_objnums[idx]].net_signature;
5586 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5587 shipp = &Ships[Objects[so->objnum].instance];
5589 // don't process non player wing ships
5590 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5596 // # of ships - used multiple times in the packet
5597 val = (ubyte)ship_count;
5600 // add ship class information (85 bytes max)
5601 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5602 shipp = &Ships[Objects[so->objnum].instance];
5604 // don't process non player wing ships
5605 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5608 // add the net signature of the object for look up
5609 ADD_DATA( Objects[so->objnum].net_signature );
5611 // add the ship info index
5612 val = (ubyte)(shipp->ship_info_index);
5615 // add the ships's team select index
5616 val = (ubyte)shipp->ts_index;
5620 // add weapon state information for all starting ships (241 bytes max)
5621 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5622 shipp = &Ships[Objects[so->objnum].instance];
5624 // don't process non player wing ships
5625 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5628 // if this is a ship owned by a player, we should mark down his weapons bank/link settings now if we're the server
5630 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5631 player_index = multi_find_player_by_net_signature(Objects[so->objnum].net_signature);
5632 if(player_index == -1){
5635 pl = &Net_players[player_index];
5639 // add the net signature and other weapon information
5640 ADD_DATA( Objects[so->objnum].net_signature );
5642 // add number of primary and secondary banks
5643 bval = (char)(shipp->weapons.num_primary_banks);
5645 bval = (char)(shipp->weapons.num_secondary_banks);
5648 // add weapon bank status
5649 bval = (char)(shipp->weapons.current_primary_bank);
5651 pl->s_info.cur_primary_bank = bval;
5653 // Assert(bval != -1);
5656 bval = (char)(shipp->weapons.current_secondary_bank);
5658 pl->s_info.cur_secondary_bank = bval;
5660 // Assert(bval != -1);
5663 // primary weapon info
5664 bval = (char)(shipp->weapons.primary_bank_weapons[0]);
5666 bval = (char)(shipp->weapons.primary_bank_weapons[1]);
5669 // secondary weapon info
5670 bval = (char)(shipp->weapons.secondary_bank_weapons[0]);
5672 val_short = (short)(shipp->weapons.secondary_bank_ammo[0]);
5673 ADD_DATA(val_short);
5674 bval = (char)(shipp->weapons.secondary_bank_weapons[1]);
5676 val_short = (short)(shipp->weapons.secondary_bank_ammo[1]);
5677 ADD_DATA(val_short);
5678 bval = (char)(shipp->weapons.secondary_bank_weapons[2]);
5680 val_short = (short)(shipp->weapons.secondary_bank_ammo[2]);
5681 ADD_DATA(val_short);
5683 // send primary and secondary weapon link status
5685 if(shipp->flags & SF_PRIMARY_LINKED){
5687 pl->s_info.cur_link_status |= (1<<0);
5691 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
5693 pl->s_info.cur_link_status |= (1<<1);
5697 // if this is a player ship add (1<<2)
5698 if(Objects[shipp->objnum].flags & OF_PLAYER_SHIP){
5703 // add a ship ets value
5706 ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
5708 ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
5710 ship_ets |= ((ushort)shipp->engine_recharge_index);
5715 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5716 // or if I'm the server as well as the host, I should be sending this to all players
5717 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5718 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5721 multi_io_send_to_all_reliable(data, packet_size);
5723 // send to a specific player
5725 multi_io_send_reliable(p, data, packet_size);
5728 multi_io_send_reliable(Net_player, data, packet_size);
5735 multi_io_send_to_all_reliable(data, packet_size);
5737 // send to a specific player
5739 multi_io_send_reliable(p, data, packet_size);
5744 void process_post_sync_data_packet(ubyte *data, header *hinfo)
5746 ubyte val, sinfo_index, ts_index;
5748 ushort net_sig, ship_ets, sval;
5752 int offset = HEADER_LENGTH;
5756 // packet routing information
5759 // 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
5760 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
5763 // at this point we want to delete all necessary ships, change all necessary ship classes, and set all weapons up
5764 multi_ts_create_wings();
5766 // send to the standalone through my socket
5767 send_post_sync_data_packet(Net_player);
5773 // add all deleted ships
5775 Multi_ts_num_deleted = (int)val;
5776 for(idx=0;idx<Multi_ts_num_deleted;idx++){
5777 // get the ship's objnum
5780 objp = multi_get_network_object(sval);
5782 // delete the ship appropriately
5783 // mark the object as having been deleted
5784 Multi_ts_deleted_objnums[idx] = OBJ_INDEX(objp);
5787 ship_add_exited_ship(&Ships[objp->instance], SEF_PLAYER_DELETED);
5788 obj_delete(Multi_ts_deleted_objnums[idx]);
5789 ship_wing_cleanup(objp->instance,&Wings[Ships[objp->instance].wingnum]);
5791 Multi_ts_num_deleted--;
5792 nprintf(("Network","Couldn't find object by net signature for ship delete in post sync data packet\n"));
5800 // process ship class information
5801 for(idx=0; idx<ship_count; idx++){
5802 // get the object's net signature
5804 GET_DATA(sinfo_index);
5807 // attempt to get the object
5808 objp = multi_get_network_object(net_sig);
5810 // make sure we found a ship
5811 Assert((objp != NULL) && (objp->type == OBJ_SHIP));
5813 // set the ship to be the right class
5814 change_ship_type(objp->instance,(int)sinfo_index);
5816 // set the ship's team select index
5817 Ships[objp->instance].ts_index = (int)ts_index;
5820 // process ship weapon state info
5821 for(idx=0; idx<ship_count; idx++){
5822 // get the object's net signature
5825 // attempt to get the object
5826 objp = multi_get_network_object(net_sig);
5828 // make sure we found a ship
5829 Assert((objp != NULL) && (objp->type == OBJ_SHIP));
5831 // get a pointer to the ship
5832 shipp = &Ships[objp->instance];
5834 // get number of primary and secondary banks;
5837 shipp->weapons.num_primary_banks = (int)b;
5841 shipp->weapons.num_secondary_banks = (int)b;
5843 // get bank selection info
5848 shipp->weapons.current_primary_bank = (int)b;
5854 shipp->weapons.current_secondary_bank = (int)b;
5856 // primary weapon info
5858 shipp->weapons.primary_bank_weapons[0] = (int)b;
5861 shipp->weapons.primary_bank_weapons[1] = (int)b;
5863 // secondary weapon info
5865 shipp->weapons.secondary_bank_weapons[0] = (int)b;
5866 GET_DATA(val_short);
5867 shipp->weapons.secondary_bank_ammo[0] = (int)val_short;
5870 shipp->weapons.secondary_bank_weapons[1] = (int)b;
5871 GET_DATA(val_short);
5872 shipp->weapons.secondary_bank_ammo[1] = (int)val_short;
5875 shipp->weapons.secondary_bank_weapons[2] = (int)b;
5876 GET_DATA(val_short);
5877 shipp->weapons.secondary_bank_ammo[2] = (int)val_short;
5884 shipp->flags |= SF_PRIMARY_LINKED;
5887 shipp->flags |= SF_SECONDARY_DUAL_FIRE;
5889 Objects[shipp->objnum].flags &= ~(OF_PLAYER_SHIP);
5890 Objects[shipp->objnum].flags &= ~(OF_COULD_BE_PLAYER);
5892 Objects[shipp->objnum].flags |= OF_PLAYER_SHIP;
5894 obj_set_flags( &Objects[shipp->objnum], Objects[shipp->objnum].flags | OF_COULD_BE_PLAYER );
5900 shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8);
5902 shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4);
5904 shipp->engine_recharge_index = (ship_ets & 0x000f);
5909 Net_player->state = NETPLAYER_STATE_POST_DATA_ACK;
5910 send_netplayer_update_packet();
5912 // the standalone server will receive this packet from the host of the game, to be applied locally and
5913 // also to be rebroadcast.
5914 if(Game_mode & GM_STANDALONE_SERVER){
5915 // update player ets settings
5916 for(idx=0;idx<MAX_PLAYERS;idx++){
5917 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player->objnum != -1)){
5918 multi_server_update_player_weapons(&Net_players[idx],&Ships[Objects[Net_players[idx].player->objnum].instance]);
5922 send_post_sync_data_packet(NULL,0);
5926 void send_wss_slots_data_packet(int team_num,int final,net_player *p,int std_request)
5928 ubyte data[MAX_PACKET_SIZE],val;
5931 int packet_size = 0;
5934 BUILD_HEADER(WSS_SLOTS_DATA);
5936 // some header information for standalone packet routing purposes
5937 val = (ubyte)std_request;
5941 val = (ubyte)team_num;
5944 // add whether this is the final packet or not
5948 // the standalone has two situations
5949 // 1.) sending a request to the host to distribute this block of data
5950 // 2.) having recevied this block of data from the host, it redistributes it
5951 if((Game_mode & GM_STANDALONE_SERVER) && std_request){
5952 // case 1, send the request
5953 multi_io_send_reliable(Netgame.host, data, packet_size);
5956 // case 2 for the standalone is below (as normal)
5958 // add all the slots
5959 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
5960 // add the ship class
5961 val = (ubyte)Wss_slots_teams[team_num][idx].ship_class;
5965 for(i = 0;i<MAX_WL_WEAPONS;i++){
5966 val = (ubyte)Wss_slots_teams[team_num][idx].wep[i];
5970 // add the weapon counts
5971 for(i = 0;i<MAX_WL_WEAPONS;i++){
5972 val_short = (short)Wss_slots_teams[team_num][idx].wep_count[i];
5973 ADD_DATA(val_short);
5977 // 2 cases, if I'm the host on a standalone, I should be sending this to the standalone only
5978 // or if I'm the server as well as the host, I should be sending this to all players
5979 if(Net_player->flags & NETINFO_FLAG_GAME_HOST){
5980 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
5983 multi_io_send_to_all_reliable(data, packet_size);
5985 // send to a specific player
5987 multi_io_send_reliable(p, data, packet_size);
5990 multi_io_send_reliable(Net_player, data, packet_size);
5997 multi_io_send_to_all_reliable(data, packet_size);
5999 // send to a specific player
6001 multi_io_send_reliable(p, data, packet_size);
6006 void process_wss_slots_data_packet(ubyte *data, header *hinfo)
6008 ubyte val,team_num,final;
6010 int offset = HEADER_LENGTH;
6013 // packet routing information
6019 // get whether this is the final packet or not
6022 // 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
6023 if((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && val){
6026 // send to the standalone through my socket
6027 send_wss_slots_data_packet((int)team_num,(int)final,Net_player);
6031 // read in all the slot data
6032 for(idx=0;idx<MULTI_TS_NUM_SHIP_SLOTS;idx++){
6033 memset(&Wss_slots_teams[team_num][idx],0,sizeof(wss_unit));
6035 // get the ship class
6037 Wss_slots_teams[team_num][idx].ship_class = (int)val;
6040 for(i = 0;i<MAX_WL_WEAPONS;i++){
6042 Wss_slots_teams[team_num][idx].wep[i] = (int)val;
6044 // check for signed/unsigned problems
6045 if(Wss_slots_teams[team_num][idx].wep[i] == 255){
6046 Wss_slots_teams[team_num][idx].wep[i] = -1;
6050 // get the weapon counts
6051 for(i = 0;i<MAX_WL_WEAPONS;i++){
6052 GET_DATA(val_short);
6053 Wss_slots_teams[team_num][idx].wep_count[i] = (int)val_short;
6058 // update my netplayer state if this is the final packet
6060 Net_player->state = NETPLAYER_STATE_WSS_ACK;
6061 send_netplayer_update_packet();
6064 // the standalone server will receive this packet from the host of the game, to be applied locally and
6065 // also to be rebroadcast.
6066 if(Game_mode & GM_STANDALONE_SERVER){
6067 send_wss_slots_data_packet((int)team_num,(int)final,NULL,0);
6069 // add some mission sync text
6070 multi_common_add_text(XSTR("Weapon slots packet\n",735),1);
6074 #define OBJ_VISIBILITY_DOT 0.6f
6076 // send and receive packets for shield explosion information
6077 void send_shield_explosion_packet( int objnum, int tri_num, vector hit_pos )
6080 ubyte data[MAX_PACKET_SIZE], utri_num;
6083 // Assert(!(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE));
6085 Assert( tri_num < UCHAR_MAX );
6086 utri_num = (ubyte)tri_num;
6088 // for each player, determine if this object is behind the player -- if so, don't
6090 for ( i = 0; i < MAX_PLAYERS; i++ ) {
6091 if ( MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) ) {
6093 vector eye_to_obj_vec, diff, eye_pos;
6096 eye_pos = Net_players[i].s_info.eye_pos;
6097 eye_orient = Net_players[i].s_info.eye_orient;
6099 // check for same vectors
6100 vm_vec_sub(&diff, &Objects[objnum].pos, &eye_pos);
6101 if ( vm_vec_mag_quick(&diff) < 0.01 ){
6105 vm_vec_normalized_dir(&eye_to_obj_vec, &Objects[objnum].pos, &eye_pos);
6106 dot = vm_vec_dot(&eye_orient.fvec, &eye_to_obj_vec);
6108 if ( dot < OBJ_VISIBILITY_DOT ){
6112 BUILD_HEADER(SHIELD_EXPLOSION);
6114 ADD_DATA( Objects[objnum].net_signature );
6117 multi_io_send(&Net_players[i], data, packet_size);
6122 void add_shield_point_multi(int objnum, int tri_num, vector *hit_pos);
6124 void process_shield_explosion_packet( ubyte *data, header *hinfo)
6131 // get the shield hit data
6132 offset = HEADER_LENGTH;
6133 GET_DATA(signature);
6135 //GET_DATA(hit_pos);
6138 // find the object with this signature. If found, then do a shield explosion
6139 objp = multi_get_network_object( signature );
6142 shield_info *shieldp;
6147 // given the tri num, find the local position which is the average of the
6148 // three vertices of the triangle affected. Use this average point as the hit
6150 // Assert( objp->type == OBJ_SHIP );
6151 if(objp->type != OBJ_SHIP){
6155 pm = model_get(Ships[objp->instance].modelnum);
6156 shieldp = &pm->shield;
6157 Assert( utri_num < shieldp->ntris );
6158 stri = shieldp->tris[utri_num];
6159 vm_vec_zero(&hit_pos);
6160 for ( i = 0; i < 3; i++ ) {
6161 vm_vec_add2( &hit_pos, &(shieldp->verts[stri.verts[i]].pos) );
6163 vm_vec_scale( &hit_pos, 1.0f/3.0f );
6164 add_shield_point_multi( OBJ_INDEX(objp), utri_num, &hit_pos );
6168 void send_player_stats_block_packet(net_player *pl, int stats_code, net_player *target)
6171 ubyte data[MAX_PACKET_SIZE], val;
6173 int packet_size = 0;
6178 sc = &pl->player->stats;
6181 BUILD_HEADER(PLAYER_STATS);
6183 // add the player id
6184 ADD_DATA(pl->player_id);
6186 // add the byte indicating whether these stats are all-time or not
6187 val = (ubyte)stats_code;
6190 // kill information - alltime
6194 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6195 u_tmp = sc->kills[idx];
6198 // medal information
6199 for(idx=0;idx<NUM_MEDALS;idx++){
6200 i_tmp = sc->medals[idx];
6204 ADD_DATA(sc->score);
6206 ADD_DATA(sc->assists);
6207 ADD_DATA(sc->kill_count);
6208 ADD_DATA(sc->kill_count_ok);
6209 ADD_DATA(sc->p_shots_fired);
6210 ADD_DATA(sc->s_shots_fired);
6211 ADD_DATA(sc->p_shots_hit);
6212 ADD_DATA(sc->s_shots_hit);
6213 ADD_DATA(sc->p_bonehead_hits);
6214 ADD_DATA(sc->s_bonehead_hits);
6215 ADD_DATA(sc->bonehead_kills);
6217 ADD_DATA(sc->missions_flown);
6218 ADD_DATA(sc->flight_time);
6219 ADD_DATA(sc->last_flown);
6220 ADD_DATA(sc->last_backup);
6225 for(idx=0;idx<MAX_SHIP_TYPES;idx++){
6226 u_tmp = sc->m_okKills[idx];
6230 ADD_DATA(sc->m_score);
6231 ADD_DATA(sc->m_assists);
6232 ADD_DATA(sc->m_kill_count);
6233 ADD_DATA(sc->m_kill_count_ok);
6234 ADD_DATA(sc->mp_shots_fired);
6235 ADD_DATA(sc->ms_shots_fired);
6236 ADD_DATA(sc->mp_shots_hit);
6237 ADD_DATA(sc->ms_shots_hit);
6238 ADD_DATA(sc->mp_bonehead_hits);
6239 ADD_DATA(sc->ms_bonehead_hits);
6240 ADD_DATA(sc->m_bonehead_kills);
6241 ADD_DATA(sc->m_player_deaths);
6242 ADD_DATA(sc->m_medal_earned);
6245 case STATS_MISSION_KILLS:
6246 ADD_DATA(sc->m_kill_count);
6247 ADD_DATA(sc->m_kill_count_ok);
6248 ADD_DATA(sc->m_assists);
6251 case STATS_DOGFIGHT_KILLS:
6252 for(idx=0; idx<MAX_PLAYERS; idx++){
6253 u_tmp = sc->m_dogfight_kills[idx];
6256 ADD_DATA(sc->m_kill_count);
6257 ADD_DATA(sc->m_kill_count_ok);
6258 ADD_DATA(sc->m_assists);
6262 Assert(packet_size < MAX_PACKET_SIZE);
6264 // if we're a client, always send the data to the server
6265 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6266 multi_io_send_reliable(Net_player, data, packet_size);
6268 // otherwise do server specific stuff
6270 // send to a specific target
6272 multi_io_send_reliable(target, data, packet_size);
6274 // otherwise, send to everyone
6276 multi_io_send_to_all_reliable(data, packet_size);
6281 void process_player_stats_block_packet(ubyte *data, header *hinfo)
6285 scoring_struct *sc,bogus;
6287 int offset = HEADER_LENGTH;
6291 // nprintf(("Network","----------++++++++++********RECEIVED STATS***********+++++++++----------\n"));
6293 // get the player who these stats are for
6294 GET_DATA(player_id);
6295 player_num = find_player_id(player_id);
6296 if (player_num == -1) {
6297 nprintf(("Network", "Couldn't find player for stats update!\n"));
6298 ml_string("Couldn't find player for stats update!\n");
6303 sc = &Net_players[player_num].player->stats;
6306 // get the stats code
6310 ml_string("Received STATS_ALLTIME\n");
6313 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6315 sc->kills[idx] = u_tmp;
6318 // read in the stats
6319 for (idx=0; idx<NUM_MEDALS; idx++) {
6321 sc->medals[idx] = i_tmp;
6324 GET_DATA(sc->score);
6326 GET_DATA(sc->assists);
6327 GET_DATA(sc->kill_count);
6328 GET_DATA(sc->kill_count_ok);
6329 GET_DATA(sc->p_shots_fired);
6330 GET_DATA(sc->s_shots_fired);
6331 GET_DATA(sc->p_shots_hit);
6332 GET_DATA(sc->s_shots_hit);
6333 GET_DATA(sc->p_bonehead_hits);
6334 GET_DATA(sc->s_bonehead_hits);
6335 GET_DATA(sc->bonehead_kills);
6337 GET_DATA(sc->missions_flown);
6338 GET_DATA(sc->flight_time);
6339 GET_DATA(sc->last_flown);
6340 GET_DATA(sc->last_backup);
6344 ml_string("Received STATS_MISSION\n");
6346 // kills - mission OK
6347 for (idx=0; idx<MAX_SHIP_TYPES; idx++) {
6349 sc->m_okKills[idx] = u_tmp;
6352 GET_DATA(sc->m_score);
6353 GET_DATA(sc->m_assists);
6354 GET_DATA(sc->m_kill_count);
6355 GET_DATA(sc->m_kill_count_ok);
6356 GET_DATA(sc->mp_shots_fired);
6357 GET_DATA(sc->ms_shots_fired);
6358 GET_DATA(sc->mp_shots_hit);
6359 GET_DATA(sc->ms_shots_hit);
6360 GET_DATA(sc->mp_bonehead_hits);
6361 GET_DATA(sc->ms_bonehead_hits);
6362 GET_DATA(sc->m_bonehead_kills);
6363 GET_DATA(sc->m_player_deaths);
6364 GET_DATA(sc->m_medal_earned);
6367 case STATS_MISSION_KILLS:
6368 ml_string("Received STATS_MISSION_KILLS\n");
6370 GET_DATA(sc->m_kill_count);
6371 GET_DATA(sc->m_kill_count_ok);
6372 GET_DATA(sc->m_assists);
6375 case STATS_DOGFIGHT_KILLS:
6376 ml_string("Received STATS_DOGFIGHT_KILLS\n");
6377 if(player_num >= 0){
6378 ml_printf("Dogfight stats for %s", Net_players[player_num].player->callsign);
6380 for(idx=0; idx<MAX_PLAYERS; idx++){
6382 sc->m_dogfight_kills[idx] = u_tmp;
6383 if(player_num >= 0){
6384 ml_printf("%d", Net_players[player_num].player->stats.m_dogfight_kills[idx]);
6387 GET_DATA(sc->m_kill_count);
6388 GET_DATA(sc->m_kill_count_ok);
6389 GET_DATA(sc->m_assists);
6394 // if I'm the server of the game, I should always rebroadcast these stats
6395 if ((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (sc != &bogus)) {
6396 // make sure these are alltime stats
6397 Assert(val == STATS_ALLTIME);
6399 multi_broadcast_stats(STATS_ALLTIME);
6403 // called to create asteroid stuff
6404 void send_asteroid_create( object *new_objp, object *parent_objp, int asteroid_type, vector *relvec )
6407 ubyte data[MAX_PACKET_SIZE];
6408 ubyte packet_type, atype;
6412 if (relvec != NULL )
6415 BUILD_HEADER( ASTEROID_INFO );
6416 packet_type = ASTEROID_CREATE;
6418 Assert( asteroid_type < UCHAR_MAX );
6419 atype = (ubyte)asteroid_type;
6421 ADD_DATA( packet_type );
6422 ADD_DATA( parent_objp->net_signature );
6423 ADD_DATA( new_objp->net_signature );
6427 multi_io_send_to_all(data, packet_size);
6430 void send_asteroid_throw( object *objp )
6433 ubyte data[MAX_PACKET_SIZE], packet_type;
6435 BUILD_HEADER( ASTEROID_INFO );
6437 // this packet type is an asteroid throw
6438 packet_type = ASTEROID_THROW;
6439 ADD_DATA( packet_type );
6440 ADD_DATA( objp->net_signature );
6441 ADD_DATA( objp->pos );
6442 ADD_DATA( objp->phys_info.vel );
6444 multi_io_send_to_all(data, packet_size);
6447 void send_asteroid_hit( object *objp, object *other_objp, vector *hitpos, float damage )
6450 ubyte data[MAX_PACKET_SIZE], packet_type;
6454 if ( hitpos != NULL )
6457 // build up an asteroid hit packet
6458 BUILD_HEADER( ASTEROID_INFO );
6459 packet_type = ASTEROID_HIT;
6460 ADD_DATA( packet_type );
6461 ADD_DATA( objp->net_signature );
6463 if(other_objp == NULL){
6464 ushort invalid_sig = 0xffff;
6465 ADD_DATA(invalid_sig);
6467 ADD_DATA( other_objp->net_signature );
6472 multi_io_send_to_all(data, packet_size);
6475 void process_asteroid_info( ubyte *data, header *hinfo )
6480 offset = HEADER_LENGTH;
6481 GET_DATA( packet_type );
6483 // based on the packet type, do something interesting with an asteroid!
6484 switch( packet_type ) {
6486 case ASTEROID_CREATE: {
6487 ushort psignature, signature;
6490 object *parent_objp;
6492 GET_DATA( psignature );
6493 GET_DATA( signature );
6497 // after getting the values, set the next network signature, and call the create sub function
6498 multi_set_network_signature( signature, MULTI_SIG_ASTEROID );
6499 parent_objp = multi_get_network_object( psignature );
6500 if ( parent_objp ) {
6501 asteroid_sub_create( parent_objp, atype, &relvec );
6503 nprintf(("Network", "Couldn't create asteroid because parent wasn't found!!!\n"));
6510 // asteroid throw packet -- asteroid has wrapped bounds
6511 case ASTEROID_THROW: {
6516 GET_DATA( signature );
6519 objp = multi_get_network_object( signature );
6521 nprintf(("Network", "Couldn't throw asteroid because couldn't find it\n"));
6525 objp->phys_info.vel = vel;
6526 objp->phys_info.desired_vel = vel;
6530 case ASTEROID_HIT: {
6531 ushort signature, osignature;
6532 object *objp, *other_objp;
6536 GET_DATA( signature );
6537 GET_DATA( osignature );
6541 objp = multi_get_network_object( signature );
6542 if(osignature == 0xffff){
6545 other_objp = multi_get_network_object( osignature );
6548 nprintf(("Network", "Cannot hit asteroid because signature isn't found\n"));
6552 if ( IS_VEC_NULL(&hitpos) ){
6553 asteroid_hit( objp, other_objp, NULL, damage );
6555 asteroid_hit( objp, other_objp, &hitpos, damage );
6558 // if we know the other object is a weapon, then do a weapon hit to kill the weapon
6559 if ( other_objp && (other_objp->type == OBJ_WEAPON) ){
6560 weapon_hit( other_objp, objp, &hitpos );
6573 void send_host_restr_packet(char *callsign,int code,int mode)
6575 ubyte data[MAX_PACKET_SIZE],val;
6576 int packet_size = 0;
6578 // build the header and add the opcode
6579 BUILD_HEADER(HOST_RESTR_QUERY);
6586 ADD_STRING(callsign);
6588 // if I'm the standalone server, I should be sending this to the game host
6589 if((Game_mode & GM_STANDALONE_SERVER) && (Netgame.host != NULL)){
6590 multi_io_send_reliable(Netgame.host, data, packet_size);
6592 // otherwise if I'm the host, I should be sending a reply back to the standalone server
6594 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6595 multi_io_send_reliable(Net_player, data, packet_size);
6599 void process_host_restr_packet(ubyte *data, header *hinfo)
6603 int offset = HEADER_LENGTH;
6605 // get the opcode and the callsign
6608 GET_STRING(callsign);
6611 // do code specific operations
6613 // query to the host from standalone
6615 Assert((Net_player->flags & NETINFO_FLAG_GAME_HOST) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER));
6617 // set the join mode
6618 Multi_join_restr_mode = mode;
6620 // set the timestamp
6621 Multi_restr_query_timestamp = timestamp(MULTI_QUERY_RESTR_STAMP);
6623 // notify the host of the event
6624 gamesnd_play_iface(SND_BRIEF_STAGE_CHG_FAIL);
6625 HUD_printf(XSTR("Player %s has tried to join - allow (y/n) ?",736),callsign);
6628 // affirmative reply from the host to the standalone
6630 Assert(Game_mode & GM_STANDALONE_SERVER);
6632 // let the player join if the timestamp has not already elapsed on the server
6633 if(Multi_restr_query_timestamp != -1){
6634 multi_process_valid_join_request(&Multi_restr_join_request,&Multi_restr_addr,(int)mode);
6640 Assert(Game_mode & GM_STANDALONE_SERVER);
6641 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
6642 Multi_restr_query_timestamp = -1;
6647 void send_netgame_end_error_packet(int notify_code,int err_code)
6651 int packet_size = 0;
6653 // only the server should ever be here - although this might change if for some reason the host wants to end the game
6654 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
6656 // build the header and add the notification and error codes
6657 BUILD_HEADER(NETGAME_END_ERROR);
6658 code = (char)notify_code;
6660 code = (char)err_code;
6664 multi_io_send_to_all_reliable(data, packet_size);
6667 void process_netgame_end_error_packet(ubyte *data, header *hinfo)
6669 int offset = HEADER_LENGTH;
6670 char notify_code,error_code;
6672 // get the error and notification codes
6673 GET_DATA(notify_code);
6674 GET_DATA(error_code);
6678 multi_quit_game(PROMPT_NONE,notify_code,error_code);
6681 // sends info that a countermeasure succeeded.
6682 void send_countermeasure_success_packet( int objnum )
6684 int pnum, packet_size;
6685 ubyte data[MAX_PACKET_SIZE];
6687 pnum = multi_find_player_by_object( &Objects[objnum] );
6689 nprintf(("Network", "Coulnd't find player for countermeasure success packet\n"));
6693 BUILD_HEADER(COUNTERMEASURE_SUCCESS);
6694 multi_io_send(&Net_players[pnum], data, packet_size);
6697 // start the flashing of my hud gauge
6698 void process_countermeasure_success_packet( ubyte *data, header *hinfo )
6702 offset = HEADER_LENGTH;
6705 hud_start_text_flash(XSTR("Evaded", 1430), 800);
6706 snd_play(&Snds[SND_MISSILE_EVADED_POPUP]);
6709 #define UPDATE_IS_PAUSED (1<<0)
6710 #define UPDATE_HULL_INFO (1<<1)
6712 void send_client_update_packet(net_player *pl)
6714 ubyte data[MAX_PACKET_SIZE],val;
6715 int packet_size = 0;
6718 BUILD_HEADER(CLIENT_UPDATE);
6722 // add the pause status
6723 if ( Multi_pause_status ) {
6724 val |= UPDATE_IS_PAUSED;
6725 } 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) ) {
6726 val |= UPDATE_HULL_INFO;
6727 Assert( Player_ship ); // I"d better have one of these!!!!
6732 // if paused, add the net address of the guy who paused
6733 if(val & UPDATE_IS_PAUSED){
6734 Assert(Multi_pause_pauser != NULL);
6735 ADD_DATA(Multi_pause_pauser->player_id);
6738 // when not paused, send hull/shield/subsystem updates to all clients (except for ingame joiners)
6739 if ( val & UPDATE_HULL_INFO ) {
6741 ubyte percent, ns, threats;
6744 ship_subsys *subsysp;
6747 // get the object for the player
6748 Assert( pl->player->objnum != -1 );
6750 objp = &Objects[pl->player->objnum];
6752 Assert ( objp->type == OBJ_SHIP );
6753 shipp = &Ships[objp->instance];
6754 sip = &Ship_info[shipp->ship_info_index];
6756 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6757 // percentage value since that should be close enough
6758 float temp = (objp->hull_strength / sip->initial_hull_strength * 100.0f);
6762 percent = (ubyte)temp;
6764 ADD_DATA( percent );
6766 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6767 percent = (ubyte)(objp->shields[i] / (sip->shields / MAX_SHIELD_SECTIONS) * 100.0f);
6768 ADD_DATA( percent );
6771 // add the data for the subsystem hits. We can assume that the lists will be the same side of
6772 // both machines. Added as percent since that number <= 100
6774 // also write out the number of subsystems. We do this because the client might not know
6775 // about the object he is getting data for. (i.e. he killed the object already).
6776 ns = (ubyte)sip->n_subsystems;
6779 // now the subsystems.
6780 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6781 percent = (ubyte)(subsysp->current_hits / subsysp->system_info->max_hits * 100.0f);
6782 ADD_DATA( percent );
6785 // compute the threats for this player. Only compute the threats if this player is actually
6786 // playing (i.e. he has a ship)
6787 hud_update_reticle( pl->player );
6788 threats = (ubyte)pl->player->threat_flags;
6789 ADD_DATA( threats );
6791 // add his energy level for guns
6792 ADD_DATA(shipp->weapon_energy);
6794 // add his secondary bank ammo
6795 ADD_DATA(shipp->weapons.num_secondary_banks);
6796 for(i=0; i<shipp->weapons.num_secondary_banks; i++){
6797 ADD_DATA(shipp->weapons.secondary_bank_ammo[i]);
6802 ADD_DATA(pl->sv_last_pl);
6804 // send the packet reliably to the player
6805 multi_io_send(pl, data, packet_size);
6808 void process_client_update_packet(ubyte *data, header *hinfo)
6813 int is_paused, have_hull_info;
6816 float weapon_energy;
6817 int offset = HEADER_LENGTH;
6819 // get the header byte containing useful information
6822 is_paused = (val & UPDATE_IS_PAUSED)?1:0;
6823 have_hull_info = (val & UPDATE_HULL_INFO)?1:0;
6825 // if we are paused, get who paused
6828 player_index = find_player_id(pauser);
6829 if(player_index != -1){
6830 Multi_pause_pauser = &Net_players[player_index];
6832 Multi_pause_pauser = NULL;
6836 // if we have hull information, then read it in.
6837 if ( have_hull_info ) {
6841 ubyte hull_percent, shield_percent[MAX_SHIELD_SECTIONS], n_subsystems, subsystem_percent[MAX_MODEL_SUBSYSTEMS], threats;
6843 ship_subsys *subsysp;
6847 // hull strength and sheild mesh information are floats (as a percentage). Pass the integer
6848 // percentage value since that should be close enough
6849 GET_DATA( hull_percent );
6851 for (i = 0; i < MAX_SHIELD_SECTIONS; i++ ){
6853 shield_percent[i] = ub_tmp;
6856 // get the data for the subsystems
6857 GET_DATA( n_subsystems );
6858 for ( i = 0; i < n_subsystems; i++ ){
6860 subsystem_percent[i] = ub_tmp;
6863 GET_DATA( threats );
6865 // add his energy level for guns
6866 GET_DATA(weapon_energy);
6868 // add his secondary bank ammo
6869 GET_DATA(ammo_count);
6870 for(i=0; i<ammo_count; i++){
6874 // assign the above information to my ship, assuming that I can find it! Ingame joiners might get this
6875 // packet because of delay between reliable packet acknowledging my ingame ship and the start of these
6876 // UDP client update packets. Only read this info if I have a ship.
6877 if ( !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Player_ship != NULL) && (Player_obj != NULL) && (Net_player != NULL)) {
6878 shipp = Player_ship;
6880 sip = &Ship_info[shipp->ship_info_index];
6882 val = hull_percent * sip->initial_hull_strength / 100.0f;
6883 objp->hull_strength = val;
6885 for ( i = 0; i < MAX_SHIELD_SECTIONS; i++ ) {
6886 val = (shield_percent[i] * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
6887 objp->shields[i] = val;
6890 // for sanity, be sure that the number of susbystems that I read in matches the player. If not,
6891 // then don't read these in.
6892 if ( n_subsystems == sip->n_subsystems ) {
6894 n_subsystems = 0; // reuse this variable
6895 for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
6898 val = subsystem_percent[n_subsystems] * subsysp->system_info->max_hits / 100.0f;
6899 subsysp->current_hits = val;
6901 // add the value just generated (it was zero'ed above) into the array of generic system types
6902 subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
6903 Assert ( subsys_type < SUBSYSTEM_MAX );
6904 shipp->subsys_info[subsys_type].current_hits += val;
6908 ship_recalc_subsys_strength( shipp );
6910 shipp->weapon_energy = weapon_energy;
6911 for(i=0; i<ammo_count; i++){
6912 shipp->weapons.secondary_bank_ammo[i] = ammo[i];
6915 // update my threat flags.
6916 // temporarily commented out until tested.
6917 Net_player->player->threat_flags = threats;
6924 if(Net_player != NULL){
6925 Net_player->cl_last_pl = pl;
6929 // note, if we're already paused or unpaused, calling these will have no effect, so it is safe to do so
6930 if(!popup_active() && !(Net_player->flags & NETINFO_FLAG_RESPAWNING) && !(Net_player->flags & NETINFO_FLAG_LIMBO)){
6932 multi_pause_pause();
6934 multi_pause_unpause();
6939 void send_countdown_packet(int time)
6943 int packet_size = 0;
6945 // build the header and add the time
6946 BUILD_HEADER(COUNTDOWN);
6950 // if we're the server, we should broadcast to everyone
6951 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
6952 multi_io_send_to_all_reliable(data, packet_size);
6954 // otherwise we'de better be a host sending to the standalone
6956 Assert(Net_player->flags & NETINFO_FLAG_GAME_HOST);
6957 multi_io_send_reliable(Net_player, data, packet_size);
6961 void process_countdown_packet(ubyte *data, header *hinfo)
6963 int offset = HEADER_LENGTH;
6970 // if we're not in the post sync data screen, ignore it
6971 if(gameseq_get_state() != GS_STATE_MULTI_MISSION_SYNC){
6975 // if we're the standalone, this should be a -1 telling us to start the countdown
6976 if(Game_mode & GM_STANDALONE_SERVER){
6977 Assert((int)time == -1);
6979 // start the countdown
6980 multi_sync_start_countdown();
6982 // otherwise if we're clients, just bash the countdown
6984 Multi_sync_countdown = (int)time;
6988 // packets for debriefing information
6989 void send_debrief_info( int stage_count[], int *stages[] )
6991 ubyte data[MAX_PACKET_SIZE];
6992 int packet_size, i, j;
6995 BUILD_HEADER(DEBRIEF_INFO);
6997 // add the data for the teams
6998 for ( i = 0; i < Num_teams; i++ ) {
7001 count = stage_count[i];
7003 for ( j = 0; j < count; j++ ) {
7004 i_tmp = stages[i][j];
7009 multi_io_send_to_all_reliable(data, packet_size);
7012 // process a debrief info packet from the server
7013 void process_debrief_info( ubyte *data, header *hinfo )
7016 int stage_counts[MAX_TEAMS], active_stages[MAX_TEAMS][MAX_DEBRIEF_STAGES], *stages[MAX_TEAMS];
7019 offset = HEADER_LENGTH;
7020 for ( i = 0; i < Num_teams; i++ ) {
7024 stage_counts[i] = count;
7025 stages[i] = active_stages[i];
7026 for ( j = 0; j < count; j++ ) {
7028 active_stages[i][j] = i_tmp;
7033 // now that we have the stage data for the debriefing stages, call debrief function with the
7034 // data so that clients can now see the debriefing stuff. Do it only for my team.
7035 Assert( (Net_player->p_info.team >= 0) && (Net_player->p_info.team < Num_teams) );
7036 debrief_set_multi_clients( stage_counts[Net_player->p_info.team], stages[Net_player->p_info.team] );
7039 // sends homing information to all clients. We only need signature and num_missiles (because of hornets).
7040 // sends homing_object and homing_subsystem to all clients.
7041 void send_homing_weapon_info( int weapon_num )
7043 ubyte data[MAX_PACKET_SIZE];
7046 object *homing_object;
7047 ushort homing_signature;
7050 wp = &Weapons[weapon_num];
7052 // be sure that this weapon object is a homing object.
7053 if ( !(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING) )
7056 // get the homing signature. If this weapon isn't homing on anything, then sent 0 as the
7057 // homing signature.
7058 homing_signature = 0;
7059 homing_object = wp->homing_object;
7060 if ( homing_object != NULL ) {
7061 homing_signature = homing_object->net_signature;
7063 // get the subsystem index.
7065 if ( (homing_object->type == OBJ_SHIP) && (wp->homing_subsys != NULL) ) {
7068 s_index = ship_get_index_from_subsys( wp->homing_subsys, OBJ_INDEX(homing_object), 1 );
7069 Assert( s_index < CHAR_MAX ); // better be less than this!!!!
7070 t_subsys = (char)s_index;
7074 BUILD_HEADER(HOMING_WEAPON_UPDATE);
7075 ADD_DATA( Objects[wp->objnum].net_signature );
7076 ADD_DATA( homing_signature );
7077 ADD_DATA( t_subsys );
7079 multi_io_send_to_all(data, packet_size);
7082 // process a homing weapon info change packet. multiple_missiles parameter specifies is this
7083 // packet contains information for multiple weapons (like hornets).
7084 void process_homing_weapon_info( ubyte *data, header *hinfo )
7087 ushort weapon_signature, homing_signature;
7089 object *homing_object, *weapon_objp;
7092 offset = HEADER_LENGTH;
7094 // get the data for the packet
7095 GET_DATA( weapon_signature );
7096 GET_DATA( homing_signature );
7097 GET_DATA( h_subsys );
7100 // deal with changing this weapons homing information
7101 weapon_objp = multi_get_network_object( weapon_signature );
7102 if ( weapon_objp == NULL ) {
7103 nprintf(("Network", "Couldn't find weapon object for homing update -- skipping update\n"));
7106 Assert( weapon_objp->type == OBJ_WEAPON );
7107 wp = &Weapons[weapon_objp->instance];
7109 // be sure that we can find these weapons and
7110 homing_object = multi_get_network_object( homing_signature );
7111 if ( homing_object == NULL ) {
7112 nprintf(("Network", "Couldn't find homing object for homing update\n"));
7116 if ( homing_object->type == OBJ_WEAPON ) {
7117 Assert(Weapon_info[Weapons[homing_object->instance].weapon_info_index].wi_flags & WIF_BOMB);
7120 wp->homing_object = homing_object;
7121 wp->homing_subsys = NULL;
7122 wp->target_num = OBJ_INDEX(homing_object);
7123 wp->target_sig = homing_object->signature;
7124 if ( h_subsys != -1 ) {
7125 Assert( homing_object->type == OBJ_SHIP );
7126 wp->homing_subsys = ship_get_indexed_subsys( &Ships[homing_object->instance], h_subsys);
7129 if ( homing_object->type == OBJ_SHIP ) {
7130 nprintf(("Network", "Updating homing information for weapon -- homing on %s\n", Ships[homing_object->instance].ship_name));
7134 void send_emp_effect(ushort net_sig, float intensity, float time)
7139 Assert(MULTIPLAYER_MASTER);
7141 // build the packet and add the opcode
7142 BUILD_HEADER(EMP_EFFECT);
7144 ADD_DATA(intensity);
7147 // send it to the player
7148 multi_io_send_to_all(data, packet_size);
7151 void process_emp_effect(ubyte *data, header *hinfo)
7153 float intensity, time;
7156 int offset = HEADER_LENGTH;
7158 // read in the EMP effect data
7160 GET_DATA(intensity);
7164 // try and find the object
7165 objp = multi_get_network_object(net_sig);
7166 if((objp != NULL) && (objp->type == OBJ_SHIP)){
7167 // if i'm not an observer and I have a valid ship, play the EMP effect
7168 if(!(Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && (Player_obj == objp)){
7169 emp_start_local(intensity, time);
7172 // start the effect for the ship itself
7173 emp_start_ship(objp, intensity, time);
7177 // tells whether or not reinforcements are available
7178 void send_reinforcement_avail( int rnum )
7183 BUILD_HEADER(REINFORCEMENT_AVAIL);
7185 multi_io_send_to_all_reliable(data, packet_size);
7188 void process_reinforcement_avail( ubyte *data, header *hinfo )
7193 offset = HEADER_LENGTH;
7197 // sanity check for a valid reinforcement number
7198 if ( (rnum >= 0) && (rnum < Num_reinforcements) ) {
7199 Reinforcements[rnum].flags |= RF_IS_AVAILABLE;
7203 void send_change_iff_packet(ushort net_signature, int new_team)
7205 ubyte data[MAX_PACKET_SIZE];
7206 int packet_size = 0;
7208 if(Net_player == NULL){
7211 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
7215 // build the packet and add the data
7216 BUILD_HEADER(CHANGE_IFF);
7217 ADD_DATA(net_signature);
7220 // send to all players
7221 multi_io_send_to_all_reliable(data, packet_size);
7224 void process_change_iff_packet( ubyte *data, header *hinfo)
7226 int offset = HEADER_LENGTH;
7227 ushort net_signature;
7232 GET_DATA(net_signature);
7236 // lookup the object
7237 objp = multi_get_network_object(net_signature);
7238 if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
7239 Ships[objp->instance].team = new_team;
7243 void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
7245 int packet_size, objnum;
7246 ubyte data[MAX_PACKET_SIZE]; // ubanks_fired, current_bank;
7249 net_player *ignore = NULL;
7251 // sanity checking for now
7252 Assert ( banks_fired <= 3 );
7254 // get an object pointer for this ship.
7255 objnum = shipp->objnum;
7256 objp = &Objects[objnum];
7258 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7259 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7263 // just in case nothing got fired
7264 if(banks_fired <= 0){
7268 // ubanks_fired = (ubyte)banks_fired;
7269 // current_bank = (ubyte)shipp->weapons.current_primary_bank;
7270 // Assert( current_bank <= 3 );
7272 // insert the current primary bank into this byte
7273 // ubanks_fired |= (current_bank << CURRENT_BANK_BIT);
7275 // append the SF_PRIMARY_LINKED flag on the top nibble of the banks_fired
7276 // if ( shipp->flags & SF_PRIMARY_LINKED ){
7277 // ubanks_fired |= (1<<7);
7280 // determine if its a player ship and don't send to him if we're in "client firing" mode
7281 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7282 if(MULTIPLAYER_MASTER){
7283 np_index = multi_find_player_by_net_signature(objp->net_signature);
7284 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7285 ignore = &Net_players[np_index];
7289 // build up the standard weapon fired packet. This packet will get sent to all players if an AI
7290 // ship fired the primary weapons. If a player fired the weaspon, then this packet will get sent
7291 // to every player but the guy who actullly fired the weapon. This method is used to help keep client
7292 // and server in sync w.r.t. weapon energy for player ship
7293 BUILD_HEADER( PRIMARY_FIRED_NEW );
7294 ADD_DATA(objp->net_signature);
7295 // ADD_DATA(ubanks_fired);
7297 // if I'm a server, broadcast to all players
7298 if(MULTIPLAYER_MASTER){
7299 multi_io_send_to_all(data, packet_size, ignore);
7302 multi_rate_add(1, "wfi", packet_size);
7304 // otherwise just send to the server
7306 multi_io_send(Net_player, data, packet_size);
7310 void process_NEW_primary_fired_packet(ubyte *data, header *hinfo)
7312 int offset; // linked;
7313 // ubyte banks_fired, current_bank;
7318 // read all packet info
7319 offset = HEADER_LENGTH;
7320 GET_DATA(shooter_sig);
7321 // GET_DATA(banks_fired);
7324 // find the object this fired packet is operating on
7325 objp = multi_get_network_object( shooter_sig );
7326 if ( objp == NULL ) {
7327 nprintf(("Network", "Could not find ship for fire primary packet NEW!"));
7330 // if this object is not actually a valid ship, don't do anything
7331 if(objp->type != OBJ_SHIP){
7334 if(objp->instance < 0){
7337 shipp = &Ships[objp->instance];
7339 // get the link status of the primary banks
7341 // if ( banks_fired & (1<<7) ) {
7343 // banks_fired ^= (1<<7);
7346 // get the current primary bank
7347 // current_bank = (ubyte)(banks_fired >> CURRENT_BANK_BIT);
7348 // current_bank &= 0x3;
7349 // Assert( (current_bank >= 0) && (current_bank < MAX_PRIMARY_BANKS) );
7350 // shipp->weapons.current_primary_bank = current_bank;
7352 // strip off all remaining bits and just keep which banks were actually fired.
7353 // banks_fired &= 0x3;
7355 // set the link status of the ship if not the player. If it is the player, we will do sanity checking
7358 // shipp->flags &= ~SF_PRIMARY_LINKED;
7360 // shipp->flags |= SF_PRIMARY_LINKED;
7363 // if we're in client firing mode, ignore ones for myself
7364 if((Player_obj != NULL) && (Player_obj == objp)){
7368 ship_fire_primary( objp, 0, 1 );
7371 void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
7373 ubyte data[MAX_PACKET_SIZE];
7376 net_player *ignore = NULL;
7378 // if i'm a multiplayer client, I should never send primary fired packets for anyone except me
7379 if(MULTIPLAYER_CLIENT && (Player_obj != objp)){
7383 Assert ( cmeasure_count < UCHAR_MAX );
7384 BUILD_HEADER(COUNTERMEASURE_NEW);
7385 ADD_DATA( objp->net_signature );
7386 ADD_DATA( rand_val );
7388 nprintf(("Network","Sending NEW countermeasure packet!\n"));
7390 // determine if its a player ship and don't send to him if we're in "client firing" mode
7391 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && MULTIPLAYER_MASTER){
7392 if(MULTIPLAYER_MASTER){
7393 np_index = multi_find_player_by_net_signature(objp->net_signature);
7394 if((np_index >= 0) && (np_index < MAX_PLAYERS)){
7395 ignore = &Net_players[np_index];
7399 // if I'm the server, send to all players
7400 if(MULTIPLAYER_MASTER){
7401 multi_io_send_to_all(data, packet_size, ignore);
7403 // otherwise send to the server
7405 multi_io_send(Net_player, data, packet_size);
7409 void process_NEW_countermeasure_fired_packet(ubyte *data, header *hinfo)
7416 offset = HEADER_LENGTH;
7417 GET_DATA( signature );
7418 GET_DATA( rand_val );
7421 objp = multi_get_network_object( signature );
7422 if ( objp == NULL ) {
7423 nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
7426 if(objp->type != OBJ_SHIP){
7430 // if we're in client firing mode, ignore ones for myself
7431 // if((Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING) && (Player_obj != NULL) && (Player_obj == objp)){
7432 if((Player_obj != NULL) && (Player_obj == objp)){
7436 // make it so ship can fire right away!
7437 Ships[objp->instance].cmeasure_fire_stamp = timestamp(0);
7438 if ( objp == Player_obj ){
7439 nprintf(("network", "firing countermeasure from my ship\n"));
7441 ship_launch_countermeasure( objp, rand_val );
7444 void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override)
7446 ubyte data[MAX_PACKET_SIZE];
7447 int packet_size = 0;
7451 // only the server should ever be doing this
7452 Assert(MULTIPLAYER_MASTER);
7454 // setup outgoing data
7455 Assert(shooter != NULL);
7456 Assert(turret != NULL);
7457 Assert(target != NULL);
7458 Assert(override != NULL);
7459 if((shooter == NULL) || (turret == NULL) || (target == NULL) || (override == NULL)){
7462 u_beam_info = (ubyte)beam_info_index;
7463 subsys_index = (char)ship_get_index_from_subsys(turret, OBJ_INDEX(shooter));
7464 Assert(subsys_index >= 0);
7465 if(subsys_index < 0){
7470 BUILD_HEADER(BEAM_FIRED);
7471 ADD_DATA(shooter->net_signature);
7472 ADD_DATA(subsys_index);
7473 ADD_DATA(target->net_signature);
7474 ADD_DATA(u_beam_info);
7475 ADD_DATA((*override));
7477 // send to all clients
7478 multi_io_send_to_all_reliable(data, packet_size);
7481 void process_beam_fired_packet(ubyte *data, header *hinfo)
7484 ushort shooter_sig, target_sig;
7488 beam_fire_info fire_info;
7490 // only clients should ever get this
7491 Assert(MULTIPLAYER_CLIENT);
7493 // read in packet data
7494 offset = HEADER_LENGTH;
7495 GET_DATA(shooter_sig);
7496 GET_DATA(subsys_index);
7497 GET_DATA(target_sig);
7498 GET_DATA(u_beam_info);
7502 // lookup all relevant data
7503 fire_info.beam_info_index = (int)u_beam_info;
7504 fire_info.shooter = NULL;
7505 fire_info.target = NULL;
7506 fire_info.turret = NULL;
7507 fire_info.target_subsys = NULL;
7508 fire_info.beam_info_override = NULL;
7509 fire_info.shooter = multi_get_network_object(shooter_sig);
7510 fire_info.target = multi_get_network_object(target_sig);
7511 fire_info.beam_info_override = &b_info;
7512 fire_info.accuracy = 1.0f;
7513 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)){
7514 nprintf(("Network", "Couldn't get shooter/target info for BEAM weapon!\n"));
7517 fire_info.turret = ship_get_indexed_subsys( &Ships[fire_info.shooter->instance], (int)subsys_index);
7518 if(fire_info.turret == NULL){
7519 nprintf(("Network", "Couldn't get turret for BEAM weapon!\n"));
7524 beam_fire(&fire_info);
7527 void send_sw_query_packet(ubyte code, char *txt)
7529 ubyte data[MAX_PACKET_SIZE];
7530 int packet_size = 0;
7532 // build the packet and add the code
7533 BUILD_HEADER(SW_STD_QUERY);
7535 if((code == SW_STD_START) || (code == SW_STD_BAD)){
7539 // if I'm the host, send to standalone
7540 if(MULTIPLAYER_HOST){
7541 Assert(!MULTIPLAYER_MASTER);
7542 Assert(code == SW_STD_START);
7543 multi_io_send_reliable(Net_player, data, packet_size);
7545 // otherwise standalone sends back to host
7547 Assert(Game_mode & GM_STANDALONE_SERVER);
7548 Assert(code != SW_STD_START);
7549 Assert(Netgame.host != NULL);
7550 if(Netgame.host != NULL){
7551 multi_io_send_reliable(Netgame.host, data, packet_size);
7556 void process_sw_query_packet(ubyte *data, header *hinfo)
7560 void send_event_update_packet(int event)
7562 ubyte data[MAX_PACKET_SIZE];
7563 ushort u_event = (ushort)event;
7564 int packet_size = 0;
7566 // build the header and add the event
7567 BUILD_HEADER(EVENT_UPDATE);
7569 ADD_DATA(Mission_events[event].flags);
7570 ADD_DATA(Mission_events[event].formula);
7571 ADD_DATA(Mission_events[event].result);
7572 ADD_DATA(Mission_events[event].count);
7574 // send to all players
7575 multi_io_send_to_all_reliable(data, packet_size);
7578 void process_event_update_packet(ubyte *data, header *hinfo)
7580 int offset = HEADER_LENGTH;
7586 store_flags = Mission_events[u_event].flags;
7587 GET_DATA(Mission_events[u_event].flags);
7588 GET_DATA(Mission_events[u_event].formula);
7589 GET_DATA(Mission_events[u_event].result);
7590 GET_DATA(Mission_events[u_event].count);
7593 // went from non directive special to directive special
7594 if(!(store_flags & MEF_DIRECTIVE_SPECIAL) && (Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7595 mission_event_set_directive_special(u_event);
7597 // if we went directive special to non directive special
7598 else if((store_flags & MEF_DIRECTIVE_SPECIAL) & !(Mission_events[u_event].flags & MEF_DIRECTIVE_SPECIAL)){
7599 mission_event_unset_directive_special(u_event);
7603 // weapon detonate packet
7604 void send_weapon_detonate_packet(object *objp)
7606 ubyte data[MAX_PACKET_SIZE];
7607 int packet_size = 0;
7610 Assert(MULTIPLAYER_MASTER);
7611 if(!MULTIPLAYER_MASTER){
7614 Assert(objp != NULL);
7619 // build the header and add the data
7620 BUILD_HEADER(WEAPON_DET);
7621 ADD_DATA(objp->net_signature);
7623 // send to all players
7624 multi_io_send_to_all(data, packet_size);
7627 void process_weapon_detonate_packet(ubyte *data, header *hinfo)
7630 int offset = HEADER_LENGTH;
7631 object *objp = NULL;
7633 // get the weapon signature
7637 // lookup the weapon
7638 objp = multi_get_network_object(net_sig);
7639 if((objp != NULL) && (objp->type == OBJ_WEAPON) && (objp->instance >= 0)){
7640 weapon_detonate(objp);
7644 // flak fired packet
7645 void send_flak_fired_packet(int ship_objnum, int subsys_index, int weapon_objnum, float flak_range)
7648 ushort pnet_signature;
7649 ubyte data[MAX_PACKET_SIZE], cindex;
7655 if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
7659 // local setup -- be sure we are actually passing a weapon!!!!
7660 objp = &Objects[weapon_objnum];
7661 Assert ( objp->type == OBJ_WEAPON );
7662 pnet_signature = Objects[ship_objnum].net_signature;
7664 Assert( subsys_index < UCHAR_MAX );
7665 cindex = (ubyte)subsys_index;
7667 ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
7672 // build the fire turret packet.
7673 BUILD_HEADER(FLAK_FIRED);
7674 packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.fvec);
7675 ADD_DATA( pnet_signature );
7677 val = (short)ssp->submodel_info_1.angs.h;
7679 val = (short)ssp->submodel_info_2.angs.p;
7681 ADD_DATA( flak_range );
7683 multi_io_send_to_all(data, packet_size);
7685 multi_rate_add(1, "flk", packet_size);
7688 void process_flak_fired_packet(ubyte *data, header *hinfo)
7690 int offset, weapon_objnum, wid;
7691 ushort pnet_signature;
7699 short pitch, heading;
7702 // get the data for the turret fired packet
7703 offset = HEADER_LENGTH;
7704 offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
7705 GET_DATA( pnet_signature );
7706 GET_DATA( turret_index );
7707 GET_DATA( heading );
7709 GET_DATA( flak_range );
7710 PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
7713 objp = multi_get_network_object( pnet_signature );
7714 if ( objp == NULL ) {
7715 nprintf(("network", "could find parent object with net signature %d for flak firing\n", pnet_signature));
7719 // if this isn't a ship, do nothing
7720 if ( objp->type != OBJ_SHIP ){
7724 // make an orientation matrix from the o_fvec
7725 vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
7727 // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
7728 // hack, but should be suitable.
7729 shipp = &Ships[objp->instance];
7730 ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
7734 wid = ssp->system_info->turret_weapon_type;
7735 if((wid < 0) || !(Weapon_info[wid].wi_flags & WIF_FLAK)){
7739 // bash the position and orientation of the turret
7740 ssp->submodel_info_1.angs.h = (float)heading;
7741 ssp->submodel_info_2.angs.p = (float)pitch;
7743 // get the world position of the weapon
7744 ship_get_global_turret_info(objp, ssp->system_info, &pos, &dir);
7746 // create the weapon object
7747 weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), 0, -1, 1);
7748 if (weapon_objnum != -1) {
7749 if ( Weapon_info[wid].launch_snd != -1 ) {
7750 snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
7753 // create a muzzle flash from a flak gun based upon firing position and weapon type
7754 flak_muzzle_flash(&pos, &dir, wid);
7756 // set its range explicitly - make it long enough so that it's guaranteed to still exist when the server tells us it blew up
7757 flak_set_range(&Objects[weapon_objnum], &pos, (float)flak_range);
7761 #define ADD_NORM_VEC(d) do { Assert((packet_size + 3) < MAX_PACKET_SIZE); char vnorm[3] = { (char)(d.x * 127.0f), (char)(d.y * 127.0f), (char)(d.z * 127.0f) }; memcpy(data + packet_size, vnorm, 3); packet_size += 3; } while(0);
7762 #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);
7764 // player pain packet
7765 void send_player_pain_packet(net_player *pl, int weapon_info_index, float damage, vector *force, vector *hitpos)
7767 ubyte data[MAX_PACKET_SIZE];
7770 int packet_size = 0;
7772 Assert(MULTIPLAYER_MASTER);
7773 if(!MULTIPLAYER_MASTER){
7781 // build the packet and add the code
7782 BUILD_HEADER(NETPLAYER_PAIN);
7783 windex = (ubyte)weapon_info_index;
7785 udamage = (ushort)damage;
7788 ADD_DATA((*hitpos));
7790 // send to the player
7791 multi_io_send(pl, data, packet_size);
7793 multi_rate_add(1, "pai", packet_size);
7796 void process_player_pain_packet(ubyte *data, header *hinfo)
7802 vector local_hit_pos;
7805 // get the data for the pain packet
7806 offset = HEADER_LENGTH;
7810 GET_DATA(local_hit_pos);
7813 mprintf(("PAIN!\n"));
7815 // get weapon info pointer
7816 Assert((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER));
7817 if(! ((windex >= 0) && (windex < Num_weapon_types) && (Weapon_info[windex].subtype == WP_LASER)) ){
7820 wip = &Weapon_info[windex];
7822 // play the weapon hit sound
7823 Assert(Player_obj != NULL);
7824 if(Player_obj == NULL){
7827 weapon_hit_do_sound(Player_obj, wip, &Player_obj->pos);
7829 // we need to do 3 things here. player pain (game flash), weapon hit sound, ship_apply_whack()
7830 ship_hit_pain((float)udamage);
7833 ship_apply_whack(&force, &local_hit_pos, Player_obj);
7837 void send_lightning_packet(int bolt_type, vector *start, vector *strike)
7839 ubyte data[MAX_PACKET_SIZE];
7841 int packet_size = 0;
7843 // build the header and add the data
7844 BUILD_HEADER(LIGHTNING_PACKET);
7845 val = (char)bolt_type;
7848 ADD_DATA((*strike));
7850 // send to everyone unreliable for now
7851 multi_io_send_to_all(data, packet_size);
7854 void process_lightning_packet(ubyte *data, header *hinfo)
7858 vector start, strike;
7861 offset = HEADER_LENGTH;
7862 GET_DATA(bolt_type);
7873 nebl_bolt(bolt_type, &start, &strike);
7876 void send_bytes_recvd_packet(net_player *pl)
7878 // only clients should ever be doing this
7883 ubyte data[MAX_PACKET_SIZE];
7884 int packet_size = 0;
7885 BUILD_HEADER(BYTES_SENT);
7886 ADD_DATA(pl->cl_bytes_recvd);
7888 // send to the server
7889 multi_io_send_reliable(pl, data, packet_size);
7892 void process_bytes_recvd_packet(ubyte *data, header *hinfo)
7896 net_player *pl = NULL;
7897 int offset = HEADER_LENGTH;
7903 if(Net_player == NULL){
7906 if(!MULTIPLAYER_MASTER){
7910 // make sure we know what player sent this
7911 pid = find_player_id(hinfo->id);
7912 if((pid < 0) || (pid >= MAX_PLAYERS)){
7915 pl = &Net_players[pid];
7918 pl->cl_bytes_recvd = bytes;
7922 pl->sv_last_pl = (int)(100.0f * (1.0f - ((float)pl->cl_bytes_recvd / (float)pl->sv_bytes_sent)));
7925 pl->sv_bytes_sent = 0;
7929 void send_host_captain_change_packet(short player_id, int captain_change)
7931 ubyte data[MAX_PACKET_SIZE];
7932 int packet_size = 0;
7935 BUILD_HEADER(TRANSFER_HOST);
7936 ADD_DATA(player_id);
7937 ADD_DATA(captain_change);
7940 multi_io_send_to_all_reliable(data, packet_size);
7943 void process_host_captain_change_packet(ubyte *data, header *hinfo)
7945 int offset = HEADER_LENGTH;
7946 int idx, found_player, captain_change;
7949 // get the player id
7950 GET_DATA(player_id);
7951 GET_DATA(captain_change);
7957 for(idx=0; idx<MAX_PLAYERS; idx++){
7958 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
7959 HUD_printf("%s is the new captain of team %d", Net_players[idx].player->callsign, Net_players[idx].p_info.team + 1);
7964 // unflag all old players
7965 for(idx=0; idx<MAX_PLAYERS; idx++){
7966 Net_players[idx].flags &= ~NETINFO_FLAG_GAME_HOST;
7971 for(idx=0; idx<MAX_PLAYERS; idx++){
7972 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].player_id == player_id)){
7973 Net_players[idx].flags |= NETINFO_FLAG_GAME_HOST;
7975 // spew to the HUD config
7976 if(Net_players[idx].player != NULL){
7977 HUD_printf("%s is the new game host", Net_players[idx].player->callsign);
7987 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_HOST_LEFT);
7992 void send_self_destruct_packet()
7994 ubyte data[MAX_PACKET_SIZE];
7995 int packet_size = 0;
7998 if(Net_player == NULL){
8002 // if i'm the server, I shouldn't be here
8003 Assert(!(Net_player->flags & NETINFO_FLAG_AM_MASTER));
8004 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
8008 // only if this is valid
8009 if(MULTI_OBSERVER(Net_players[MY_NET_PLAYER_NUM])){
8014 if((Player_ship == NULL) || (Player_obj == NULL)){
8019 BUILD_HEADER(SELF_DESTRUCT);
8020 ADD_DATA(Player_obj->net_signature);
8022 // send to the server
8023 multi_io_send_reliable(Net_player, data, packet_size);
8026 void process_self_destruct_packet(ubyte *data, header *hinfo)
8028 int offset = HEADER_LENGTH;
8032 // get the net signature
8037 np_index = find_player_id(hinfo->id);
8041 if(MULTI_OBSERVER(Net_players[np_index])){
8044 if(Net_players[np_index].player == NULL){
8047 if((Net_players[np_index].player->objnum < 0) || (Net_players[np_index].player->objnum >= MAX_OBJECTS)){
8050 if(Objects[Net_players[np_index].player->objnum].net_signature != net_sig){
8053 if(Objects[Net_players[np_index].player->objnum].type != OBJ_SHIP){
8056 if((Objects[Net_players[np_index].player->objnum].instance < 0) || (Objects[Net_players[np_index].player->objnum].instance >= MAX_SHIPS)){
8061 ship_self_destruct(&Objects[Net_players[np_index].player->objnum]);