FS2_Open
Open source remastering of the Freespace 2 engine
multimsgs.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include <limits.h>
14 
15 #include "globalincs/pstypes.h"
16 #include "network/multimsgs.h"
17 #include "network/multiutil.h"
18 #include "network/multiui.h"
19 #include "network/multi.h"
20 #include "globalincs/linklist.h"
22 #include "hud/hudmessage.h"
23 #include "hud/hudsquadmsg.h"
24 #include "freespace2/freespace.h"
25 #include "io/timer.h"
26 #include "mission/missiongoals.h"
27 #include "mission/missionlog.h"
28 #include "mission/missionmessage.h"
29 #include "network/stand_gui.h"
30 #include "gamesnd/gamesnd.h"
31 #include "ship/shiphit.h"
32 #include "render/3d.h"
33 #include "playerman/player.h"
34 #include "debris/debris.h"
37 #include "ship/shipfx.h"
38 #include "popup/popup.h"
39 #include "network/multi_ingame.h"
41 #include "ai/aigoals.h"
42 #include "network/multi_campaign.h"
43 #include "network/multi_team.h"
44 #include "network/multi_respawn.h"
45 #include "network/multi_observer.h"
46 #include "asteroid/asteroid.h"
47 #include "network/multi_pmsg.h"
48 #include "object/object.h"
49 #include "ship/ship.h"
50 #include "weapon/weapon.h"
51 #include "hud/hudreticle.h"
52 #include "network/multi_pause.h"
53 #include "network/multi_endgame.h"
55 #include "network/multi_log.h"
56 #include "weapon/emp.h"
57 #include "network/multi_kick.h"
58 #include "cmdline/cmdline.h"
59 #include "weapon/flak.h"
60 #include "weapon/beam.h"
61 #include "network/multi_rate.h"
62 #include "nebula/neblightning.h"
63 #include "hud/hud.h"
66 #include "network/multi_log.h"
67 #include "object/objectdock.h"
68 #include "cmeasure/cmeasure.h"
69 #include "parse/sexp.h"
70 #include "fs2netd/fs2netd_client.h"
71 #include "network/multi_sexp.h"
72 
73 // #define _MULTI_SUPER_WACKY_COMPRESSION
74 
75 #ifdef _MULTI_SUPER_WACKY_COMPRESSION
76 #define BITS 15
77 #define MAX_CODE ( ( 1 << BITS ) - 1 )
78 #define TABLE_SIZE 35023L
79 #define END_OF_STREAM 256
80 #define BUMP_CODE 257
81 #define FLUSH_CODE 258
82 #define FIRST_CODE 259
83 #define UNUSED -1
84 
85 typedef struct {
86  int code_value;
87  int parent_code;
88  char character;
89 } DICTIONARY;
90 
91 static DICTIONARY dict[TABLE_SIZE];
92 static char decode_stack[TABLE_SIZE];
93 static uint next_code;
94 static int current_code_bits;
95 static uint next_bump_code;
96 
97 typedef struct BitBuf {
98  ubyte mask;
99  int rack;
100  ubyte *data;
101 } BitBuf;
102 
103 void output_bits( BitBuf *bitbuf, uint code, int count )
104 {
105  uint mask;
106 
107  mask = 1L << ( count - 1 );
108  while ( mask != 0) {
109  if ( mask & code )
110  bitbuf->rack |= bitbuf->mask;
111  bitbuf->mask >>= 1;
112  if ( bitbuf->mask == 0 ) {
113  *bitbuf->data++=(ubyte)bitbuf->rack;
114  bitbuf->rack = 0;
115  bitbuf->mask = 0x80;
116  }
117  mask >>= 1;
118  }
119 }
120 
121 uint input_bits( BitBuf *bitbuf, int bit_count )
122 {
123  uint mask;
124  uint return_value;
125 
126  mask = 1L << ( bit_count - 1 );
127  return_value = 0;
128  while ( mask != 0) {
129  if ( bitbuf->mask == 0x80 ) {
130  bitbuf->rack = *bitbuf->data++;
131  if ( bitbuf->rack == EOF )
132  return END_OF_STREAM;
133  }
134  if ( bitbuf->rack & bitbuf->mask )
135  return_value |= mask;
136  mask >>= 1;
137  bitbuf->mask >>= 1;
138  if ( bitbuf->mask == 0 )
139  bitbuf->mask = 0x80;
140  }
141  return( return_value );
142 }
143 
144 
145 static void InitializeDictionary()
146 {
147  uint i;
148 
149  for ( i = 0 ; i < TABLE_SIZE ; i++ )
150  dict[i].code_value = UNUSED;
151 
152  next_code = FIRST_CODE;
153  current_code_bits = 9;
154  next_bump_code = 511;
155 
156 }
157 
158 static uint find_child_node( int parent_code, int child_character )
159 {
160  uint index;
161  int offset;
162 
163  index = ( child_character << ( BITS - 8 ) ) ^ parent_code;
164  if ( index == 0 )
165  offset = 1;
166  else
167  offset = TABLE_SIZE - index;
168  for ( ; ; ) {
169  if ( dict[ index ].code_value == UNUSED )
170  return( (uint) index );
171  if ( dict[ index ].parent_code == parent_code &&
172  dict[ index ].character == (char) child_character )
173  return( index );
174  if ( (int) index >= offset )
175  index -= offset;
176  else
177  index += TABLE_SIZE - offset;
178  }
179 }
180 
181 
182 static uint decode_string( uint count, uint code )
183 {
184  while ( code > 255 ) {
185  decode_stack[ count++ ] = dict[ code ].character;
186  code = dict[ code ].parent_code;
187  }
188  decode_stack[ count++ ] = (char) code;
189  return( count );
190 }
191 
192 int lzw_compress( ubyte *outputbuf, ubyte *inputbuf, int input_size )
193 {
194  BitBuf output;
195  int character;
196  int string_code;
197  uint index;
198  int i;
199 
200  // Init output bit buffer
201  output.rack = 0;
202  output.mask = 0x80;
203  output.data = outputbuf;
204 
205  InitializeDictionary();
206 
207  string_code = *inputbuf++;
208 
209  for ( i=1 ; i<input_size ; i++ ) {
210  character = *inputbuf++;
211  index = find_child_node( string_code, character );
212  if ( dict[ index ].code_value != - 1 )
213  string_code = dict[ index ].code_value;
214  else {
215  dict[ index ].code_value = next_code++;
216  dict[ index ].parent_code = string_code;
217  dict[ index ].character = (char) character;
218  output_bits( &output, (unsigned long) string_code, current_code_bits );
219  string_code = character;
220  if ( next_code > MAX_CODE ) {
221  output_bits( &output, (unsigned long) FLUSH_CODE, current_code_bits );
222  InitializeDictionary();
223  } else if ( next_code > next_bump_code ) {
224  output_bits( &output, (unsigned long) BUMP_CODE, current_code_bits );
225  current_code_bits++;
226  next_bump_code <<= 1;
227  next_bump_code |= 1;
228  }
229  }
230  }
231  output_bits( &output, (unsigned long) string_code, current_code_bits );
232  output_bits( &output, (unsigned long) END_OF_STREAM, current_code_bits);
233 
234  if ( output.mask != 0x80 )
235  *output.data++ = (ubyte)output.rack;
236 
237  return output.data-outputbuf;
238 }
239 
240 
241 int lzw_expand( ubyte *outputbuf, ubyte *inputbuf )
242 {
243  BitBuf input;
244  uint new_code;
245  uint old_code;
246  int character;
247  uint count;
248  uint counter;
249 
250  input.rack = 0;
251  input.mask = 0x80;
252  input.data = inputbuf;
253 
254  counter = 0;
255  for ( ; ; ) {
256  InitializeDictionary();
257  old_code = (uint) input_bits( &input, current_code_bits );
258  if ( old_code == END_OF_STREAM )
259  return counter;
260  character = old_code;
261  outputbuf[counter++] = ( ubyte )old_code;
262  for ( ; ; ) {
263  new_code = (uint) input_bits( &input, current_code_bits );
264  if ( new_code == END_OF_STREAM )
265  return counter;
266  if ( new_code == FLUSH_CODE )
267  break;
268  if ( new_code == BUMP_CODE ) {
269  current_code_bits++;
270  continue;
271  }
272  if ( new_code >= next_code ) {
273  decode_stack[ 0 ] = (char) character;
274  count = decode_string( 1, old_code );
275  } else {
276  count = decode_string( 0, new_code );
277  }
278  character = decode_stack[ count - 1 ];
279  while ( count > 0 )
280  outputbuf[counter++] = ( ubyte )decode_stack[ --count ];
281  dict[ next_code ].parent_code = old_code;
282  dict[ next_code ].character = (char) character;
283  next_code++;
284  old_code = new_code;
285  }
286  }
287 }
288 #endif
289 
290 // process a join request packet add
292 {
293  int packet_size = *size;
294  join_request jr_tmp;
295 
296  memcpy(&jr_tmp, jr, sizeof(join_request));
297 
298  jr_tmp.tracker_id = INTEL_INT(jr->tracker_id);
301 
302  ADD_DATA(jr_tmp);
303 
304  *size = packet_size;
305 }
306 
307 // process a join request packet get
309 {
310  int offset = *size;
311 
312  GET_DATA(*jr);
313 
314  jr->tracker_id = INTEL_INT(jr->tracker_id); //-V570
317 
318  *size = offset;
319 }
320 
322 {
323  int packet_size = *size;
324  net_addr addr_tmp;
325 
326  memcpy(&addr_tmp, addr, sizeof(net_addr));
327 
328  addr_tmp.type = INTEL_INT(addr->type);
329  addr_tmp.port = INTEL_SHORT(addr->port);
330 
331  ADD_DATA(addr_tmp);
332 
333  *size = packet_size;
334 }
335 
337 {
338  int offset = *size;
339 
340  GET_DATA(*addr);
341 
342  addr->type = INTEL_INT(addr->type); //-V570
343  addr->port = INTEL_SHORT(addr->port); //-V570
344 
345  *size = offset;
346 }
347 /*
348 void add_vector_data(ubyte *data, int *size, vec3d vec)
349 {
350  int packet_size = *size;
351 
352  ADD_FLOAT(vec.xyz.x);
353  ADD_FLOAT(vec.xyz.y);
354  ADD_FLOAT(vec.xyz.z);
355 
356  *size = packet_size;
357 }
358 
359 void get_vector_data(ubyte *data, int *size, vec3d vec)
360 {
361  int offset = *size;
362 
363  GET_FLOAT(vec.xyz.x);
364  GET_FLOAT(vec.xyz.y);
365  GET_FLOAT(vec.xyz.z);
366 
367  *size = offset;
368 }
369 */
370 // send the specified data packet to all players
372 {
373  // invalid
374  if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
375  return;
376  }
377 
378  // don't do it for single player
379  if(!(Game_mode & GM_MULTIPLAYER)){
380  return;
381  }
382 
383  // sanity checks
384  if(MULTIPLAYER_CLIENT){
385  // Assert(pl == Net_player);
386  if(pl != Net_player){
387  return;
388  }
389  } else {
390  // Assert(pl != Net_player);
391  if(pl == Net_player){
392  return;
393  }
394  }
395 
396  // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
397  if ((pl->s_info.unreliable_buffer_size + len) > MAX_PACKET_SIZE) {
400  }
401 
403 
404  memcpy(pl->s_info.unreliable_buffer + pl->s_info.unreliable_buffer_size, data, len);
406 }
407 
409 {
410  int i;
412 
413  // need to check for i > 1, hmmm... and connected. I don't know.
414  for (i = 0; i < MAX_PLAYERS; i++ ) {
415  if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
416  continue;
417  }
418 
419  // maybe ignore a player
420  if((ignore != NULL) && (&Net_players[i] == ignore)){
421  continue;
422  }
423 
424  // ingame joiners not waiting to select a ship doesn't get any packets
426  continue;
427  }
428 
429  // send it
430  multi_io_send(&Net_players[i], data, length);
431  }
432 }
433 
435 {
436  // invalid
437  if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
438  return;
439  }
440 
441  // don't do it for single player
442  if(!(Game_mode & GM_MULTIPLAYER)){
443  return;
444  }
445 
446  // send everything in
447  if (MULTIPLAYER_MASTER) {
449 
450  // add the bytes sent to this player
452  } else {
454  }
456 }
457 
458 // send the data packet to all players via their reliable sockets
460 {
461  // invalid
462  if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
463  return;
464  }
465 
466  // don't do it for single player
467  if(!(Game_mode & GM_MULTIPLAYER)){
468  return;
469  }
470 
471  // sanity checks
472  if(MULTIPLAYER_CLIENT){
473  // Assert(pl == Net_player);
474  if(pl != Net_player){
475  return;
476  }
477  } else {
478  // Assert(pl != Net_player);
479  if(pl == Net_player){
480  return;
481  }
482  }
483 
484  // If this packet will push the buffer over MAX_PACKET_SIZE, send the current send_buffer
485  if ((pl->s_info.reliable_buffer_size + len) > MAX_PACKET_SIZE) {
488  }
489 
491 
492  memcpy(pl->s_info.reliable_buffer + pl->s_info.reliable_buffer_size, data, len);
494 }
495 
497 {
498  int i;
500 
501  // need to check for i > 1, hmmm... and connected. I don't know.
502  for (i = 0; i < MAX_PLAYERS; i++ ) {
503  if ( !MULTI_CONNECTED(Net_players[i]) || (Net_player == &Net_players[i])){
504  continue;
505  }
506 
507  // maybe ignore a player
508  if((ignore != NULL) && (&Net_players[i] == ignore)){
509  continue;
510  }
511 
512  // ingame joiners not waiting to select a ship doesn't get any packets
514  continue;
515  }
516 
517  // send it
518  multi_io_send_reliable(&Net_players[i], data, length);
519  }
520 }
521 
523 {
524  // invalid
525  if((pl == NULL) || (NET_PLAYER_NUM(pl) >= MAX_PLAYERS)){
526  return;
527  }
528 
529  // don't do it for single player
530  if(!(Game_mode & GM_MULTIPLAYER)){
531  return;
532  }
533 
534  // send everything in
535  if(MULTIPLAYER_MASTER) {
537  } else if(Net_player != NULL){
539  }
541 }
542 
543 // send all buffered packets
545 {
546  int idx;
547 
548  // don't do it for single player
549  if(!(Game_mode & GM_MULTIPLAYER)){
550  return;
551  }
552 
553  // server
554  if(MULTIPLAYER_MASTER){
555  for(idx=0; idx<MAX_PLAYERS; idx++){
556  if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
557  // force unreliable data
558  if(Net_players[idx].s_info.unreliable_buffer_size > 0){
561  }
562 
563  // force reliable data
564  if(Net_players[idx].s_info.reliable_buffer_size > 0){
567  }
568  }
569  }
570  }
571  // clients
572  else if(Net_player != NULL){
573  // force unreliable data
577  }
578 
579  // force reliable data
583  }
584  }
585 }
586 
587 //*********************************************************************************************************
588 // Game Chat Packet
589 //*********************************************************************************************************
590 /*
591 struct fs2_game_chat_packet
592 {
593  char packet_signature; //0xC3
594  short from_player_id;
595  int server_msg;
596  char mode;
597 
598  // variable record
599  if (mode)
600  short to_player_id;
601  else
602  {
603  int i;
604  char expr[i];
605  }
606  int j;
607  char message[j];
608 
609 }
610 */
611 
612 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613 
614 // 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)
615 void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
616 {
618  int packet_size,idx;
619  bool undeliverable = true;
620 
622 
623  // add the id
624  ADD_SHORT(from->player_id);
625 
626  // add the message mode and if in MSG_TARGET mode, add who the target is
627  ADD_INT(server_msg);
628  mode = (ubyte)msg_mode;
629  ADD_DATA(mode);
630  switch(mode){
631  case MULTI_MSG_TARGET:
632  Assert(to != NULL);
633  ADD_SHORT(to->player_id);
634  break;
635  case MULTI_MSG_EXPR:
636  Assert(expr != NULL);
637  ADD_STRING(expr);
638  break;
639  }
640  // add the message itself
641  ADD_STRING( msg );
642 
644  switch(mode){
645  // message all players
646  case MULTI_MSG_ALL:
647  for(idx=0;idx<MAX_PLAYERS;idx++){
648  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from)){
649  multi_io_send_reliable(&Net_players[idx], data, packet_size);
650  }
651  }
652  break;
653 
654  // message only friendly players
655  case MULTI_MSG_FRIENDLY:
656  for(idx=0;idx<MAX_PLAYERS;idx++){
657  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)){
658  multi_io_send_reliable(&Net_players[idx], data, packet_size);
659  }
660  }
661  break;
662 
663  // message only hostile players
664  case MULTI_MSG_HOSTILE:
665  for(idx=0;idx<MAX_PLAYERS;idx++){
666  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)){
667  multi_io_send_reliable(&Net_players[idx], data, packet_size);
668  }
669  }
670  break;
671 
672  // message the player's target
673  case MULTI_MSG_TARGET:
674  Assert(to != NULL);
675  if(MULTI_CONNECTED((*to)) && !MULTI_STANDALONE((*to))){
676  multi_io_send_reliable(to, data, packet_size);
677  }
678  break;
679 
680  // message all players who match the expression string
681  case MULTI_MSG_EXPR:
682  Assert(expr != NULL);
683  for(idx=0;idx<MAX_PLAYERS;idx++){
684  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (&Net_players[idx] != from) && multi_msg_matches_expr(&Net_players[idx],expr) ){
685  multi_io_send_reliable(&Net_players[idx], data, packet_size);
686  undeliverable = false;
687  }
688  }
689  break;
690  }
691 
692  // if the message can't be delivered, notify the player
693  if (undeliverable) {
694  switch(mode){
695  case MULTI_MSG_EXPR:
696  // if the message came from the server
697  if (from == Net_player) {
698  multi_display_chat_msg ("Unable to send message, player does not exist", 0, 0);
699  }
700  // otherwise send a message back to the player
701  else {
702  send_game_chat_packet(Net_player, "Unable to send message, player does not exist", MULTI_MSG_TARGET, from, NULL, 1);
703  }
704  break;
705  }
706  }
707  }
708  // send to the server, who will take care of routing it
709  else {
710  multi_io_send_reliable(Net_player, data, packet_size);
711  }
712 }
713 
714 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
715 
716 // process a general game chat packet, if we're the standalone we should rebroadcast
718 {
719  int offset;
720  ubyte mode;
721  int color_index,player_index,to_player_index,should_display,server_msg;
723  char expr[255];
724  short from, to;
725 
726  offset = HEADER_LENGTH;
727 
728  // get the id of the sender
729  GET_SHORT(from);
730 
731  // determine if this is a server message
732  GET_INT(server_msg);
733 
734  // get the mode
735  GET_DATA(mode);
736 
737  // if targeting a specific player, get the address
738  to = -1;
739  switch(mode){
740  case MULTI_MSG_TARGET:
741  GET_SHORT(to);
742  break;
743  case MULTI_MSG_EXPR:
744  GET_STRING(expr);
745  break;
746  }
747  // get the message itself
748  GET_STRING(msg);
749  PACKET_SET_SIZE();
750 
751  // get the index of the sending player
752  color_index = find_player_id(from);
753  player_index = color_index;
754 
755  // if we couldn't find the player - bail
756  if(player_index == -1){
757  nprintf(("Network","Could not find player for processing game chat packet!\n"));
758  return;
759  }
760 
761  should_display = 0;
762 
763  // if we're the server, determine what to do with the packet here
765  // if he's targeting a specific player, find out who it is
766  if(mode == MULTI_MSG_TARGET){
767  to_player_index = find_player_id(to);
768  } else {
769  to_player_index = -1;
770  }
771 
772  // if we couldn't find who sent the message or who should be getting the message, the bail
773  if(((to_player_index == -1) && (mode == MULTI_MSG_TARGET)) || (player_index == -1)){
774  return;
775  }
776 
777  // determine if _I_ should be seeing the text
779  should_display = 1;
780  }
781  // check against myself for several specific cases
782  else {
783  if((mode == MULTI_MSG_ALL) ||
784  ((mode == MULTI_MSG_FRIENDLY) && (Net_player->p_info.team == Net_players[player_index].p_info.team)) ||
785  ((mode == MULTI_MSG_HOSTILE) && (Net_player->p_info.team != Net_players[player_index].p_info.team)) ||
786  ((mode == MULTI_MSG_TARGET) && (MY_NET_PLAYER_NUM == to_player_index)) ||
787  ((mode == MULTI_MSG_EXPR) && multi_msg_matches_expr(Net_player,expr)) ){
788  should_display = 1;
789  }
790  }
791 
792  // if we're the server of a game, we need to rebroadcast to all other players
793  switch(mode){
794  // individual target mission
795  case MULTI_MSG_TARGET:
796  // if I was the inteneded target, or we couldn't find the intended target, don't rebroadcast
797  if(to_player_index != MY_NET_PLAYER_NUM){
798  send_game_chat_packet(&Net_players[player_index], msg, (int)mode, &Net_players[to_player_index], NULL, server_msg);
799  }
800  break;
801  // expression mode
802  case MULTI_MSG_EXPR:
803  send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, expr, server_msg);
804  break;
805  // all other modes
806  default :
807  send_game_chat_packet(&Net_players[player_index], msg, (int)mode, NULL, NULL, server_msg);
808  break;
809  }
810  }
811  // if a client receives this packet, its always ok for him to display it
812  else {
813  should_display = 1;
814  }
815 
816  // if we're not on a standalone
817  if(should_display){
818  if(server_msg == 2){
819  HUD_printf(msg);
820  } else {
821  multi_display_chat_msg(msg, player_index, !server_msg);
822  }
823  }
824 }
825 
826 
827 //*********************************************************************************************************
828 // Hud Message packet
829 //*********************************************************************************************************
830 /*
831 struct fs2_game_chat_packet
832 {
833  char packet_signature; //0xC1 HUD_MSG
834  int msg_size;
835  char msg[msg_size];
836 }
837 */
838 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
839 
840 // broadcast a hud message to all players
841 void send_hud_msg_to_all( char* msg )
842 {
844  int packet_size;
845 
846  // only the server should be sending this packet
848 
849  ADD_STRING(msg);
850 
851  multi_io_send_to_all( data, packet_size );
852 }
853 
854 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
855 
856 // process an incoming hud message packet
858 {
859  int offset;
860  char msg_buffer[255];
861 
862  offset = HEADER_LENGTH;
863 
864  GET_STRING(msg_buffer);
865  PACKET_SET_SIZE();
866 
867  // this is the only safe place to do this since only in the mission is the HUD guaranteed to be inited
868  if(Game_mode & GM_IN_MISSION){
869  HUD_printf(msg_buffer);
870  }
871 }
872 
873 
874 //*********************************************************************************************************
875 // Join Packet
876 //*********************************************************************************************************
877 /*
878 struct fs2_game_chat_packet
879 {
880  char packet_signature; //0xC1 HUD_MSG
881  int msg_size;
882  char msg[msg_size];
883 }
884 */
885 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
886 
887 // send a join packet request to the specified address (should be a server)
889 {
891  int packet_size;
892 
893  // build the header and add the request
894  BUILD_HEADER(JOIN);
895  add_join_request(data, &packet_size, jr);
896 
897  psnet_send(addr, data, packet_size);
898 }
899 
900 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
901 
902 // process an incoming join request packet
904 {
905  join_request jr;
906  int offset;
907  int ret_code;
908  int host_restr_mode;
909  int team0_avail,team1_avail;
910  char join_string[255];
911  net_addr addr;
912 
913  // only the server of the game should ever receive this packet
915  return;
916 
917  offset = HEADER_LENGTH;
918 
919  // read in the request info
920  memset(&jr,0,sizeof(join_request));
921 
922  get_join_request(data, &offset, &jr);
923 
924  PACKET_SET_SIZE();
925 
926  // fill in the address information of where this came from
927  fill_net_addr(&addr, hinfo->addr, hinfo->port);
928 
929  // determine if we should accept this guy, or return a reason we should reject him
930  // see the DENY_* codes in multi.h
931  ret_code = multi_eval_join_request(&jr,&addr);
932 
933  // evaluate the return code
934  switch(ret_code)
935  {
936  // he should be accepted
937  case -1 :
938  break;
939 
940  // we have to query the host because this is a restricted game
941  case JOIN_QUERY_RESTRICTED :
943  // notify the host of the event
945  }
946 
947  // set the query timestamp
950 
951  // determine what mode we're in
952  host_restr_mode = -1;
953  memset(join_string,0,255);
955  multi_player_ships_available(&team0_avail,&team1_avail);
956 
957  if(team0_avail && team1_avail){
958  host_restr_mode = MULTI_JOIN_RESTR_MODE_4;
959  sprintf(join_string,"Player %s has tried to join. Accept on team 1 or 2 ?",jr.callsign);
960  } else if(team0_avail && !team1_avail){
961  host_restr_mode = MULTI_JOIN_RESTR_MODE_2;
962  sprintf(join_string,"Player %s has tried to join team 0, accept y/n ? ?",jr.callsign);
963  } else if(!team0_avail && team1_avail){
964  host_restr_mode = MULTI_JOIN_RESTR_MODE_3;
965  sprintf(join_string,"Player %s has tried to join team 1, accept y/n ?",jr.callsign);
966  }
967  } else if(Netgame.mode == NG_MODE_RESTRICTED){
968  host_restr_mode = MULTI_JOIN_RESTR_MODE_1;
969  sprintf(join_string,XSTR("Player %s has tried to join, accept y/n ?",715),jr.callsign);
970  }
971  Assert(host_restr_mode != -1);
972 
973  // store the request info
974  memcpy(&Multi_restr_join_request,&jr,sizeof(join_request));
975  memcpy(&Multi_restr_addr,&addr,sizeof(net_addr));
976  Multi_join_restr_mode = host_restr_mode;
977 
978  // if i'm the standalone server, I need to send a query to the host
979  if(Game_mode & GM_STANDALONE_SERVER){
981  } else {
982  HUD_printf(join_string);
983  }
984 
985  // NETLOG
986  ml_printf(NOX("Receive restricted join request from %s"), jr.callsign);
987 
988  return;
989 
990  // he'e being denied for some reason
991  default :
992  // send him the reason he is being denied
993  send_deny_packet(&addr,ret_code);
995  return;
996  }
997 
998  // process the rest of the request
1000 }
1001 
1002 //*********************************************************************************************************
1003 // New Player Packet
1004 //*********************************************************************************************************
1005 /*
1006 struct fs2_new_player_packet
1007 {
1008  char packet_signature; // 0xB4 NOTIFY_NEW_PLAYER
1009  int new_player_num;
1010  net_addr player_addr;
1011  short player_id;
1012  int flags;
1013 
1014  int i;
1015  char callsign[i];
1016 
1017  int j;
1018  char plyr_image_filename[j];
1019 
1020  int k;
1021  char plyr_squad_filename[k];
1022 
1023  int l;
1024  char plyr_pxo_squad_name[l];
1025 }
1026 */
1027 
1028 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1029 
1030 // send a notification that a new player has joined the game (if target != NULL, broadcast the packet)
1031 void send_new_player_packet(int new_player_num,net_player *target)
1032 {
1034  int packet_size = 0;
1035 
1037 
1038  // add the new player's info
1039  ADD_INT(new_player_num);
1040 // ADD_DATA(Net_players[new_player_num].p_info.addr);
1041  add_net_addr(data, &packet_size, &Net_players[new_player_num].p_info.addr);
1042  ADD_SHORT(Net_players[new_player_num].player_id);
1043  ADD_INT(Net_players[new_player_num].flags);
1044  ADD_STRING(Net_players[new_player_num].m_player->callsign);
1045  ADD_STRING(Net_players[new_player_num].m_player->image_filename);
1046  ADD_STRING(Net_players[new_player_num].m_player->m_squad_filename);
1047  ADD_STRING(Net_players[new_player_num].p_info.pxo_squad_name);
1048 
1049  val = (ubyte)Net_players[new_player_num].p_info.team;
1050  ADD_DATA(val);
1051 
1052  // broadcast the data
1053  if(target != NULL){
1054  multi_io_send_reliable(target, data, packet_size);
1055  } else {
1056  multi_io_send_to_all_reliable(data, packet_size);
1057  }
1058 }
1059 
1060 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1061 
1062 // process a notification for a new player who has joined the game
1064 {
1065  int already_in_game = 0;
1066  int offset, new_player_num,player_num,new_flags;
1067  net_addr new_addr;
1068  char new_player_name[CALLSIGN_LEN+2] = "";
1069  char new_player_image[MAX_FILENAME_LEN+1] = "";
1070  char new_player_squad[MAX_FILENAME_LEN+1] = "";
1071  char new_player_pxo_squad[LOGIN_LEN+1] = "";
1072  char notify_string[256];
1073  ubyte team;
1074  short new_id;
1075 
1076  offset = HEADER_LENGTH;
1077 
1078  // get the new players information
1079  GET_INT(new_player_num);
1080 // GET_DATA(new_addr);
1081  get_net_addr(data, &offset, &new_addr);
1082  GET_SHORT(new_id);
1083  GET_INT(new_flags);
1084  GET_STRING(new_player_name);
1085  GET_STRING(new_player_image);
1086  GET_STRING(new_player_squad);
1087  GET_STRING(new_player_pxo_squad);
1088  GET_DATA(team);
1089  PACKET_SET_SIZE();
1090 
1091  player_num = multi_find_open_player_slot();
1092  Assert(player_num != -1);
1093 
1094  // note that this new code does not check for duplicate IPs. It merely checks to see if
1095  // the slot referenced by new_player_num is already occupied by a connected player
1096  if(MULTI_CONNECTED(Net_players[new_player_num])){
1097  already_in_game=1;
1098  }
1099 
1100  // if he's not alreayd in the game for one reason or another
1101  if ( !already_in_game ) {
1102  if ( Game_mode & GM_IN_MISSION ){
1103  HUD_sourced_printf(HUD_SOURCE_COMPUTER, XSTR("%s has entered the game\n",716), new_player_name);
1104  }
1105 
1106  // create the player
1107  if(new_flags & NETINFO_FLAG_OBSERVER){
1108  multi_obs_create_player(new_player_num,new_player_name,&new_addr,&Players[player_num]);
1109  Net_players[new_player_num].flags |= new_flags;
1110  } else {
1111  multi_create_player( new_player_num, &Players[player_num],new_player_name, &new_addr, -1, new_id );
1112  Net_players[new_player_num].flags |= new_flags;
1113  }
1114 
1115  // copy in the filename
1116  if(new_player_image[0] != '\0'){
1117  strcpy_s(Net_players[new_player_num].m_player->image_filename, new_player_image);
1118  } else {
1119  strcpy_s(Net_players[new_player_num].m_player->image_filename, "");
1120  }
1121  // copy his pilot squad filename
1122  Net_players[new_player_num].m_player->insignia_texture = -1;
1123  player_set_squad_bitmap(Net_players[new_player_num].m_player, new_player_squad, true);
1124 
1125  // copy in his pxo squad name
1126  strcpy_s(Net_players[new_player_num].p_info.pxo_squad_name, new_player_pxo_squad);
1127 
1128  // since we just created the player, set the last_heard_time here.
1130 
1131  Net_players[new_player_num].p_info.team = team;
1132 
1133  Net_players[new_player_num].player_id = new_id;
1134 
1135  // zero out this players ping
1136  multi_ping_reset(&Net_players[new_player_num].s_info.ping);
1137 
1138  // add a chat message
1139  if(*Net_players[new_player_num].m_player->callsign){
1140  sprintf(notify_string,XSTR("<%s has joined>",717),Net_players[new_player_num].m_player->callsign);
1141  multi_display_chat_msg(notify_string,0,0);
1142  }
1143  }
1144 
1145  // NETLOG
1146  ml_printf(NOX("Received notification of new player %s"), Net_players[new_player_num].m_player->callsign);
1147 
1148  // let the current ui screen know someone joined
1149  switch(gameseq_get_state()){
1151  multi_create_handle_join(&Net_players[new_player_num]);
1152  break;
1154  multi_jw_handle_join(&Net_players[new_player_num]);
1155  break;
1156  }
1157 }
1158 
1159 //*********************************************************************************************************
1160 // Accept Player Data Packet
1161 //*********************************************************************************************************
1162 /*
1163 struct fs2_accept_player_data
1164 {
1165  char packet_signature; //ACCEPT_PLAYER_DATA
1166  ubyte stop;
1167  int player_num;
1168  net_addr plyr_addr;
1169  int player_id;
1170 
1171  int i;
1172  char callsign[i];
1173 
1174  int j;
1175  char plr_image_filename[j];
1176 
1177  int k;
1178  char plr_squad_filename[k]
1179 
1180  int l
1181  char plr_pxo_squadname[l];
1182 
1183  int flags;
1184 
1185  if (is_ingame)
1186  int net_signature;
1187 
1188 
1189 };
1190 */
1191 
1192 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1193 
1194 #define PLAYER_DATA_SLOP 100
1195 
1196 void send_accept_player_data( net_player *npp, int is_ingame )
1197 {
1198  int packet_size;
1199  int i;
1200  ubyte data[MAX_PACKET_SIZE], stop;
1201 
1203 
1204  // add in the netplayer data for all players
1205  stop = APD_NEXT;
1206  for (i=0; i<MAX_PLAYERS; i++) {
1207  // skip non connected players
1208  if ( !MULTI_CONNECTED(Net_players[i]) ){
1209  continue;
1210  }
1211 
1212  // skip this new player's entry
1213  if ( npp->player_id == Net_players[i].player_id ){
1214  continue;
1215  }
1216 
1217  // add the stop byte
1218  ADD_DATA(stop);
1219 
1220  // add the player's number
1221  ADD_INT(i);
1222 
1223  // add the player's address
1224  // ADD_DATA(Net_players[i].p_info.addr);
1225  add_net_addr(data, &packet_size, &Net_players[i].p_info.addr);
1226 
1227  // add his id#
1228  ADD_SHORT(Net_players[i].player_id);
1229 
1230  // add his callsign
1231  ADD_STRING(Net_players[i].m_player->callsign);
1232 
1233  // add his image filename
1234  ADD_STRING(Net_players[i].m_player->image_filename);
1235 
1236  // add his squad filename
1237  ADD_STRING(Net_players[i].m_player->m_squad_filename);
1238 
1239  // add his PXO squad name
1240  ADD_STRING(Net_players[i].p_info.pxo_squad_name);
1241 
1242  // add his flags
1243  ADD_INT(Net_players[i].flags);
1244 
1245  // add his object's net sig
1246  if ( is_ingame ) {
1247  ADD_USHORT( Objects[Net_players[i].m_player->objnum].net_signature );
1248  }
1249 
1250  if ( (packet_size + PLAYER_DATA_SLOP) > MAX_PACKET_SIZE ) {
1251  stop = APD_END_PACKET;
1252  ADD_DATA(stop);
1253  multi_io_send_reliable( npp, data, packet_size );
1255  stop = APD_NEXT;
1256  }
1257 
1258  }
1259 
1260  // add the stop byte
1261  stop = APD_END_DATA;
1262  ADD_DATA(stop);
1263  multi_io_send_reliable(npp, data, packet_size);
1264 }
1265 
1266 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1267 
1268 // process the player data from the server
1270 {
1271  int offset, player_num, player_slot_num, new_flags;
1272  char name[CALLSIGN_LEN + 1] = "";
1273  char image_name[MAX_FILENAME_LEN + 1] = "";
1274  char squad_name[MAX_FILENAME_LEN + 1] = "";
1275  char pxo_squad_name[LOGIN_LEN+1] = "";
1276  short player_id;
1277  net_addr addr;
1278  ubyte stop;
1279  ushort ig_signature;
1280 
1281  offset = HEADER_LENGTH;
1282 
1283  GET_DATA(stop);
1284  while ( stop == APD_NEXT ) {
1285  player_slot_num = multi_find_open_player_slot();
1286  Assert(player_slot_num != -1);
1287 
1288  // get the player's number
1289  GET_INT(player_num);
1290 
1291  // add the player's address
1292  // GET_DATA(addr);
1293  get_net_addr(data, &offset, &addr);
1294 
1295  // get the player's id#
1296  GET_SHORT(player_id);
1297 
1298  // get his callsign
1299  GET_STRING(name);
1300 
1301  // add his image filename
1302  GET_STRING(image_name);
1303 
1304  // get his squad logo filename
1305  GET_STRING(squad_name);
1306 
1307  // get his PXO squad name
1308  GET_STRING(pxo_squad_name);
1309 
1310  // get his flags
1311  GET_INT(new_flags);
1312 
1313  if (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) {
1314  if (!multi_obs_create_player(player_num, name, &addr, &Players[player_slot_num])) {
1315  Int3();
1316  }
1317 
1318  } else {
1319  // the error handling here is less than stellar. We should probably put up a popup and go
1320  // back to the main menu. But then again, this should never ever happen!
1321  if ( !multi_create_player(player_num, &Players[player_slot_num],name, &addr, -1, player_id) ) {
1322  Int3();
1323  }
1324  }
1325 
1326  // copy his image filename
1327  strcpy_s(Net_players[player_num].m_player->image_filename, image_name);
1328 
1329  // copy his pilot squad filename
1330  Net_players[player_num].m_player->insignia_texture = -1;
1331  player_set_squad_bitmap(Net_players[player_num].m_player, squad_name, true);
1332 
1333  // copy his pxo squad name
1334  strcpy_s(Net_players[player_num].p_info.pxo_squad_name, pxo_squad_name);
1335 
1336  // set his player id#
1337  Net_players[player_num].player_id = player_id;
1338 
1339  // mark him as being connected
1340  Net_players[player_num].flags |= NETINFO_FLAG_CONNECTED;
1341  Net_players[player_num].flags |= new_flags;
1342 
1343  // set the server pointer
1344  if ( Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER ) {
1345  Netgame.server = &Net_players[player_num];
1347 
1348  // also - always set the server address to be where this data came from, NOT from
1349  // the data in the packet
1350  fill_net_addr(&Net_players[player_num].p_info.addr, hinfo->addr, hinfo->port);
1351  }
1352 
1353  // set the host pointer
1354  if ( Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST ) {
1355  Netgame.host = &Net_players[player_num];
1356  }
1357 
1358  // read in the player's object net signature and store as his objnum for now
1360  GET_USHORT( ig_signature );
1361  Net_players[player_num].m_player->objnum = ig_signature;
1362  }
1363 
1364  // get the stop byte
1365  GET_DATA(stop);
1366  }
1367  PACKET_SET_SIZE();
1368 
1369  if ( stop == APD_END_DATA ) {
1370  // if joining a game automatically, set the connect address to NULl so we don't try and
1371  // do this next time we enter a game
1372  if (Cmdline_connect_addr != NULL) {
1373  Cmdline_connect_addr = NULL;
1374  }
1375 
1376  // send my stats to the server if I'm not in observer mode
1379  }
1380 
1381  // if i'm being accepted as a host, then move into the host setup state
1383  // set my permission bits
1386 
1388  }
1389 
1392 
1393  // since observers can join 1 of 2 ways, only do this if we're not doing an ingame observer join
1396  }
1397  }
1398 
1401  }
1402 
1404  // flag myself as being an ingame joiner
1406 
1407  // move myself into the ingame join mission sync state
1410  }
1411 
1412  // update my options on the server
1414 
1415  // if we're in PXO mode, mark it down in our player struct
1419  }
1420  }
1421 }
1422 
1423 
1424 //*********************************************************************************************************
1425 // Accept Player Packet
1426 //*********************************************************************************************************
1427 /*
1428 struct fs2_accept_packet
1429 {
1430  char packet_signature;
1431  int code;
1432 
1433  if (code & ACCEPT_INGAME)
1434  {
1435  int gm_mis_fname_len;
1436  char mission_filename[gm_mis_fname_len];
1437  unsigned char ingame_joining_team;
1438  if (ingame_joining_team == 1)
1439  unsigned char ingame_join_team;
1440 
1441  }
1442 
1443  int skill_level;
1444  int player_num;
1445  short player_id;
1446  int netgame_type_flags;
1447 
1448 }
1449 */
1450 // send an accept packet to a client in response to a request to join the game
1451 void send_accept_packet(int new_player_num, int code, int ingame_join_team)
1452 {
1453  int packet_size, i;
1455  char notify_string[256];
1456 
1457  // sanity
1458  Assert(new_player_num >= 0);
1459 
1460  // setup his "reliable" socket
1462 
1463  // build the packet header
1464  packet_size = 0;
1465  BUILD_HEADER(ACCEPT);
1466 
1467  // add the accept code
1468  ADD_INT(code);
1469 
1470  // add code specific accept data
1471  if (code & ACCEPT_INGAME) {
1472  // the game filename
1474 
1475  // if he is joining on a specific team, mark it here
1476  if(ingame_join_team != -1){
1477  val = 1;
1478  ADD_DATA(val);
1479  val = (ubyte)ingame_join_team;
1480  ADD_DATA(val);
1481  } else {
1482  val = 0;
1483  ADD_DATA(val);
1484  }
1485  }
1486 
1487  if (code & ACCEPT_OBSERVER) {
1488  Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1489  }
1490 
1491  if (code & ACCEPT_HOST) {
1492  Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1493  }
1494 
1495  if (code & ACCEPT_CLIENT) {
1496  Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1497  }
1498 
1499  // add the current skill level setting on the host
1500  // sanity check - reset skill level to default before sending if out of range
1501  if (Game_skill_level < 0 || Game_skill_level >= NUM_SKILL_LEVELS) {
1502  Warning(LOCATION, "Trying to send packet containing invalid skill level %i! Valid range 0 to %i. Resetting to default.", Game_skill_level, NUM_SKILL_LEVELS);
1504  }
1506 
1507  // add this guys player num
1508  ADD_INT(new_player_num);
1509 
1510  // add his player id
1511  ADD_SHORT(Net_players[new_player_num].player_id);
1512 
1513  // add netgame type flags
1515 
1516  // actually send the packet
1517  psnet_send(&Net_players[new_player_num].p_info.addr, data, packet_size);
1518 
1519  // if he's not an observer, inform all the other players in the game about him
1520  // inform the other players in the game about this new player
1521  for (i=0; i<MAX_PLAYERS; i++) {
1522  // skip unconnected players as well as this new guy himself
1523  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])) {
1524  continue;
1525  }
1526 
1527  // send the new packet
1528  send_new_player_packet(new_player_num,&Net_players[i]);
1529  }
1530 
1531  // add a chat message
1532  if(*Net_players[new_player_num].m_player->callsign){
1533  sprintf(notify_string,XSTR("<%s has joined>",717), Net_players[new_player_num].m_player->callsign);
1534  multi_display_chat_msg(notify_string, 0, 0);
1535  }
1536 
1537  // handle any team vs. team details
1538  if (!(code & ACCEPT_OBSERVER)) {
1539  multi_team_handle_join(&Net_players[new_player_num]);
1540  }
1541 
1542  // NETLOG
1543  if(Net_players[new_player_num].tracker_player_id >= 0){
1544  ml_printf(NOX("Server accepted %s (tracker id %d) as new client"), Net_players[new_player_num].m_player->callsign, Net_players[new_player_num].tracker_player_id);
1545  } else {
1546  ml_printf(NOX("Server accepted %s as new client"), Net_players[new_player_num].m_player->callsign);
1547  }
1548 }
1549 
1550 // process an accept packet from the server
1551 extern int Select_default_ship;
1552 
1554 {
1555  int code, my_player_num, offset;
1556  ubyte val,team = 0;
1557  short player_id;
1558 
1559  // get the accept code
1560  offset = HEADER_LENGTH;
1561 
1562  GET_INT(code);
1563 
1564  // read in the accept code specific data
1565  val = 0;
1566  if (code & ACCEPT_INGAME) {
1567  // the game filename
1569  mprintf(("Got mission filename %s\n", Game_current_mission_filename));
1570  Select_default_ship = 0;
1571 
1572  // determine if I'm being placed on a team
1573  GET_DATA(val);
1574  if(val){
1575  GET_DATA(team);
1576  }
1577  }
1578 
1579  if (code & ACCEPT_OBSERVER) {
1580  Assert(!(code & (ACCEPT_CLIENT | ACCEPT_HOST)));
1581  }
1582 
1583  if (code & ACCEPT_HOST) {
1584  Assert(!(code & (ACCEPT_CLIENT | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1585  }
1586 
1587  if (code & ACCEPT_CLIENT) {
1588  Assert(!(code & (ACCEPT_HOST | ACCEPT_OBSERVER | ACCEPT_INGAME)));
1589  }
1590 
1591  // fill in the netgame server address
1592  fill_net_addr( &Netgame.server_addr, hinfo->addr, hinfo->port );
1593 
1594  // get the skill level setting
1596  if (Game_skill_level < 0 || Game_skill_level >= NUM_SKILL_LEVELS) {
1597  Warning(LOCATION, "Received packet containing invalid skill level %i! Valid range 0 to %i. Resetting to default.", Game_skill_level, NUM_SKILL_LEVELS);
1599  }
1600 
1601  // get my netplayer number
1602  GET_INT(my_player_num);
1603 
1604  // get my id #
1605  GET_SHORT(player_id);
1606 
1607  // get netgame type flags
1609 
1610  // setup the Net_players structure for myself first
1611  Net_player = &Net_players[my_player_num];
1612  Net_player->flags = 0;
1614  Net_player->player_id = player_id;
1616  // stuff_netplayer_info( Net_player, &Psnet_my_addr, Ships[Objects[Player->objnum].instance].ship_info_index, Player );
1619  Net_player->p_info.team = team;
1620 
1621  // determine if I have a CD
1622  if(Multi_has_cd){
1624  }
1625 
1626  // set accept code in netplayer for this guy
1627  if ( code & ACCEPT_INGAME ){
1629  }
1630  if ( code & ACCEPT_OBSERVER ){
1632  }
1633  if ( code & ACCEPT_HOST ){
1635  }
1636  if ( code & ACCEPT_CLIENT ){
1638  }
1639 
1640  // if I have hacked data
1641  if(game_hacked_data()){
1643  }
1644 
1645  // if we're supposed to flush our local data cache, do so now
1648  }
1649 
1651  Net_player->sv_last_pl = -1;
1653  Net_player->cl_last_pl = -1;
1654 
1655  // intiialize endgame stuff
1657 
1658  PACKET_SET_SIZE();
1659 
1660  // make a call to psnet to initialize and try to connect with the server.
1664  }
1665 }
1666 
1667 //*********************************************************************************************************
1668 // Player Leave Packet
1669 //*********************************************************************************************************
1670 /*
1671 struct fs2_leave_game_packet
1672 {
1673  char packet_signature;
1674  char kicked_reason;
1675  short player_id;
1676 
1677 }
1678 */
1679 // send a notice that the player at net_addr is leaving (if target is NULL, the broadcast the packet)
1680 void send_leave_game_packet(short player_id, int kicked_reason, net_player *target)
1681 {
1683  char val;
1684  int packet_size = 0;
1685 
1687 
1688  // add a flag indicating whether he was kicked or not
1689  val = (char)kicked_reason;
1690  ADD_DATA(val);
1691 
1692  if (player_id < 0) {
1694 
1695  // inform the host that we are leaving the game
1697  multi_io_send_to_all_reliable(data, packet_size);
1698  } else {
1699  multi_io_send_reliable(Net_player, data, packet_size);
1700  }
1701  }
1702  // this is the case where to server is tossing a player (or indicating a respawned player has quit or become an observer)
1703  // so he has to tell everyone that this guy left
1704  else {
1705  nprintf(("Network","Sending a leave game packet to all players (server)\n"));
1706 
1707  // a couple of important checks
1708  Assert(player_id != Net_player->player_id);
1710 
1711  // add the id of the guy to be kicked
1712  ADD_SHORT(player_id);
1713 
1714  // broadcast to everyone
1715  if (target == NULL) {
1716  multi_io_send_to_all_reliable(data, packet_size);
1717  } else {
1718  multi_io_send_reliable(target, data, packet_size);
1719  }
1720  }
1721 }
1722 
1723 // process a notification that a player has left the game
1725 {
1726  int offset;
1727  short deader_id;
1728  int player_num;
1729  char kicked_reason;
1730  char str[512];
1731 
1732  offset = HEADER_LENGTH;
1733 
1734  // get whether he was kicked
1735  GET_DATA(kicked_reason);
1736 
1737  // get the address of the guy who is to leave
1738  GET_SHORT(deader_id);
1739  PACKET_SET_SIZE();
1740 
1741  // determine who is dropping and printf out a notification
1742  player_num = find_player_id(deader_id);
1743  if (player_num == -1) {
1744  nprintf(("Network", "Received leave game packet for unknown player, ignoring\n"));
1745  return;
1746 
1747  } else {
1748  nprintf(("Network", "Received a leave game notice for %s\n", Net_players[player_num].m_player->callsign));
1749  }
1750 
1751  // a hook to display that a player was kicked
1752  if (kicked_reason >= 0){
1753  // if it was me that was kicked, leave the game
1754  if((Net_player != NULL) && (Net_player->player_id == deader_id)){
1755  int notify_code;
1756 
1757  switch(kicked_reason){
1758  case KICK_REASON_BAD_XFER:
1759  notify_code = MULTI_END_NOTIFY_KICKED_BAD_XFER;
1760  break;
1761  case KICK_REASON_CANT_XFER:
1762  notify_code = MULTI_END_NOTIFY_KICKED_CANT_XFER;
1763  break;
1766  break;
1767  default:
1768  notify_code = MULTI_END_NOTIFY_KICKED;
1769  break;
1770  }
1771 
1772  multi_quit_game(PROMPT_NONE, notify_code);
1773  return;
1774 
1775  // otherwise indicate someone was kicked
1776  } else {
1777  nprintf(("Network","%s was kicked\n",Net_players[player_num].m_player->callsign));
1778 
1779  // display the result
1780  memset(str, 0, 512);
1781  multi_kick_get_text(&Net_players[player_num], kicked_reason, str);
1782  multi_display_chat_msg(str, player_num, 0);
1783  }
1784  }
1785 
1786  // first of all, if we're the master, we should be rebroadcasting this packet
1788  char msg[255];
1789 
1790  sprintf(msg, XSTR("%s has left the game",719), Net_players[player_num].m_player->callsign );
1791 
1792  if (!(Game_mode & GM_STANDALONE_SERVER)){
1794  }
1795 
1796  send_hud_msg_to_all(msg);
1797  multi_io_send_to_all_reliable(data, offset);
1798  }
1799 
1800  // leave the game if the host and/or master has dropped
1801  /*
1802  if (((Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER) || (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)) ) {
1803  nprintf(("Network","Host and/or server has left the game - aborting...\n"));
1804 
1805  // NETLOG
1806  ml_string(NOX("Host and/or server has left the game"));
1807 
1808  // if the host leaves in the debriefing state, we should still wait until the player selects accept before we quit
1809  if (gameseq_get_state() != GS_STATE_DEBRIEF) {
1810  multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_SERVER_LEFT);
1811  }
1812 
1813  delete_player(player_num);
1814  } else {
1815  */
1816  delete_player(player_num);
1817 
1818  // OSAPI GUI stuff (if standalone)
1820  // returns true if we should reset the standalone
1821  if (std_remove_player(&Net_players[player_num])) {
1822  nprintf(("Network", "Should reset!!\n"));
1823  return;
1824  }
1825 
1826  // update these gui vals
1829  }
1830 }
1831 
1832 //*********************************************************************************************************
1833 // Game active packet
1834 //*********************************************************************************************************
1835 /*
1836 struct fs2_game_active_packet
1837 {
1838  char packet_signature;
1839  ubyte server_version;
1840  ubyte compat_version;
1841  int len1;
1842  char netgame_name[len1];
1843  int len2;
1844  char netgame_mission_name[len2];
1845  int len3;
1846  char netgame_title[len3];
1847  ubyte num_players;
1848  unsigned short flags;
1849 }
1850 */
1851 // send information about this currently active game to the specified address
1853 {
1854  int packet_size;
1855  ushort flags;
1857 
1858  // build the header and add the data
1860 
1861  // add the server version and compatible version #
1863  ADD_DATA(val);
1865  ADD_DATA(val);
1866 
1870  val = (ubyte)multi_num_players();
1871  ADD_DATA(val);
1872 
1873  // add the proper flags
1874  flags = 0;
1876  flags |= AG_FLAG_PASSWD;
1877  }
1878 
1879  // proper netgame type flags
1881  flags |= AG_FLAG_TEAMS;
1882  } else if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
1883  flags |= AG_FLAG_DOGFIGHT;
1884  } else {
1885  flags |= AG_FLAG_COOP;
1886  }
1887 
1888  // proper netgame state flags
1889  switch(Netgame.game_state){
1890  case NETGAME_STATE_FORMING:
1891  flags |= AG_FLAG_FORMING;
1892  break;
1893 
1897  flags |= AG_FLAG_BRIEFING;
1898  break;
1899 
1901  flags |= AG_FLAG_IN_MISSION;
1902  break;
1903 
1904  case NETGAME_STATE_PAUSED:
1905  flags |= AG_FLAG_PAUSE;
1906  break;
1907 
1908  case NETGAME_STATE_ENDGAME:
1909  case NETGAME_STATE_DEBRIEF:
1910  flags |= AG_FLAG_DEBRIEF;
1911  break;
1912  }
1913 
1914  // if this is a standalone
1915  if(Game_mode & GM_STANDALONE_SERVER){
1916  flags |= AG_FLAG_STANDALONE;
1917  }
1918 
1919  // if we're in campaign mode
1921  flags |= AG_FLAG_CAMPAIGN;
1922  }
1923 
1924  // add the data about the connection speed of the host machine
1927 
1928  ADD_USHORT(flags);
1929 
1930  // send the data
1931  psnet_send(addr, data, packet_size);
1932 }
1933 
1934 // process information about an active game
1936 {
1937  int offset;
1938  ubyte val;
1939  active_game ag;
1940  int modes_compatible = 1;
1941 
1942  fill_net_addr(&ag.server_addr, hinfo->addr, hinfo->port);
1943 
1944  // read this game into a temporary structure
1945  offset = HEADER_LENGTH;
1946 
1947  // get the server version and compatible version
1948  GET_DATA(ag.version);
1949  GET_DATA(ag.comp_version);
1950 
1951  GET_STRING(ag.name);
1953  GET_STRING(ag.title);
1954  GET_DATA(val);
1955  ag.num_players = val;
1956  GET_USHORT(ag.flags);
1957 
1958  PACKET_SET_SIZE();
1959 
1960  if ( (ag.flags & AG_FLAG_TRACKER) && !Multi_options_g.pxo )
1961  modes_compatible = 0;
1962 
1963  if ( !(ag.flags & AG_FLAG_TRACKER) && Multi_options_g.pxo )
1964  modes_compatible = 0;
1965 
1966  // if this is a compatible version, and our modes are compatible, register it
1967  if ( (ag.version == MULTI_FS_SERVER_VERSION) && modes_compatible ) {
1969  }
1970 }
1971 
1972 //*********************************************************************************************************
1973 // Game Update Packet
1974 //*********************************************************************************************************
1975 /*
1976 struct fs2_game_update
1977 {
1978  char packet_signature;
1979  int len1;
1980  char netgame_name[len1];
1981  int len2;
1982  char netgame_mission_name[len2];
1983  int len3;
1984  char netgame_title[len3];
1985  int len4;
1986  char netgame_campaign_name[len4];
1987  int campaign_mode;
1988  int max_players;
1989  int security;
1990  unsigned int respawn;
1991  int flags;
1992  int type_flags;
1993  int version_info;
1994  ubyte debug_flags;
1995 
1996  // !!!!!! this isn't relying on information earlier in the packet!
1997  // receiving seems to always assume it's there!
1998  if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1999  int game_state;
2000  }
2001 
2002  }
2003 
2004 */
2005 
2006 // send_game_update_packet sends an updated Netgame structure to all players currently connected. The update
2007 // is used to change the current mission, current state, etc.
2009 {
2010  int packet_size;
2011  int idx;
2013 
2014  packet_size = 0;
2016 
2017  // with new mission description field, this becomes way to large
2018  // so we must add every element piece by piece except the
2031 
2032  // only the server should ever send the netgame state (standalone situation)
2035  }
2036 
2037  // if we're the host on a standalone, send to the standalone and let him rebroadcast
2039  if ( pl == NULL ) {
2040  multi_io_send_to_all_reliable(data, packet_size);
2041 
2042  for(idx=0; idx<MAX_PLAYERS; idx++){
2043  if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
2044  send_netgame_descript_packet(&Net_players[idx].p_info.addr, 1);
2045  }
2046  }
2047  } else {
2048  multi_io_send_reliable(pl, data, packet_size);
2050  }
2051  } else {
2052  Assert( pl == NULL ); // I don't think that a host in a standalone game would get here.
2053  multi_io_send_reliable(Net_player, data, packet_size);
2054  }
2055 
2056  // host should always send a netgame options update as well
2059  }
2060 }
2061 
2062 // process information about the netgame sent from the server/host
2064 {
2065  int offset;
2066  int ng_state;
2067 
2070 
2071  // read in the netgame information
2072  offset = HEADER_LENGTH;
2078  GET_INT(Netgame.max_players); // ignore on the standalone, who keeps track of this himself
2081 
2082  // be sure not to blast the quitting flag because of the "one frame extra" problem
2083  GET_INT(Netgame.flags);
2087 
2088  // netgame state
2089  GET_INT(ng_state);
2090 
2091  PACKET_SET_SIZE();
2092 
2093  // now compare the passed in game state to our current known state. If it has changed, then maybe
2094  // do something interesting.
2095  // move from the forming or debriefing state to the mission sync state
2096  if ( ng_state == NETGAME_STATE_MISSION_SYNC ){
2097  // if coming from the forming state
2100  // do any special processing for forced state transitions
2102 
2106  }
2107  // if coming from the debriefing state
2108  else if( (Netgame.game_state == NETGAME_STATE_DEBRIEF) ||
2110 
2111  // do any special processing for forced state transitions
2113 
2115 
2119  }
2120  }
2121  // move from mission sync to team select
2122  else if ( ng_state == NETGAME_STATE_BRIEFING ){
2125 
2126  // do any special processing for forced state transitions
2128 
2131  }
2132  }
2133  // move from the debriefing to the create game screen
2134  else if ( ng_state == NETGAME_STATE_FORMING ){
2137  // do any special processing for forced state transitions
2139 
2141 
2142  // move to the proper screen
2145  } else {
2147  }
2148  }
2149  }
2150 
2151  Netgame.game_state = ng_state;
2152 }
2153 
2154 //*********************************************************************************************************
2155 // Game Update Packet
2156 //*********************************************************************************************************
2157 /*
2158 
2159 */
2160 // send a request or a reply for mission description, if code == 0, request, if code == 1, reply
2162 {
2164  int desc_len;
2165  int packet_size = 0;
2166 
2167  // build the header
2169 
2170  val = (ubyte)code;
2171  ADD_DATA(val);
2172 
2173  if(code == 1){
2174  // add as much of the description as we dare
2175  desc_len = strlen(The_mission.mission_desc);
2176  if(desc_len > MAX_PACKET_SIZE - 10){
2177  desc_len = MAX_PACKET_SIZE - 10;
2178  ADD_INT(desc_len);
2179  memcpy(data+packet_size, The_mission.mission_desc, desc_len);
2180  packet_size += desc_len;
2181  } else {
2183  }
2184  }
2185 
2186  Assert(addr != NULL);
2187  if(addr != NULL){
2188  psnet_send(addr, data, packet_size);
2189  }
2190 }
2191 
2192 // process an incoming netgame description packet
2194 {
2195  int offset,state;
2196  ubyte code;
2197  char mission_desc[MISSION_DESC_LENGTH+2];
2198  net_addr addr;
2199 
2200  fill_net_addr(&addr, hinfo->addr, hinfo->port);
2201 
2202  // read this game into a temporary structure
2203  offset = HEADER_LENGTH;
2204  GET_DATA(code);
2205 
2206  // if this is a request for mission description
2207  if(code == 0){
2209  PACKET_SET_SIZE();
2210  return;
2211  }
2212 
2213  // send an update to this guy
2214  send_netgame_descript_packet(&addr, 1);
2215  } else {
2216  memset(mission_desc,0,MISSION_DESC_LENGTH+2);
2217  GET_STRING(mission_desc);
2218 
2219  // only display if we're in the proper state
2220  state = gameseq_get_state();
2221  switch(state){
2225  multi_common_set_text(mission_desc);
2226  break;
2227  }
2228  }
2229 
2230  PACKET_SET_SIZE();
2231 }
2232 
2233 // broadcast a query for active games. TCP will either request from the MT or from the specified list
2235 {
2236  int packet_size;
2237  net_addr addr;
2238  server_item *s_moveup;
2240 
2243  return;
2244  }
2245 
2247 
2248  // go through the server list and query each of those as well
2249  s_moveup = Game_server_head;
2250  if(s_moveup != NULL){
2251  do {
2252  send_server_query(&s_moveup->server_addr);
2253  s_moveup = s_moveup->next;
2254  } while(s_moveup != Game_server_head);
2255  }
2256 
2258 
2259  // send out a broadcast if our options allow us
2261  psnet_broadcast( &addr, data, packet_size);
2262  }
2263 }
2264 
2265 // send an individual query to an address to see if there is an active game
2267 {
2268  int packet_size;
2270 
2271  // build the header and send the data
2273  psnet_send(addr, data, packet_size);
2274 }
2275 
2276 // process a query from a client looking for active freespace games
2278 {
2279  int offset;
2280  net_addr addr;
2281 
2282  offset = HEADER_LENGTH;
2283 
2284  PACKET_SET_SIZE();
2285 
2286  // check to be sure that we don't capture our own broadcast message
2287  fill_net_addr(&addr, hinfo->addr, hinfo->port);
2288  if ( psnet_same( &addr, &Psnet_my_addr) ){
2289  return;
2290  }
2291 
2292  // if I am not a server of a game, don't send a reply!!!
2294  return;
2295  }
2296 
2297  // if the game options are being selected, then ignore the request
2298  // also, if Netgame.max_players == -1, the host has not chosen a mission yet and we should wait
2300  return;
2301  }
2302 
2303  // send information about this active game
2304  send_game_active_packet(&addr);
2305 }
2306 
2307 // sends information about netplayers in the game. if called on the server, broadcasts information about _all_ players
2309 {
2310  int packet_size,idx;
2312 
2314 
2315  // if I'm the server of the game, I should send an update for _all_players in the game
2317  for(idx=0;idx<MAX_PLAYERS;idx++){
2318  // only send info for connected players
2319  if(MULTI_CONNECTED(Net_players[idx])){
2320  // add a stop byte
2321  val = 0x0;
2322  ADD_DATA(val);
2323 
2324  // add the net player's information
2325  ADD_SHORT(Net_players[idx].player_id);
2326  ADD_INT(Net_players[idx].state);
2327  ADD_INT(Net_players[idx].p_info.ship_class);
2328  ADD_INT(Net_players[idx].tracker_player_id);
2329 
2331  val = 1;
2332  } else {
2333  val = 0;
2334  }
2335  ADD_DATA(val);
2336  }
2337  }
2338  // add the final stop byte
2339  val = 0xff;
2340  ADD_DATA(val);
2341 
2342  // broadcast the packet
2343  if(!(Game_mode & GM_IN_MISSION)){
2344  if ( pl == NULL ) {
2345  multi_io_send_to_all_reliable(data, packet_size);
2346  } else {
2347  multi_io_send_reliable(pl, data, packet_size);
2348  }
2349  } else {
2350  if ( pl == NULL ) {
2351  multi_io_send_to_all(data, packet_size);
2352  } else {
2353  multi_io_send(pl, data, packet_size);
2354  }
2355  }
2356  } else {
2357  // add a stop byte
2358  val = 0x0;
2359  ADD_DATA(val);
2360 
2361  // add my current state in the netgame to this packet
2366 
2367  // add if I have a CD or not
2368  if(Multi_has_cd){
2369  val = 1;
2370  } else {
2371  val = 0;
2372  }
2373  ADD_DATA(val);
2374 
2375  // add a final stop byte
2376  val = 0xff;
2377  ADD_DATA(val);
2378 
2379  // send the packet to the server
2380  Assert( pl == NULL ); // shouldn't ever be the case that pl is non-null here.
2381  if(!(Game_mode & GM_IN_MISSION)){
2382  multi_io_send_reliable(Net_player, data, packet_size);
2383  } else {
2384  multi_io_send(Net_player, data, packet_size);
2385  }
2386  }
2387 }
2388 
2389 // process an incoming netplayer state update. if we're the server, we should rebroadcast
2391 {
2392  int offset, player_num;
2393  net_player bogus;
2394  ubyte stop, has_cd;
2395  short player_id;
2396  int new_state;
2397 
2398  offset = HEADER_LENGTH;
2399 
2400  // get the first stop byte
2401  GET_DATA(stop);
2402  player_num = -1;
2403  while(stop != 0xff){
2404  // look the player up
2405  GET_SHORT(player_id);
2406  player_num = find_player_id(player_id);
2407  // if we couldn't find him, read in the bogus data
2408  if((player_num == -1) || (Net_player == &Net_players[player_num])){
2409  GET_INT(bogus.state);
2410  GET_INT(bogus.p_info.ship_class);
2411  GET_INT(bogus.tracker_player_id);
2412 
2413  GET_DATA(has_cd);
2414  }
2415  // otherwise read in the data correctly
2416  else {
2417  GET_INT(new_state);
2418  GET_INT(Net_players[player_num].p_info.ship_class);
2419  GET_INT(Net_players[player_num].tracker_player_id);
2420  GET_DATA(has_cd);
2421  if(has_cd){
2422  Net_players[player_num].flags |= NETINFO_FLAG_HAS_CD;
2423  } else {
2424  Net_players[player_num].flags &= ~(NETINFO_FLAG_HAS_CD);
2425  }
2426 
2427  // if he's changing state to joined, send a team update
2428  if((Net_players[player_num].state == NETPLAYER_STATE_JOINING) && (new_state == NETPLAYER_STATE_JOINED) && (Netgame.type_flags & NG_TYPE_TEAM)){
2430  }
2431 
2432  // set state
2433  Net_players[player_num].state = new_state;
2434  }
2435 
2436  // get the next stop byte
2437  GET_DATA(stop);
2438  }
2439 
2440  PACKET_SET_SIZE();
2441 
2442  // if I'm the host or the server of the game, update everyone else so things are synched up as tightly as possible
2445  }
2446 
2447  // if i'm the standalone and this is an update from the host, maybe change some netgame settings
2448  if((Game_mode & GM_STANDALONE_SERVER) && (player_num != -1) && (Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST)){
2449  switch(Net_players[player_num].state){
2452  break;
2453 
2455  // check for race conditions
2458  }
2459  break;
2460  }
2461  }
2462 }
2463 
2464 #define EXTRA_DEATH_VAPORIZED (1<<0)
2465 #define EXTRA_DEATH_WASHED (1<<1)
2466 // send a packet indicating a ship has been killed
2467 void send_ship_kill_packet( object *objp, object *other_objp, float percent_killed, int self_destruct )
2468 {
2469  int packet_size, model;
2470  ubyte data[MAX_PACKET_SIZE], was_player, extra_death_info, vaporized;
2471  ushort debris_signature;
2472  ubyte sd;
2473  polymodel * pm;
2474 
2475  // only sendable from the master
2477 
2478  // special deaths
2479  vaporized = ( (Ships[objp->instance].flags & SF_VAPORIZE) > 0 );
2480 
2481  extra_death_info = 0;
2482  if ( vaporized ) {
2483  extra_death_info |= EXTRA_DEATH_VAPORIZED;
2484  }
2485 
2486  if ( Ships[objp->instance].wash_killed ) {
2487  extra_death_info |= EXTRA_DEATH_WASHED;
2488  }
2489 
2490  // find out the next network signature that will be used for the debris pieces.
2491  model = Ship_info[Ships[objp->instance].ship_info_index].model_num;
2492  pm = model_get(model);
2493  debris_signature = 0;
2494  if ( pm && !vaporized ) {
2495  debris_signature = multi_get_next_network_signature( MULTI_SIG_DEBRIS );
2497  Ships[objp->instance].debris_net_sig = debris_signature;
2498  }
2499 
2501  ADD_USHORT(objp->net_signature);
2502 
2503  // ships which are initially killed get the rest of the data sent. self destructed ships and
2504  if ( other_objp == NULL ) {
2505  ushort temp;
2506 
2507  temp = 0;
2508  ADD_USHORT(temp);
2509  nprintf(("Network","Don't know other_obj for ship kill packet, sending NULL\n"));
2510  } else {
2511  ADD_USHORT( other_objp->net_signature );
2512  }
2513 
2514  ADD_USHORT( debris_signature );
2515  ADD_FLOAT( percent_killed );
2516  sd = (ubyte)self_destruct;
2517  ADD_DATA(sd);
2518  ADD_DATA( extra_death_info );
2519 
2520  // if the ship who died is a player, then send some extra info, like who killed him, etc.
2521  was_player = 0;
2522  if ( objp->flags & OF_PLAYER_SHIP ) {
2523  int pnum;
2524  char temp;
2525  short temp2;
2526 
2527  pnum = multi_find_player_by_object( objp );
2528  if ( pnum != -1 ) {
2529  was_player = 1;
2530  ADD_DATA( was_player );
2531 
2532  Assert(Net_players[pnum].m_player->killer_objtype < CHAR_MAX);
2533  temp = (char)Net_players[pnum].m_player->killer_objtype;
2534  ADD_DATA( temp );
2535 
2536  Assert(Net_players[pnum].m_player->killer_species < CHAR_MAX);
2537  temp = (char)Net_players[pnum].m_player->killer_species;
2538  ADD_DATA( temp );
2539 
2540  Assert(Net_players[pnum].m_player->killer_weapon_index < SHRT_MAX);
2541  temp2 = (short)Net_players[pnum].m_player->killer_weapon_index;
2542  ADD_SHORT( temp2 );
2543 
2544  ADD_STRING( Net_players[pnum].m_player->killer_parent_name );
2545  } else {
2546  ADD_DATA( was_player );
2547  }
2548  } else {
2549  ADD_DATA( was_player );
2550  }
2551 
2552  // send the packet reliably!!!
2553  multi_io_send_to_all_reliable(data, packet_size);
2554 }
2555 
2556 // process a packet indicating that a ship has been killed
2558 {
2559  int offset;
2560  ushort ship_sig, other_sig, debris_sig;
2561  object *sobjp, *oobjp;
2562  float percent_killed;
2563  ubyte was_player, extra_death_info, sd;
2564  char killer_name[NAME_LENGTH], killer_objtype = OBJ_NONE, killer_species = 0;
2565  short killer_weapon_index = -1;
2566 
2567  offset = HEADER_LENGTH;
2568  GET_USHORT(ship_sig);
2569 
2570  GET_USHORT( other_sig );
2571  GET_USHORT( debris_sig );
2572  GET_FLOAT( percent_killed );
2573  GET_DATA( sd );
2574  GET_DATA( extra_death_info );
2575  GET_DATA( was_player );
2576 
2577 
2578  // pnum is >=0 when the dying ship is a pleyer ship. Get the info about how he died
2579  if ( was_player != 0 ) {
2580  GET_DATA( killer_objtype );
2581  GET_DATA( killer_species );
2582  GET_SHORT( killer_weapon_index );
2583  GET_STRING( killer_name );
2584  }
2585 
2586  PACKET_SET_SIZE();
2587 
2588  sobjp = multi_get_network_object( ship_sig );
2589 
2590  // if I am unable to find the ship object which was killed, I have to bail and rely on getting
2591  // another message from the server that this happened!
2592  if ( sobjp == NULL ) {
2593  nprintf(("Network", "Couldn't find net signature %d for kill packet\n", ship_sig));
2594  return;
2595  }
2596 
2597  // set this ship's hull value to 0
2598  sobjp->hull_strength = 0.0f;
2599 
2600  // maybe set vaporized
2601  if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2602  Ships[sobjp->instance].flags |= SF_VAPORIZE;
2603  }
2604 
2605  // maybe set wash_killed
2606  if (extra_death_info & EXTRA_DEATH_VAPORIZED) {
2607  Ships[sobjp->instance].wash_killed = 1;
2608  }
2609 
2610  oobjp = multi_get_network_object( other_sig );
2611 
2612  if ( was_player != 0 ) {
2613  int pnum;
2614 
2615  pnum = multi_find_player_by_object( sobjp );
2616  if ( pnum != -1 ) {
2617  Net_players[pnum].m_player->killer_objtype = killer_objtype;
2618  Net_players[pnum].m_player->killer_species = killer_species;
2619  Net_players[pnum].m_player->killer_weapon_index = killer_weapon_index;
2620  strcpy_s( Net_players[pnum].m_player->killer_parent_name, killer_name );
2621  }
2622  }
2623 
2624  // check to see if I need to respawn myself
2625  multi_respawn_check(sobjp);
2626 
2627  // store the debris signature in the arrival distance which will never get used for player ships
2628  Ships[sobjp->instance].debris_net_sig = debris_sig;
2629 
2630  // set this bit so that we don't accidentally start switching targets when we die
2631  if(sobjp == Player_obj){
2633  }
2634 
2635  mprintf(("Network Killing off %s\n", Ships[sobjp->instance].ship_name));
2636 
2637  // do the normal thing when not ingame joining. When ingame joining, simply kill off the ship.
2639  ship_hit_kill( sobjp, oobjp, percent_killed, sd );
2640  } else {
2641  sobjp->flags |= OF_SHOULD_BE_DEAD;
2643  obj_delete( OBJ_INDEX(sobjp) );
2644  }
2645 }
2646 
2647 // send a packet indicating a ship should be created
2648 void send_ship_create_packet( object *objp, int is_support )
2649 {
2650  int packet_size;
2652 
2653  // We will pass the ship to create by name.
2655  ADD_USHORT(objp->net_signature);
2656  ADD_INT( is_support );
2657  if ( is_support ){
2658  ADD_VECTOR( objp->pos );
2659  }
2660 
2661  // broadcast the packet
2662  multi_io_send_to_all_reliable(data, packet_size);
2663 }
2664 
2665 // process a packet indicating a ship should be created
2667 {
2668  int offset, objnum, is_support;
2669  ushort signature;
2670  p_object *objp;
2671  vec3d pos = ZERO_VECTOR;
2672 
2674  offset = HEADER_LENGTH;
2675  GET_USHORT(signature);
2676  GET_INT( is_support );
2677  if ( is_support ){
2678  GET_VECTOR( pos );
2679  }
2680 
2681  PACKET_SET_SIZE();
2682 
2683  // find the name of this ship on ship ship arrival list. if found, pass it to parse_object_create
2684  if ( !is_support ) {
2685  objp = mission_parse_get_arrival_ship( signature );
2686  if ( objp != NULL ) {
2687  objnum = parse_create_object(objp);
2688  } else {
2689  nprintf(("Network", "Ship with sig %d not found on ship arrival list -- not creating!!\n", signature));
2690  }
2691  } else {
2693  if(Arriving_support_ship == NULL){
2694  return;
2695  }
2697  Arriving_support_ship->net_signature = signature;
2699  Assert( objnum != -1 );
2700  if(objnum >= 0){
2702  }
2703  }
2704 }
2705 
2706 // send a packet indicating a wing of ships should be created
2707 void send_wing_create_packet( wing *wingp, int num_to_create, int pre_create_count )
2708 {
2709  int packet_size, index, ship_instance;
2711  ushort signature;
2712  int val;
2713 
2714  // for creating wing -- we just send the index into the wing array of this wing.
2715  // all players load the same mission, and so their array's should all match. We also
2716  // need to send the signature of the first ship that was created. We can find this by
2717  // looking num_to_create places back in the ship_index field in the wing structure.
2718 
2719  index = WING_INDEX(wingp);
2720  ship_instance = wingp->ship_index[wingp->current_count - num_to_create];
2721  signature = Objects[Ships[ship_instance].objnum].net_signature;
2722 
2724  ADD_INT(index);
2725  ADD_INT(num_to_create);
2726  ADD_USHORT(signature);
2727  ADD_INT(pre_create_count);
2728  val = wingp->current_wave - 1;
2729  ADD_INT(val);
2730 
2731  multi_io_send_to_all_reliable(data, packet_size);
2732 }
2733 
2734 // process a packet saying that a wing should be created
2736 {
2737  int offset, index, num_to_create;
2738  ushort signature;
2739  int total_arrived_count, current_wave;
2740 
2741  offset = HEADER_LENGTH;
2742  GET_INT(index);
2743  GET_INT(num_to_create);
2744  GET_USHORT(signature);
2745  GET_INT(total_arrived_count);
2746  GET_INT(current_wave);
2747 
2748  PACKET_SET_SIZE();
2749 
2750  // do a sanity check on the wing to be sure that we are actually working on a valid wing
2751  if ( (index < 0) || (index >= Num_wings) || (Wings[index].num_waves == -1) ) {
2752  nprintf(("Network", "Invalid index %d for wing create packet\n", index));
2753  return;
2754  }
2755  if ( (num_to_create <= 0) || (num_to_create > Wings[index].wave_count) ) {
2756  nprintf(("Network", "Invalid number of ships to create (%d) for wing %s\n", num_to_create, Wings[index].name));
2757  return;
2758  }
2759 
2760  // bash some info
2761  Wings[index].current_count = 0;
2762  Wings[index].total_arrived_count = total_arrived_count;
2763  Wings[index].current_wave = current_wave;
2764 
2765  // set the network signature that was passed. The client should create ships in the same order
2766  // as the server -- so all ships should get the same sigs as assigned by the server. We also
2767  // need to set some timestamps and cues correctly to be sure that these things get created on
2768  // the clients correctly
2770  parse_wing_create_ships( &Wings[index], num_to_create, 1 );
2771 }
2772 
2773 // packet indicating a ship is departing
2774 void send_ship_depart_packet( object *objp, int method )
2775 {
2777  int packet_size;
2778  ushort signature;
2779 
2780  signature = objp->net_signature;
2781 
2783  ADD_USHORT( signature );
2784  ADD_INT( method );
2785 
2786  multi_io_send_to_all_reliable(data, packet_size);
2787 }
2788 
2789 // process a packet indicating a ship is departing
2791 {
2792  int offset;
2793  object *objp;
2794  ushort signature;
2795  int s_method;
2796 
2797  offset = HEADER_LENGTH;
2798  GET_USHORT( signature );
2799  GET_INT(s_method);
2800  PACKET_SET_SIZE();
2801 
2802  // find the object which is departing
2803  objp = multi_get_network_object( signature );
2804  if ( objp == NULL ) {
2805  nprintf(("network", "Couldn't find object with net signature %d to depart\n", signature ));
2806  return;
2807  }
2808 
2809  switch (s_method) {
2810  case SHIP_DEPARTED_BAY:
2811  case SHIP_VANISHED:
2812  if (objp->type == OBJ_SHIP) {
2813  ship_actually_depart(objp->instance, s_method);
2814  }
2815  else {
2816  nprintf(("network", "Can not process ship depart packed. Object with net signature %d is not a ship!\n", signature ));
2817  return;
2818  }
2819  break;
2820 
2821  // assume standard warp out
2822  default:
2823  // start warping him out
2824  shipfx_warpout_start( objp );
2825  }
2826 }
2827 
2828 // packet to tell clients cargo of a ship was revealed to all
2830 {
2832  int packet_size;
2833 
2834  // build the header and add the data
2837 
2838  // server sends to all players
2839  if(MULTIPLAYER_MASTER){
2840  multi_io_send_to_all_reliable(data, packet_size);
2841  }
2842  // clients just send to the server
2843  else {
2844  multi_io_send_reliable(Net_player, data, packet_size);
2845  }
2846 }
2847 
2848 // process a cargo revealed packet
2850 {
2851  int offset;
2852  ushort signature;
2853  object *objp;
2854 
2855  offset = HEADER_LENGTH;
2856  GET_USHORT(signature);
2857  PACKET_SET_SIZE();
2858 
2859  // get a ship pointer and call the ship function to reveal the cargo
2860  objp = multi_get_network_object( signature );
2861  if ( objp == NULL ) {
2862  nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
2863  return;
2864  }
2865 
2866  // Assert( objp->type == OBJ_SHIP );
2867  if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2868  return;
2869  }
2870 
2871  // this will take care of re-routing to all other clients
2872  ship_do_cargo_revealed( &Ships[objp->instance], 1);
2873 
2874  // server should rebroadcast
2875  if(MULTIPLAYER_MASTER){
2877  }
2878 }
2879 
2880 // packet to tell clients cargo of a ship was hidden to all
2882 {
2884  int packet_size;
2885 
2886  // build the header and add the data
2889 
2890  // server sends to all players
2891  if(MULTIPLAYER_MASTER){
2892  multi_io_send_to_all_reliable(data, packet_size);
2893  }
2894  // clients just send to the server
2895  else {
2896  multi_io_send_reliable(Net_player, data, packet_size);
2897  }
2898 }
2899 
2900 // process a cargo hidden packet
2902 {
2903  int offset;
2904  ushort signature;
2905  object *objp;
2906 
2907  offset = HEADER_LENGTH;
2908  GET_USHORT(signature);
2909  PACKET_SET_SIZE();
2910 
2911  // get a ship pointer and call the ship function to hide the cargo
2912  objp = multi_get_network_object( signature );
2913  if ( objp == NULL ) {
2914  nprintf(("Network", "Could not find object with net signature %d for cargo hidden\n", signature ));
2915  return;
2916  }
2917 
2918  // Assert( objp->type == OBJ_SHIP );
2919  if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
2920  return;
2921  }
2922 
2923  // this will take care of re-routing to all other clients
2924  ship_do_cargo_hidden( &Ships[objp->instance], 1);
2925 
2926  // server should rebroadcast
2927  if(MULTIPLAYER_MASTER){
2929  }
2930 }
2931 
2932 // defines used for secondary fire packet
2933 #define SFPF_ALLOW_SWARM (1<<7)
2934 #define SFPF_DUAL_FIRE (1<<6)
2935 #define SFPF_TARGET_LOCKED (1<<5)
2936 
2937 // send a packet indicating a secondary weapon was fired
2938 void send_secondary_fired_packet( ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm )
2939 {
2940  int packet_size, net_player_num;
2941  ubyte data[MAX_PACKET_SIZE], sinfo, current_bank;
2942  object *objp;
2943  ushort target_signature;
2944  char t_subsys;
2945  ai_info *aip;
2946 
2947  // Assert ( starting_count < UCHAR_MAX );
2948 
2949  // get the object for this ship. If it is an AI object, send all the info to all player. Otherwise,
2950  // we might send the info to the other player different than the one who fired
2951  objp = &Objects[shipp->objnum];
2952  if ( !(objp->flags & OF_PLAYER_SHIP) ) {
2953  if ( num_fired == 0 ) {
2954  return;
2955  }
2956  }
2957 
2958  aip = &Ai_info[shipp->ai_index];
2959 
2960  current_bank = (ubyte)shipp->weapons.current_secondary_bank;
2961  Assert( (current_bank < MAX_SHIP_SECONDARY_BANKS) );
2962 
2963  // build up the header portion
2965 
2967  ADD_USHORT( starting_sig );
2968 
2969  // add a couple of bits for swarm missiles and dual fire secondary weapons
2970  sinfo = current_bank;
2971 
2972  if ( allow_swarm ){
2973  sinfo |= SFPF_ALLOW_SWARM;
2974  }
2975 
2976  if ( shipp->flags & SF_SECONDARY_DUAL_FIRE ){
2977  sinfo |= SFPF_DUAL_FIRE;
2978  }
2979 
2980  if ( aip->current_target_is_locked ){
2981  sinfo |= SFPF_TARGET_LOCKED;
2982  }
2983 
2984  ADD_DATA( sinfo );
2985 
2986  // add the ship's target and any targeted subsystem
2987  target_signature = 0;
2988  t_subsys = -1;
2989  if ( aip->target_objnum != -1) {
2990  target_signature = Objects[aip->target_objnum].net_signature;
2991  if ( (Objects[aip->target_objnum].type == OBJ_SHIP) && (aip->targeted_subsys != NULL) ) {
2992  int s_index;
2993 
2995  Assert( s_index < CHAR_MAX ); // better be less than this!!!!
2996  t_subsys = (char)s_index;
2997  }
2998 
2999  if ( Objects[aip->target_objnum].type == OBJ_WEAPON ) {
3001  }
3002 
3003  }
3004 
3005  ADD_USHORT( target_signature );
3006  ADD_DATA( t_subsys );
3007 
3008  // just send this packet to everyone, then bail if an AI ship fired.
3009  if ( !(objp->flags & OF_PLAYER_SHIP) ) {
3010  multi_io_send_to_all(data, packet_size);
3011  return;
3012  }
3013 
3014  net_player_num = multi_find_player_by_object( objp );
3015 
3016  if ( net_player_num < 0 ) {
3017  // Pass to higher level code to handle
3018  return;
3019  }
3020 
3021  // getting here means a player fired. Send the current packet to all players except the player
3022  // who fired. If nothing got fired, then don't send to the other players -- we will just send
3023  // a packet to the player who will find out that he didn't fire anything
3024  if ( num_fired > 0 ) {
3025  multi_io_send_to_all_reliable(data, packet_size, &Net_players[net_player_num]);
3026  }
3027 
3028  // if I (the master) fired, then return
3029  if ( Net_players[net_player_num].flags & NETINFO_FLAG_AM_MASTER ){
3030  return;
3031  }
3032 
3033  // now build up the packet to send to the player who actually fired.
3035  ADD_USHORT(starting_sig);
3036  ADD_DATA( sinfo );
3037 
3038  // add the targeting information so that the player's weapons will always home on the correct
3039  // ship
3040  ADD_USHORT( target_signature );
3041  ADD_DATA( t_subsys );
3042 
3043  multi_io_send_reliable(&Net_players[net_player_num], data, packet_size);
3044 }
3045 
3047 void process_secondary_fired_packet(ubyte* data, header* hinfo, int from_player)
3048 {
3049  int offset, allow_swarm, target_objnum_save;
3050  ushort net_signature, starting_sig, target_signature;
3051  ubyte sinfo, current_bank;
3052  object* objp, *target_objp;
3053  ship *shipp;
3054  char t_subsys;
3055  ai_info *aip;
3056  ship_subsys *targeted_subsys_save;
3057 
3058  offset = HEADER_LENGTH; // size of the header
3059 
3060  // if from_player is false, it means that the secondary weapon info in this packet was
3061  // fired by an ai object (or another player). from_player == 1 means tha me (the person
3062  // receiving this packet) fired the secondary weapon
3063  if ( !from_player ) {
3064  GET_USHORT( net_signature );
3065  GET_USHORT( starting_sig );
3066  GET_DATA( sinfo ); // are we firing swarm missiles
3067 
3068  GET_USHORT( target_signature );
3069  GET_DATA( t_subsys );
3070 
3071  PACKET_SET_SIZE();
3072 
3073  // find the object (based on network signatures) for the object that fired
3074  objp = multi_get_network_object( net_signature );
3075  if ( objp == NULL ) {
3076  nprintf(("Network", "Could not find ship for fire secondary packet!"));
3077  return;
3078  }
3079 
3080  // set up the ships current secondary bank and that bank's mode. Below, we will set the timeout
3081  // of the next fire time of this bank to 0 so we can fire right away
3082  shipp = &Ships[objp->instance];
3083 
3084  } else {
3085  GET_USHORT( starting_sig );
3086  GET_DATA( sinfo );
3087 
3088  GET_USHORT( target_signature );
3089  GET_DATA( t_subsys );
3090 
3091  PACKET_SET_SIZE();
3092 
3093  // get the object and ship
3094  objp = Player_obj;
3095  shipp = Player_ship;
3096  }
3097 
3098  // check the allow swarm bit
3099  allow_swarm = 0;
3100  if ( sinfo & SFPF_ALLOW_SWARM ){
3101  allow_swarm = 1;
3102  }
3103 
3104  // set the dual fire properties of the ship
3105  if ( sinfo & SFPF_DUAL_FIRE ){
3106  shipp->flags |= SF_SECONDARY_DUAL_FIRE;
3107  } else {
3108  shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
3109  }
3110 
3111  // determine whether current target is locked
3112  Assert( shipp->ai_index != -1 );
3113  aip = &Ai_info[shipp->ai_index];
3114  if ( sinfo & SFPF_TARGET_LOCKED ) {
3115  aip->current_target_is_locked = 1;
3116  } else {
3117  aip->current_target_is_locked = 0;
3118  }
3119 
3120  // find out the current bank
3121  current_bank = (ubyte)(sinfo & 0x3);
3122  Assert( (current_bank < MAX_SHIP_SECONDARY_BANKS) );
3123  shipp->weapons.current_secondary_bank = current_bank;
3124 
3125  // make it so we can fire this ship's secondary bank immediately!!!
3127  shipp->weapons.detonate_weapon_time = timestamp(5000); // be sure that we don't detonate a remote weapon before it is time.
3128 
3129  // set this ship's target and subsystem information. We will save and restore target and
3130  // targeted subsystem so that we do not accidentally change targets for this player or
3131  // any AI ships on his system.
3132  target_objnum_save = aip->target_objnum;
3133  targeted_subsys_save = aip->targeted_subsys;
3134 
3135  // reset these variables for accuracy. They will get reassigned at the end of this fuction
3136  aip->target_objnum = -1;
3137  aip->targeted_subsys = NULL;
3138 
3139  target_objp = multi_get_network_object( target_signature );
3140  if ( target_objp != NULL ) {
3141  aip->target_objnum = OBJ_INDEX(target_objp);
3142 
3143  if ( (t_subsys != -1) && (target_objp->type == OBJ_SHIP) ) {
3144  aip->targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
3145  }
3146  }
3147 
3148  if ( starting_sig != 0 ){
3150  } else {
3151  shipp->weapons.detonate_weapon_time = timestamp(0); // signature of -1 say detonate remote weapon
3152  }
3153 
3154  ship_fire_secondary( objp, allow_swarm );
3155 
3156  // restore targeted object and targeted subsystem
3157  aip->target_objnum = target_objnum_save;
3158  aip->targeted_subsys = targeted_subsys_save;
3159 }
3160 
3161 // send a packet indicating a countermeasure was fired
3162 void send_countermeasure_fired_packet( object *objp, int cmeasure_count, int rand_val )
3163 {
3165  int packet_size;
3166 
3167  Int3();
3168 
3169  Assert ( cmeasure_count < UCHAR_MAX );
3171  ADD_USHORT( objp->net_signature );
3172  ADD_INT( rand_val );
3173 
3174  multi_io_send_to_all(data, packet_size);
3175 }
3176 
3177 // process a packet indicating a countermeasure was fired
3179 {
3180  int offset, rand_val;
3181  ushort signature;
3182  object *objp;
3183 
3184  Int3();
3185 
3186  offset = HEADER_LENGTH;
3187 
3188  GET_USHORT( signature );
3189  GET_INT( rand_val );
3190  PACKET_SET_SIZE();
3191 
3192  objp = multi_get_network_object( signature );
3193  if ( objp == NULL ) {
3194  nprintf(("network", "Could find object whose countermeasures are being launched!!!\n"));
3195  return;
3196  }
3197  if(objp->type != OBJ_SHIP){
3198  return;
3199  }
3200  // Assert ( objp->type == OBJ_SHIP );
3201 
3202  // make it so ship can fire right away!
3204  if ( objp == Player_obj ){
3205  nprintf(("network", "firing countermeasure from my ship\n"));
3206  }
3207 
3208  ship_launch_countermeasure( objp, rand_val );
3209 }
3210 
3211 // send a packet indicating that a turret has been fired
3212 void send_turret_fired_packet( int ship_objnum, int subsys_index, int weapon_objnum )
3213 {
3214  int packet_size;
3215  ushort pnet_signature;
3216  ubyte data[MAX_PACKET_SIZE], cindex;
3217  object *objp;
3218  ubyte has_sig = 0;
3219  ship_subsys *ssp;
3220  short val;
3221 
3222  // sanity
3223  if((weapon_objnum < 0) || (Objects[weapon_objnum].type != OBJ_WEAPON) || (Objects[weapon_objnum].instance < 0) || (Weapons[Objects[weapon_objnum].instance].weapon_info_index < 0)){
3224  return;
3225  }
3226 
3227  // local setup -- be sure we are actually passing a weapon!!!!
3228  objp = &Objects[weapon_objnum];
3229  Assert ( objp->type == OBJ_WEAPON );
3231  has_sig = 1;
3232  }
3233 
3234  pnet_signature = Objects[ship_objnum].net_signature;
3235 
3236  Assert( subsys_index < UCHAR_MAX );
3237  cindex = (ubyte)subsys_index;
3238 
3239  ssp = ship_get_indexed_subsys( &Ships[Objects[ship_objnum].instance], subsys_index, NULL );
3240  if(ssp == NULL){
3241  return;
3242  }
3243 
3244  // build the fire turret packet.
3246  packet_size += multi_pack_unpack_position(1, data + packet_size, &objp->orient.vec.fvec);
3247  ADD_DATA( has_sig );
3248  ADD_USHORT( pnet_signature );
3249  if(has_sig){
3250  ADD_USHORT( objp->net_signature );
3251  }
3252  ADD_DATA( cindex );
3253  val = (short)ssp->submodel_info_1.angs.h;
3254  ADD_SHORT( val );
3255  val = (short)ssp->submodel_info_2.angs.p;
3256  ADD_SHORT( val );
3257 
3258  multi_io_send_to_all(data, packet_size);
3259 
3260  multi_rate_add(1, "tur", packet_size);
3261 }
3262 
3263 // process a packet indicating a turret has been fired
3265 {
3266  int offset, weapon_objnum, wid = -1;
3267  ushort pnet_signature, wnet_signature;
3268  vec3d pos, temp;
3269  matrix orient;
3270  vec3d o_fvec;
3271  ubyte turret_index;
3272  object *objp;
3273  ship_subsys *ssp;
3274  ubyte has_sig = 0;
3275  ship *shipp;
3276  short pitch, heading;
3277 
3278  // get the data for the turret fired packet
3279  offset = HEADER_LENGTH;
3280  offset += multi_pack_unpack_position(0, data + offset, &o_fvec);
3281  GET_DATA( has_sig );
3282  GET_USHORT( pnet_signature );
3283  if(has_sig){
3284  GET_USHORT( wnet_signature );
3285  } else {
3286  wnet_signature = 0;
3287  }
3288  GET_DATA( turret_index );
3289  GET_SHORT( heading );
3290  GET_SHORT( pitch );
3291  PACKET_SET_SIZE(); // move our counter forward the number of bytes we have read
3292 
3293  // find the object
3294  objp = multi_get_network_object( pnet_signature );
3295  if ( objp == NULL ) {
3296  nprintf(("network", "could find parent object with net signature %d for turret firing\n", pnet_signature));
3297  return;
3298  }
3299 
3300  // if this isn't a ship, do nothing
3301  if ( objp->type != OBJ_SHIP ){
3302  return;
3303  }
3304 
3305  // make an orientation matrix from the o_fvec
3306  vm_vector_2_matrix(&orient, &o_fvec, NULL, NULL);
3307 
3308  // find this turret, and set the position of the turret that just fired to be where it fired. Quite a
3309  // hack, but should be suitable.
3310  shipp = &Ships[objp->instance];
3311  ssp = ship_get_indexed_subsys( shipp, turret_index, NULL );
3312  if(ssp == NULL){
3313  return;
3314  }
3315 
3316  if (ssp->weapons.num_primary_banks > 0) {
3317  wid = ssp->weapons.primary_bank_weapons[0];
3318  } else if (ssp->weapons.num_secondary_banks > 0) {
3319  wid = ssp->weapons.secondary_bank_weapons[0];
3320  }
3321 
3322  if (wid < 0)
3323  return;
3324 
3325  // bash the position and orientation of the turret
3326  ssp->submodel_info_1.angs.h = (float)heading;
3327  ssp->submodel_info_2.angs.p = (float)pitch;
3328 
3329  // get the world position of the weapon
3330  ship_get_global_turret_info(objp, ssp->system_info, &pos, &temp);
3331 
3332  // create the weapon object
3333  if(wnet_signature != 0){
3335  }
3336 
3337  weapon_objnum = weapon_create( &pos, &orient, wid, OBJ_INDEX(objp), -1, 1, 0, 0.0f, ssp);
3338 
3339  if (weapon_objnum != -1) {
3340  wid = Weapons[Objects[weapon_objnum].instance].weapon_info_index;
3341  if ( Weapon_info[wid].launch_snd != -1 ) {
3342  snd_play_3d( &Snds[Weapon_info[wid].launch_snd], &pos, &View_position );
3343  }
3344  }
3345 }
3346 
3347 // send a mission log item packet
3349 {
3350  int packet_size;
3352  ubyte type;
3353  int sindex;
3354  log_entry *entry;
3355 
3357 
3358  // get the data from the log
3359  entry = &log_entries[num];
3360  type = (ubyte)entry->type; // do the type casting thing to save on packet space
3361  sindex = entry->index;
3362 
3364  ADD_DATA(type);
3365  ADD_INT(entry->flags);
3366  ADD_INT(sindex);
3367  ADD_INT(entry->timestamp); // NOTE: this is a long so careful with swapping in 64-bit platforms - taylor
3368  ADD_STRING(entry->pname);
3369  ADD_STRING(entry->sname);
3370 
3371  // broadcast the packet to all players
3372  multi_io_send_to_all_reliable(data, packet_size);
3373 }
3374 
3375 // process a mission log item packet
3377 {
3378  int offset, flags;
3379  int sindex;
3380  ubyte type;
3381  char pname[NAME_LENGTH], sname[NAME_LENGTH];
3382  fix timestamp;
3383 
3385 
3386  offset = HEADER_LENGTH;
3387  GET_DATA(type);
3388  GET_INT(flags);
3389  GET_INT(sindex);
3390  GET_INT(timestamp); // NOTE: this is a long so careful with swapping in 64-bit platforms - taylor
3391  GET_STRING(pname);
3392  GET_STRING(sname);
3393 
3394  PACKET_SET_SIZE();
3395 
3396  mission_log_add_entry_multi( type, pname, sname, sindex, timestamp, flags );
3397 }
3398 
3399 // send a mission message packet
3400 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, int delay)
3401 {
3402  int packet_size;
3403  ubyte data[MAX_PACKET_SIZE], up, us, utime;
3404 
3406  Assert ( (priority >= 0) && (priority < UCHAR_MAX) );
3407  Assert ( (timing >= 0) && (timing < UCHAR_MAX) );
3408 
3409  up = (ubyte) priority;
3410  us = (ubyte) source;
3411  utime = (ubyte)timing;
3412 
3414  ADD_INT(id);
3415  ADD_STRING(who_from);
3416  ADD_DATA(up);
3417  ADD_DATA(utime);
3418  ADD_DATA(us);
3419  ADD_INT(builtin_type);
3420  ADD_INT(multi_team_filter);
3421  ADD_INT(delay);
3422 
3423  if (multi_target == -1){
3424  multi_io_send_to_all_reliable(data, packet_size);
3425  } else {
3426  multi_io_send_reliable(&Net_players[multi_target], data, packet_size);
3427  }
3428 }
3429 
3430 // process a mission message packet
3432 {
3433  int offset, id, builtin_type, delay;
3434  ubyte priority, source, utiming;
3435  char who_from[NAME_LENGTH];
3436  int multi_team_filter;
3437 
3439 
3440  offset = HEADER_LENGTH;
3441  GET_INT(id);
3442  GET_STRING(who_from);
3443  GET_DATA(priority);
3444  GET_DATA(utiming);
3445  GET_DATA(source);
3446  GET_INT(builtin_type);
3447  GET_INT(multi_team_filter);
3448  GET_INT(delay);
3449 
3450  PACKET_SET_SIZE();
3451 
3452  // filter out some builtin ones in TvT
3453  if((builtin_type >= 0) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL) && (Net_player->p_info.team != multi_team_filter)) {
3454  mprintf(("Builtin message of type %d filtered out in process_mission_message_packet()\n", id));
3455  return;
3456  }
3457 
3458  // maybe filter this out
3459  if(!message_filter_multi(id)){
3460  // send the message as if it came from an sexpression
3461  message_queue_message( id, priority, utiming, who_from, source, 0, delay, builtin_type );
3462  }
3463 }
3464 
3465 // just send them a pong back as fast as possible
3467 {
3468  net_addr addr;
3469  int offset;
3470 
3471  offset = HEADER_LENGTH;
3472  PACKET_SET_SIZE();
3473 
3474  // get the address to return the pong to
3475  fill_net_addr(&addr, hinfo->addr, hinfo->port);
3476 
3477  // send the pong
3478  send_pong(&addr);
3479 }
3480 
3481 // right now it just routes the pong through to the standalone gui, which is the only
3482 // system which uses ping and pong right now.
3484 {
3485  net_player *p;
3486  net_addr addr;
3487  int offset,lookup;
3488 
3489  offset = HEADER_LENGTH;
3490 
3491  fill_net_addr(&addr, hinfo->addr, hinfo->port);
3492 
3493  PACKET_SET_SIZE();
3494 
3495  // if we're connected , see who sent us this pong
3497  lookup = find_player_id(hinfo->id);
3498  if(lookup == -1){
3499  return;
3500  }
3501 
3502  p = &Net_players[lookup];
3503 
3504  // evaluate the ping
3505  multi_ping_eval_pong(&Net_players[lookup].s_info.ping);
3506 
3507  // put in calls to any functions which may want to know about the ping times from
3508  // this guy
3511  }
3512 
3513  // mark his socket as still alive (extra precaution)
3515  }
3516  // otherwise, do any special processing
3517  else {
3518  // if we're in the join game state, see if this pong came from a server on our
3519  // list
3522  }
3523  }
3524 }
3525 
3526 // send a ping packet
3528 {
3529  unsigned char data[8];
3530  int packet_size;
3531 
3532  // build the header and send the packet
3533  BUILD_HEADER( PING );
3534  psnet_send(addr, &data[0], packet_size);
3535 }
3536 
3537 // send a pong packet
3539 {
3540  unsigned char data[8];
3541  int packet_size;
3542 
3543  // build the header and send the packet
3544  BUILD_HEADER(PONG);
3545  psnet_send(addr, &data[0], packet_size);
3546 }
3547 
3548 // sent from host to master. give me the list of missions you have.
3549 // this will be used only in a standalone mode
3551 {
3553  int packet_size;
3554 
3555  // build the header and ask for a list of missions or campaigns (depending
3556  // on the 'what' flag).
3558 
3559  multi_io_send_reliable(Net_player, data, packet_size);
3560 }
3561 
3562 // maximum number of bytes that we can send in a mission items packet.
3563 #define MAX_MISSION_ITEMS_BYTES (MAX_PACKET_SIZE - (sizeof(multi_create_info) + 1) )
3564 
3565 // defines used to tell what type of packets are being sent
3566 #define MISSION_LIST_ITEMS 1
3567 #define CAMPAIGN_LIST_ITEMS 2
3568 
3569 // send an individual mission file item
3571 {
3573  int packet_size, i;
3574  ubyte stop, type;
3575 
3576  // build the header
3578 
3579  // send the list of missions and campaigns avilable on the server. Stop when
3580  // reaching a certain maximum
3581  type = MISSION_LIST_ITEMS;
3582  ADD_DATA( type );
3583  for (i = 0; i < (int)Multi_create_mission_list.size(); i++ ) {
3584  stop = 0;
3585  ADD_DATA( stop );
3586 
3590  ADD_DATA( Multi_create_mission_list[i].max_players );
3591  ADD_INT( Multi_create_mission_list[i].respawn );
3592 
3593  // STANDALONE_ONLY
3594  ADD_DATA( Multi_create_mission_list[i].valid_status );
3595 
3596  if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3597  stop = 1;
3598  ADD_DATA( stop );
3599  multi_io_send_reliable(pl, data, packet_size);
3601  ADD_DATA( type );
3602  }
3603  }
3604  stop = 1;
3605  ADD_DATA(stop);
3606  multi_io_send_reliable(pl, data, packet_size);
3607 
3608  // send the campaign information
3609  type = CAMPAIGN_LIST_ITEMS;
3611  ADD_DATA( type );
3612  for (i = 0; i < (int)Multi_create_campaign_list.size(); i++ ) {
3613  stop = 0;
3614  ADD_DATA( stop );
3615 
3619  ADD_DATA( Multi_create_campaign_list[i].max_players );
3620 
3621  if ( packet_size > (int)MAX_MISSION_ITEMS_BYTES ) {
3622  stop = 1;
3623  ADD_DATA( stop );
3624  multi_io_send_reliable(pl, data, packet_size);
3626  ADD_DATA( type );
3627  }
3628  }
3629  stop = 1;
3630  ADD_DATA(stop);
3631  multi_io_send_reliable(pl, data, packet_size);
3632 }
3633 
3634 // process a request for a list of missions
3636 {
3637  int player_num,offset;
3638 
3639  offset = HEADER_LENGTH;
3640  PACKET_SET_SIZE();
3641 
3642  // fill in the address information of where this came from
3643  player_num = find_player_id(hinfo->id);
3644  if(player_num == -1){
3645  nprintf(("Network","Could not find player to send mission list items to!\n"));
3646  return;
3647  }
3648 
3649  send_mission_items( &Net_players[player_num] );
3650 }
3651 
3652 // process an individual mission file item
3654 {
3655  int offset, flags;
3656  char filename[MAX_FILENAME_LEN], name[NAME_LENGTH], valid_status;
3657  ubyte stop, type,max_players;
3658  uint respawn;
3659  multi_create_info mcip;
3660 
3662  offset = HEADER_LENGTH;
3663 
3664  GET_DATA( type );
3665  GET_DATA(stop);
3666  while( !stop ) {
3667  GET_STRING( filename );
3668  GET_STRING( name );
3669  GET_INT( flags );
3670  GET_DATA( max_players );
3671 
3672  // missions also have respawns and a crc32 associated with them
3673  if(type == MISSION_LIST_ITEMS){
3674  GET_UINT(respawn);
3675 
3676  // STANDALONE_ONLY
3677  GET_DATA(valid_status);
3678 
3679  strcpy_s(mcip.filename, filename );
3680  strcpy_s(mcip.name, name );
3681  mcip.flags = flags;
3682  mcip.respawn = respawn;
3683  mcip.max_players = max_players;
3684 
3685  // STANDALONE_ONLY
3686  mcip.valid_status = valid_status;
3687 
3688  Multi_create_mission_list.push_back( mcip );
3689  } else if ( type == CAMPAIGN_LIST_ITEMS ) {
3690  strcpy_s(mcip.filename, filename );
3691  strcpy_s(mcip.name, name );
3692  mcip.flags = flags;
3693  mcip.respawn = 0;
3694  mcip.max_players = max_players;
3695 
3696  Multi_create_campaign_list.push_back( mcip );
3697  }
3698 
3699  GET_DATA( stop );
3700  }
3701 
3702  PACKET_SET_SIZE();
3703 
3704  // this will cause whatever list to get resorted (although they should be appearing in order)
3706 }
3707 
3708 // send a request to the server to pause or unpause the game
3710 {
3712  ubyte val;
3713  int packet_size = 0;
3714 
3716 
3717  // build the header
3719  val = (ubyte) pause;
3720 
3721  // add the pause info
3722  ADD_DATA(val);
3723 
3724  // send the request to the server
3725  multi_io_send_reliable(Net_player, data, packet_size);
3726 }
3727 
3728 // process a pause update packet (pause, unpause, etc)
3730 {
3731  int offset;
3732  ubyte val;
3733  int player_index;
3734 
3735  offset = HEADER_LENGTH;
3736 
3737  // get the data
3738  GET_DATA(val);
3739  PACKET_SET_SIZE();
3740 
3741  // get who sent the packet
3742  player_index = find_player_id(hinfo->id);
3743  // if we don't know who sent the packet, don't do anything
3744  if(player_index == -1){
3745  return;
3746  }
3747 
3748  // if we're the server, we should evaluate whether this guy is allowed to send the packet
3749  multi_pause_server_eval_request(&Net_players[player_index],(int)val);
3750 }
3751 
3752 // send a game information update
3754 {
3755  int packet_size;
3756  ubyte data[MAX_PACKET_SIZE], paused;
3757 
3758  // set the paused variable
3759  paused = (ubyte)((Netgame.game_state == NETGAME_STATE_PAUSED)?1:0);
3760 
3762  ADD_INT( Missiontime ); // NOTE: this is a long so careful with swapping in 64-bit platforms - taylor
3763  ADD_DATA( paused );
3764 
3765  multi_io_send_to_all(data, packet_size);
3766 }
3767 
3768 // process a game information update
3770 {
3771  int offset;
3772  fix mission_time;
3773  ubyte paused;
3774 
3775  offset = HEADER_LENGTH;
3776 
3777  // get the mission time -- we should examine our time and the time from the server. If off by some delta
3778  // time, set our time to server time (should take ping time into account!!!)
3779  GET_INT( mission_time ); // NOTE: this is a long so careful with swapping in 64-bit platforms - taylor
3780  GET_DATA( paused );
3781  PACKET_SET_SIZE();
3782 }
3783 
3784 // send an ingame nak packet
3785 void send_ingame_nak(int state, net_player *p)
3786 {
3788  int packet_size;
3789  packet_size = 0;
3791 
3792  ADD_INT(state);
3793 
3794  multi_io_send_reliable(p, data, packet_size);
3795 }
3796 
3797 // process an ingame nak packet
3799 {
3800  int offset,state,pid;
3801 
3802  offset = HEADER_LENGTH;
3803  GET_INT(state);
3804  PACKET_SET_SIZE();
3805 
3806  pid = find_player_id(hinfo->id);
3807  if(pid < 0){
3808  return;
3809  }
3810 
3811  switch(state){
3812  case ACK_FILE_ACCEPTED :
3814  nprintf(("Network","Mission file rejected by server, aborting...\n"));
3816  break;
3817  }
3818 }
3819 
3820 // If the end_mission SEXP has been used tell clients to skip straight to the debrief screen
3822 {
3824  int packet_size;
3825 
3826  packet_size = 0;
3828 
3830  {
3831  // tell everyone to leave the game
3832  multi_io_send_to_all_reliable(data, packet_size);
3833  }
3834 }
3835 
3836 // process a packet indicating that we should jump straight to the debrief screen
3838 {
3839  int offset;
3840 
3841  offset = HEADER_LENGTH;
3842 
3843  PACKET_SET_SIZE();
3844 
3845  ml_string("Receiving force end mission packet");
3846 
3847  // Since only the server sends out these packets it should never receive one
3849 
3852 }
3853 
3854 // send a packet telling players to end the mission
3856 {
3858  int packet_size;
3859 
3860  packet_size = 0;
3862 
3863  // sending to a specific player?
3864  if(pl != NULL){
3866  multi_io_send_reliable(pl, data, packet_size);
3867  return;
3868  }
3869 
3871  // send all player stats here
3873 
3874  // if in dogfight mode, send all dogfight stats as well
3875  ml_string("Before dogfight stats!");
3877  ml_string("Sending dogfight stats!");
3878 
3880  }
3881  ml_string("After dogfight stats!");
3882 
3883  // tell everyone to leave the game
3884  multi_io_send_to_all_reliable(data, packet_size);
3885  } else {
3886  multi_io_send_reliable(Net_player, data, packet_size);
3887  }
3888 }
3889 
3890 // process a packet indicating we should end the current mission
3892 {
3893  int offset;
3894  int player_num;
3895 
3896  offset = HEADER_LENGTH;
3897 
3898  PACKET_SET_SIZE();
3899 
3900  ml_string("Receiving endgame packet");
3901 
3902  // if I'm the server, I should evaluate whether the sender is authorized to end the game
3904  // determine who this came from and make sure he is allowed to end the game
3905  player_num = find_player_id(hinfo->id);
3906  Assert(player_num != -1);
3907  if(player_num < 0){
3908  return;
3909  }
3910 
3911  // if the player is allowed to end the mission
3912  if(!multi_can_end_mission(&Net_players[player_num])){
3913  return;
3914  }
3915 
3916  // act as if we hit alt+j locally
3918  }
3919  // all clients process immediately
3920  else {
3921  // ingame joiners should quit when they receive an endgame packet since the game is over
3924  return;
3925  }
3926 
3927  // do any special processing for being in a state other than the gameplay state
3929 
3930  // make sure we're not already in the debrief state
3933  }
3934  }
3935 }
3936 
3937 // send a position/orientation update for myself (if I'm an observer)
3939 {
3941  int packet_size;
3942  int ret;
3943  ushort target_sig;
3944 
3945  // its possible for the master to be an observer if has run out of respawns. In this case, he doesn't need
3946  // to send any update packets to anyone.
3948  return;
3949  }
3950 
3951  if((Player_obj == NULL) || (Player_obj->type != OBJ_OBSERVER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
3952  return;
3953  }
3954 
3955  packet_size = 0;
3956 
3958 
3959  ret = multi_pack_unpack_position( 1, data + packet_size, &Player_obj->pos );
3960  packet_size += ret;
3961  ret = multi_pack_unpack_orient( 1, data + packet_size, &Player_obj->orient );
3962  packet_size += ret;
3963 
3964  // add targeting infomation
3965  if((Player_ai != NULL) && (Player_ai->target_objnum >= 0)){
3967  } else {
3968  target_sig = 0;
3969  }
3970  ADD_USHORT(target_sig);
3971 
3972  multi_io_send(Net_player, data, packet_size);
3973 }
3974 
3975 // process a position/orientation update from an observer
3977 {
3978  int offset,ret;
3979  int obs_num;
3980  vec3d g_vec;
3981  matrix g_mat;
3982  physics_info bogus_pi;
3983  ushort target_sig;
3984  object *target_obj;
3985  offset = HEADER_LENGTH;
3986 
3987  obs_num = find_player_id(hinfo->id);
3988 
3989  memset(&bogus_pi,0,sizeof(physics_info));
3990  ret = multi_pack_unpack_position( 0, data + offset, &g_vec );
3991  offset += ret;
3992  ret = multi_pack_unpack_orient( 0, data + offset, &g_mat );
3993  offset += ret;
3994 
3995  // targeting information
3996  GET_USHORT(target_sig);
3997  PACKET_SET_SIZE();
3998 
3999  if((obs_num < 0) || (Net_players[obs_num].m_player->objnum < 0)){
4000  return;
4001  }
4002 
4003  // set targeting info
4004  if(target_sig == 0){
4005  Net_players[obs_num].s_info.target_objnum = -1;
4006  } else {
4007  target_obj = multi_get_network_object(target_sig);
4008  Net_players[obs_num].s_info.target_objnum = (target_obj == NULL) ? -1 : OBJ_INDEX(target_obj);
4009  }
4010 
4011  Objects[Net_players[obs_num].m_player->objnum].pos = g_vec;
4012  Objects[Net_players[obs_num].m_player->objnum].orient = g_mat;
4013  Net_players[obs_num].s_info.eye_pos = g_vec;
4014  Net_players[obs_num].s_info.eye_orient = g_mat;
4015 }
4016 
4018 {
4020  int packet_size,idx;
4021  ubyte stop;
4022 
4023  packet_size = 0;
4024  stop = 0xff;
4026  for(idx=0;idx<MAX_PLAYERS;idx++){
4028  ADD_DATA(stop);
4029  ADD_SHORT(Net_players[idx].player_id);
4030  ADD_USHORT(Objects[Net_players[idx].m_player->objnum].net_signature);
4031  ADD_INT(Net_players[idx].p_info.ship_class);
4032  ADD_INT(Net_players[idx].p_info.ship_index);
4033  }
4034  }
4035  stop = 0x0;
4036  ADD_DATA(stop);
4037 
4038  // standalone case or not
4040  multi_io_send_to_all_reliable(data, packet_size);
4041  } else {
4042  multi_io_send_reliable(Net_player, data, packet_size);
4043  }
4044 }
4045 
4047 {
4048  int offset;
4049  int player_num,ship_class,ship_index;
4050  ushort net_sig;
4051  object *objp;
4052  ubyte stop;
4053  short player_id;
4054 
4055  offset = HEADER_LENGTH;
4056 
4057  // first untag all of the player ships and make them OF_COULD_BE_PLAYER
4059 
4060  GET_DATA(stop);
4061  while(stop != 0x0){
4062  GET_SHORT(player_id);
4063  GET_USHORT(net_sig);
4064  GET_INT(ship_class);
4065  GET_INT(ship_index);
4066  player_num = find_player_id(player_id);
4067  if(player_num < 0){
4068  nprintf(("Network","Error looking up player for object/slot assignment!!\n"));
4069  } else {
4070  // call the function in multiutil.cpp to set up the player object stuff
4071  // being careful not to muck with the standalone object
4072  if(!((player_num == 0) && (Game_mode & GM_STANDALONE_SERVER))){
4073  objp = multi_get_network_object(net_sig);
4074  if (objp == NULL) {
4075  Error(LOCATION, "Could not retrieve net object for signature %d!\n", net_sig);
4076  }
4077  multi_assign_player_ship( player_num, objp, ship_class );
4078  Net_players[player_num].p_info.ship_index = ship_index;
4079  objp->flags &= ~(OF_COULD_BE_PLAYER);
4080  objp->flags |= OF_PLAYER_SHIP;
4081  }
4082  }
4083  GET_DATA(stop);
4084  }
4085  PACKET_SET_SIZE();
4086 
4087  // standalone should forward the packet and wait for a response
4090  }
4091 
4094 }
4095 
4096 // two functions to deal with ships changing their primary/secondary weapon status. 'what' indicates
4097 // if this change is a primary or secondary change. new_bank is the new current primary/secondary
4098 // bank, link_status is whether primaries are linked or not, or secondaries are dual fire or not
4099 void send_ship_weapon_change( ship *shipp, int what, int new_bank, int link_status )
4100 {
4101  ubyte data[MAX_PACKET_SIZE], utmp;
4102  int packet_size;
4103 
4106  utmp = (ubyte)(what);
4107  ADD_DATA( utmp );
4108  utmp = (ubyte)(new_bank);
4109  ADD_DATA( utmp );
4110  utmp = (ubyte)(link_status);
4111  ADD_DATA( utmp );
4112 
4113  // Removed the above psnet_send() call - it didn't appear to do anything since it was called only from the server anyway - DB
4114  multi_io_send_to_all_reliable(data, packet_size);
4115 }
4116 
4118 {
4119  int offset;
4120  ushort signature;
4121  ubyte what, new_bank, link_status;
4122  object *objp;
4123  ship *shipp;
4124 
4125  offset = HEADER_LENGTH;
4126  GET_USHORT( signature );
4127  GET_DATA( what );
4128  GET_DATA( new_bank );
4129  GET_DATA( link_status );
4130  PACKET_SET_SIZE();
4131 
4132  objp = multi_get_network_object( signature );
4133  if ( objp == NULL ) {
4134  nprintf(("network", "Unable to locate ship with signature %d for weapon state change\n", signature));
4135  return;
4136  }
4137  // Assert( objp->type == OBJ_SHIP );
4138  if(objp->type != OBJ_SHIP){
4139  return;
4140  }
4141 
4142  // if this is my data, do nothing since I already have my own data
4143  if ( objp == Player_obj ){
4144  return;
4145  }
4146 
4147  // now, get the ship and set the new bank and link modes based on the 'what' value
4148  shipp = &Ships[objp->instance];
4149  if ( what == MULTI_PRIMARY_CHANGED ) {
4150  shipp->weapons.current_primary_bank = new_bank;
4151  if ( link_status ){
4152  shipp->flags |= SF_PRIMARY_LINKED;
4153  } else {
4154  shipp->flags &= ~SF_PRIMARY_LINKED;
4155  }
4156  } else {
4157  shipp->weapons.current_secondary_bank = new_bank;
4158  if ( link_status ){
4159  shipp->flags |= SF_SECONDARY_DUAL_FIRE;
4160  } else {
4161  shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
4162  }
4163  }
4164 }
4165 
4166  // ship status change procedure
4167 // 1.) <client> - Client runs through the normal button_function procedure. Any remaining control bits are implied as being
4168 // server critical.
4169 // 2.) <client> - Client puts this button_info item into his last_buttons array and sends a bunch of SHIP_STATUS packets
4170 // for added redundancy.
4171 // 3.) <server> - Receives the packet. Checks to see if the net_player on his side already has this one defined. If so, it
4172 // ignores as a repeat packet. Otherwise it puts it in the last_buttons array for the net_player
4173 // 4.) <server> - Server applies the command on his side (with multi_apply_ship_status(...) and sends the ack (also a SHIP_STATUS)
4174 // back to the client. Also sends multiple times for redundancy
4175 // 5.) <client> - Receives the packet back. Does a lookup into his last_buttons array. If he finds the match, apply the functions
4176 // and remove the item from the list. If no match is found it means that either he has received an ack, has acted
4177 // on it and removed it, or that it has been "timed out" and replaced by a newer button_info.
4178 
4179 #define SHIP_STATUS_REPEAT 2
4181 {
4182  int idx, temp;
4184  int packet_size = 0;
4185 
4186  if(pl == NULL){
4187  return;
4188  }
4189 
4191  ADD_INT(id);
4192  for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4193  temp = bi->status[idx];
4194  ADD_INT(temp);
4195  }
4196 
4197  // server should send reliably (response packet)
4198  if(MULTIPLAYER_MASTER){
4199  multi_io_send_reliable(pl, data, packet_size);
4200  } else {
4201  multi_io_send(pl, data, packet_size);
4202  }
4203 }
4204 
4206 {
4207  int idx;
4208  int offset;
4209  int player_num,unique_id;
4210  button_info bi;
4211  int i_tmp;
4212 
4213  offset = HEADER_LENGTH;
4214 
4215  // zero out the button info structure for good measure
4216  memset(&bi,0,sizeof(button_info));
4217 
4218  // read the button-info
4219  GET_INT(unique_id);
4220 
4221  for(idx=0;idx<NUM_BUTTON_FIELDS;idx++){
4222  GET_INT(i_tmp);
4223  bi.status[idx] = i_tmp;
4224  }
4225 
4226  PACKET_SET_SIZE();
4227 
4228  // this will be handled differently client and server side. Duh.
4229  if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // SERVER SIDE
4230  // find which net-player has sent us butotn information
4231  player_num = find_player_id(hinfo->id);
4232  Assert(player_num >= 0);
4233  if(player_num < 0){
4234  return;
4235  }
4236 
4237  // don't process critical button information for observers
4238  // its a new button_info for this guy. apply and ack
4239  if(!MULTI_OBSERVER(Net_players[player_num]) && !lookup_ship_status(&Net_players[player_num],unique_id)){
4240  // mark that he's pressed this button
4241  // add_net_button_info(&Net_players[player_num], &bi, unique_id);
4242 
4243  // send a return packet
4244  send_ship_status_packet(&Net_players[player_num], &bi,unique_id);
4245 
4246  // apply the button presses to his ship as normal
4247  multi_apply_ship_status(&Net_players[player_num], &bi, 0);
4248  }
4249  // else ignore it as a repeat from the same guy
4250  } else { // CLIENT SIDE
4251  // this is the return from the server, so we should now apply them locally
4252  // if(lookup_ship_status(Net_player,unique_id,1)){
4254  // }
4255  }
4256 }
4257 
4258 // MWA 4/28/9 -- redid this function since message all fighers was really broken
4259 // for clients. Left all details to this function instead of higher level messaging
4260 // code
4261 void send_player_order_packet(int type, int index, int cmd)
4262 {
4264  ubyte val;
4265  ushort target_signature;
4266  char t_subsys;
4267  int packet_size = 0;
4268 
4270 
4271  val = (ubyte)type;
4272  ADD_DATA(val); // ship order or wing order, or message all fighters
4273 
4274  // if we are not messaging all ships or wings, add the index, which is the shipnum or wingnum
4275  if ( val != SQUAD_MSG_ALL ){
4276  ADD_INT(index); // net signature of target ship
4277  }
4278 
4279  ADD_INT(cmd); // the command itself
4280 
4281  // add target data.
4282  target_signature = 0;
4283  if ( Player_ai->target_objnum != -1 ){
4284  target_signature = Objects[Player_ai->target_objnum].net_signature;
4285  }
4286 
4287  ADD_USHORT( target_signature );
4288 
4289  t_subsys = -1;
4290  if ( (Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL) ) {
4291  int s_index;
4292 
4294  Assert( s_index < CHAR_MAX ); // better be less than this!!!!
4295  t_subsys = (char)s_index;
4296  }
4297  ADD_DATA(t_subsys);
4298 
4299  multi_io_send_reliable(Net_player, data, packet_size);
4300 }
4301 
4302 // brief explanation :
4303 // in either case (wing or ship command), we need to send in a pseudo-ai object. Basically, both command handler
4304 // functions "normally" (non multiplayer) use a couple of the Player_ai fields. So, we just fill in the ones necessary
4305 // (which we can reconstruct from the packet data), and pass this as the default variable ai_info *local
4306 // Its kind of a hack, but it eliminates the need to go in and screw around with quite a bit of code
4308 {
4309  int offset, player_num, command, index = 0, tobjnum_save;
4310  ushort target_signature;
4311  char t_subsys, type;
4312  object *objp, *target_objp;
4313  ai_info *aip;
4314  ship *shipp;
4315  ship_subsys *tsubsys_save, *targeted_subsys;
4316 
4318 
4319  // packet values - its easier to read all of these in first
4320 
4321  offset = HEADER_LENGTH;
4322 
4323  GET_DATA( type );
4324  if ( type != SQUAD_MSG_ALL ){
4325  GET_INT( index );
4326  }
4327 
4328  GET_INT( command );
4329  GET_USHORT( target_signature );
4330  GET_DATA( t_subsys );
4331 
4332  PACKET_SET_SIZE();
4333 
4334  player_num = find_player_id(hinfo->id);
4335  if(player_num == -1){
4336  nprintf(("Network","Received player order packet from unknown player\n"));
4337  return;
4338  }
4339 
4340  objp = &Objects[Net_players[player_num].m_player->objnum];
4341  if ( objp->type != OBJ_SHIP ) {
4342  nprintf(("Network", "not doing player order because object requestting is not a ship\n"));
4343  return;
4344  }
4345 
4346  // HACK HACK HACK HACK HACK HACK
4347  // if the player has sent a rearm-repair me message, we should bail here after evaluating it, since most likely the rest of
4348  // the data is BOGUS. All people should be able to to these things as well.
4349  if(command == REARM_REPAIR_ME_ITEM){
4350  hud_squadmsg_repair_rearm(0,&Objects[Net_players[player_num].m_player->objnum]);
4351  return;
4352  } else if(command == ABORT_REARM_REPAIR_ITEM){
4353  hud_squadmsg_repair_rearm_abort(0,&Objects[Net_players[player_num].m_player->objnum]);
4354  return;
4355  }
4356 
4357  // if this player is not allowed to do messaging, quit here
4358  if( !multi_can_message(&Net_players[player_num]) ){
4359  nprintf(("Network","Received player order packet from player not allowed to give orders!!\n"));
4360  return;
4361  }
4362 
4363  // check to see if the type of order is a reinforcement call. If so, intercept it, and
4364  // then call them in.
4365  if ( type == SQUAD_MSG_REINFORCEMENT ) {
4366  Assert( (index >= 0) && (index < Num_reinforcements) );
4367  hud_squadmsg_call_reinforcement(index, player_num);
4368  return;
4369  }
4370 
4371  // set the player's ai information here
4372  shipp = &Ships[objp->instance];
4373  aip = &Ai_info[shipp->ai_index];
4374 
4375  // get the target objnum and targeted subsystem. Quick out if we don't have an object to act on.
4376  target_objp = multi_get_network_object( target_signature );
4377  if ( target_objp == NULL ) {
4378  return;
4379  }
4380 
4381  targeted_subsys = NULL;
4382  if ( t_subsys != -1 ) {
4383  Assert( target_objp != NULL );
4384  targeted_subsys = ship_get_indexed_subsys( &Ships[target_objp->instance], t_subsys);
4385  }
4386 
4387  // save and restore the target objnum and targeted subsystem so that we don't mess up other things
4388  // here
4389  tobjnum_save = aip->target_objnum;
4390  tsubsys_save = aip->targeted_subsys;
4391 
4392  if ( target_objp ) {
4393  aip->target_objnum = OBJ_INDEX(target_objp);
4394  } else {
4395  aip->target_objnum = -1;
4396  }
4397 
4398  aip->targeted_subsys = targeted_subsys;
4399 
4400  if ( type == SQUAD_MSG_SHIP ) {
4401  hud_squadmsg_send_ship_command(index, command, 1, SQUADMSG_HISTORY_ADD_ENTRY, player_num);
4402  } else if ( type == SQUAD_MSG_WING ) {
4403  hud_squadmsg_send_wing_command(index, command, 1, SQUADMSG_HISTORY_ADD_ENTRY, player_num);
4404  } else if ( type == SQUAD_MSG_ALL ) {
4405  hud_squadmsg_send_to_all_fighters( command, player_num );
4406  }
4407 
4408  Assert(tobjnum_save != Ships[aip->shipnum].objnum); // make sure not targeting self
4409  aip->target_objnum = tobjnum_save;
4410  aip->targeted_subsys = tsubsys_save;
4411 }
4412 
4413 // FILE SIGNATURE stuff :
4414 // there are 2 cases for file signature sending which are handled very differently
4415 // 1.) Pregame. In this case, the host requires that all clients send a filesig packet (when process_file_sig() is called, it
4416 // posts an ACK_FILE_ACCEPTED packet to ack_evaluate, so he thinks they have acked).
4417 // 2.) Ingame join. In this case, the client sends his filesig packet automatically to the server and the _client_ waits for
4418 // the ack, before continuing to join. It would be way too messy to have the server wait on the clients ack, since he
4419 // would have to keep track of up to potentially 14 other ack handles (ouch).
4420 void send_file_sig_packet(ushort sum_sig,int length_sig)
4421 {
4423  int packet_size = 0;
4424 
4426  ADD_USHORT(sum_sig);
4427  ADD_INT(length_sig);
4428 
4429  multi_io_send_reliable(Net_player, data, packet_size);
4430 }
4431 
4433 {
4434  int offset;
4435  int length_sig;
4436  ushort sum_sig;
4437  offset = HEADER_LENGTH;
4438 
4439  // should only be received on the server-side
4441 
4442  GET_USHORT(sum_sig);
4443  GET_INT(length_sig);
4444  PACKET_SET_SIZE();
4445  server_verify_filesig(hinfo->id, sum_sig, length_sig);
4446 }
4447 
4448 void send_file_sig_request(char *file_name)
4449 {
4451  int packet_size = 0;
4452 
4454  ADD_STRING(file_name);
4455 
4457 
4458  multi_io_send_to_all_reliable(data, packet_size);
4459 }
4460 
4462 {
4463  int offset = HEADER_LENGTH;
4464 
4465  // get the mission name
4467  PACKET_SET_SIZE();
4468 
4469  // set the current mission filename
4471 
4472  // get the checksum
4474 
4475  if(!multi_endgame_ending()){
4476  // reply to the server
4478  }
4479 }
4480 
4481 // functions to deal with subsystems getting whacked
4482 void send_subsystem_destroyed_packet( ship *shipp, int index, vec3d world_hitpos )
4483 {
4485  int packet_size;
4486  ubyte uindex;
4487  vec3d tmp, local_hitpos;
4488  object *objp;
4489 
4490  Assert ( index < UCHAR_MAX );
4491  uindex = (ubyte)(index);
4492 
4493  objp = &Objects[shipp->objnum];
4494 
4495  vm_vec_sub(&tmp, &world_hitpos, &objp->pos );
4496  vm_vec_rotate( &local_hitpos, &tmp, &objp->orient );
4497 
4500  ADD_DATA( uindex );
4501  ADD_VECTOR( local_hitpos );
4502 
4503  multi_io_send_to_all_reliable(data, packet_size);
4504 }
4505 
4507 {
4508  int offset;
4509  ushort signature;
4510  ubyte uindex;
4511  object *objp;
4512  vec3d local_hit_pos, world_hit_pos;
4513 
4514  offset = HEADER_LENGTH;
4515 
4516  GET_USHORT( signature );
4517  GET_DATA( uindex );
4518  GET_VECTOR( local_hit_pos );
4519 
4520  // get the network object. process it if we find it.
4521  objp = multi_get_network_object( signature );
4522  if ( objp != NULL ) {
4523  ship *shipp;
4524  ship_subsys *subsysp;
4525 
4526  // be sure we have a ship!!!
4527  // Assert ( objp->type == OBJ_SHIP );
4528  if(objp->type != OBJ_SHIP){
4529  PACKET_SET_SIZE();
4530  return;
4531  }
4532 
4533  shipp = &Ships[objp->instance];
4534 
4535  // call to get the pointer to the subsystem we should be working on
4536  subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4537  if (subsysp == NULL) {
4538  nprintf(("Network", "Could not find subsys %d for ship %s to process as being destroyed\n", (int)uindex, shipp->ship_name ));
4539  PACKET_SET_SIZE();
4540  return;
4541  }
4542 
4543  vm_vec_unrotate( &world_hit_pos, &local_hit_pos, &objp->orient );
4544  vm_vec_add2( &world_hit_pos, &objp->pos );
4545 
4546  do_subobj_destroyed_stuff( shipp, subsysp, &world_hit_pos );
4547  if ( objp == Player_obj ) {
4549  }
4550  }
4551 
4552  PACKET_SET_SIZE();
4553 }
4554 
4555 
4556 // packet to tell clients cargo of a ship was revealed to all
4558 {
4559  ubyte data[MAX_PACKET_SIZE], uindex;
4560  int packet_size;
4561 
4562  Assert ( index < UCHAR_MAX );
4563  uindex = (ubyte)(index);
4564 
4565  // build the header and add the data
4568  ADD_DATA( uindex );
4569 
4570  // server sends to all players
4571  if(MULTIPLAYER_MASTER){
4572  multi_io_send_to_all_reliable(data, packet_size);
4573  }
4574  // clients just send to the server
4575  else {
4576  multi_io_send_reliable(Net_player, data, packet_size);
4577  }
4578 }
4579 
4580 // process a subsystem cargo revealed packet
4582 {
4583  int offset;
4584  ushort signature;
4585  ubyte uindex;
4586  object *objp;
4587  ship *shipp;
4588  ship_subsys *subsysp;
4589 
4590  offset = HEADER_LENGTH;
4591  GET_USHORT( signature );
4592  GET_DATA( uindex );
4593  PACKET_SET_SIZE();
4594 
4595  // get a ship pointer and call the ship function to reveal the cargo
4596  objp = multi_get_network_object( signature );
4597  if ( objp == NULL ) {
4598  nprintf(("Network", "Could not find object with net signature %d for cargo revealed\n", signature ));
4599  return;
4600  }
4601 
4602  // Assert( objp->type == OBJ_SHIP );
4603  if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4604  return;
4605  }
4606 
4607  shipp = &Ships[objp->instance];
4608 
4609  // call to get the pointer to the subsystem we should be working on
4610  subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4611  if (subsysp == NULL) {
4612  nprintf(("Network", "Could not find subsys for ship %s for cargo revealed\n", Ships[objp->instance].ship_name ));
4613  return;
4614  }
4615 
4616  // this will take care of re-routing to all other clients
4617  ship_do_cap_subsys_cargo_revealed( shipp, subsysp, 1 );
4618 
4619  // server should rebroadcast
4620  if(MULTIPLAYER_MASTER){
4621  send_subsystem_cargo_revealed_packet(&Ships[objp->instance], (int)uindex);
4622  }
4623 }
4624 
4625 // packet to tell clients cargo of a ship was hidden to all
4627 {
4628  ubyte data[MAX_PACKET_SIZE], uindex;
4629  int packet_size;
4630 
4631  Assert ( index < UCHAR_MAX );
4632  uindex = (ubyte)(index);
4633 
4634  // build the header and add the data
4637  ADD_DATA( uindex );
4638 
4639  // server sends to all players
4640  if(MULTIPLAYER_MASTER){
4641  multi_io_send_to_all_reliable(data, packet_size);
4642  }
4643  // clients just send to the server
4644  else {
4645  multi_io_send_reliable(Net_player, data, packet_size);
4646  }
4647 }
4648 
4649 // process a subsystem cargo hidden packet
4651 {
4652  int offset;
4653  ushort signature;
4654  ubyte uindex;
4655  object *objp;
4656  ship *shipp;
4657  ship_subsys *subsysp;
4658 
4659  offset = HEADER_LENGTH;
4660  GET_USHORT( signature );
4661  GET_DATA( uindex );
4662  PACKET_SET_SIZE();
4663 
4664  // get a ship pointer and call the ship function to reveal the cargo
4665  objp = multi_get_network_object( signature );
4666  if ( objp == NULL ) {
4667  nprintf(("Network", "Could not find object with net signature %d for cargo hidden\n", signature ));
4668  return;
4669  }
4670 
4671  // Assert( objp->type == OBJ_SHIP );
4672  if((objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
4673  return;
4674  }
4675 
4676  shipp = &Ships[objp->instance];
4677 
4678  // call to get the pointer to the subsystem we should be working on
4679  subsysp = ship_get_indexed_subsys( shipp, (int)uindex );
4680  if (subsysp == NULL) {
4681  nprintf(("Network", "Could not find subsys for ship %s for cargo hidden\n", Ships[objp->instance].ship_name ));
4682  return;
4683  }
4684 
4685  // this will take care of re-routing to all other clients
4686  ship_do_cap_subsys_cargo_hidden( shipp, subsysp, 1 );
4687 
4688  // server should rebroadcast
4689  if(MULTIPLAYER_MASTER){
4690  send_subsystem_cargo_hidden_packet(&Ships[objp->instance], (int)uindex);
4691  }
4692 }
4693 
4695 {
4697  int packet_size = 0;
4698 
4701 
4702  if(pl == NULL){
4703  multi_io_send_to_all_reliable(data, packet_size);
4704  } else {
4705  multi_io_send_reliable(pl, data, packet_size);
4706  }
4707 }
4708 
4710 {
4711  char str[100];
4712  int offset = HEADER_LENGTH;
4713 
4714  GET_STRING(str);
4715  PACKET_SET_SIZE();
4716 
4719  if(!Multi_mission_loaded){
4720 
4721  // MWA 2/3/98 -- ingame join changes!!!
4722  // everyone can go through the same mission loading path here!!!!
4723  nprintf(("Network","Loading mission..."));
4724 
4725  // notify everyone that I'm loading the mission
4728 
4729  // do the load itself
4730  game_start_mission();
4731 
4732  // ingame joiners need to "untag" all player ships as could_be_players. The ingame joining
4733  // code will remark the correct player ships
4736  }
4737 
4741 
4743  nprintf(("Network","Finished loading mission\n"));
4744  }
4745 }
4746 
4748 {
4750  int packet_size = 0;
4751 
4753 
4755 
4756  // ingame joiners will get special data. We need to tell them about the state of the mission, like paused,
4757  // and possible other things.
4758  if ( pl != NULL ) {
4759  if ( pl->flags & NETINFO_FLAG_INGAME_JOIN ) {
4761  }
4762  }
4763 
4764  // broadcast
4765  if(pl == NULL){
4766  multi_io_send_to_all_reliable(data, packet_size);
4767  }
4768  // send to a specific player
4769  else {
4770  multi_io_send_reliable(pl, data, packet_size);
4771  }
4772 }
4773 
4775 {
4776  int offset = HEADER_LENGTH;
4777  int state;
4778 
4779  state = 0;
4780 
4781  // if I am ingame joining, there should be extra data. For now, this data is the netgame state.
4782  // the game could be paused, so ingame joiner needs to deal with it.
4784  GET_INT( state );
4785  Netgame.game_state = state;
4786  }
4787 
4788  PACKET_SET_SIZE();
4789 
4790  // handle any special processing for being in a weird substate
4792 
4793  // if I'm an ingame joiner, go to the ship select screen, or if I'm an observer, jump right in!
4797  } else {
4801  }
4802  } else {
4803  // start the mission!!
4809  }
4810  }
4811 
4812  // recalc all object pairs now
4813  extern void obj_reset_all_collisions();
4815 
4816  // display some cool text
4817  multi_common_add_text(XSTR("Received mission start\n",720),1);
4818 
4819  // NETLOG
4820  ml_string(NOX("Client received mission start from server - entering mission"));
4821 }
4822 
4823 //XSTR:OFF
4824 
4825 char *repair_text[] = {
4826  "unknown",
4827  "REPAIR_INFO_BEGIN",
4828  "REPAIR_INFO_END",
4829  "REPAIR_INFO_UPDATE",
4830  "REPAIR_INFO_QUEUE",
4831  "REPAIR_INFO_ABORT",
4832  "REPAIR_INFO_BROKEN",
4833  "REPAIR_INFO_WARP_ADD",
4834  "REPAIR_INFO_WARP_REMOVE",
4835  "REPAIR_INFO_ONWAY",
4836  "REPAIR_INFO_KILLED",
4837  "REPAIR_INFO_COMPLETE",
4838 };
4839 
4840 //XSTR:ON
4841 
4842 // the following two routines deal with updating and sending information regarding players
4843 // rearming and repairing during the game. The process function calls the routines to deal with
4844 // setting flags and other interesting things.
4845 void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code )
4846 {
4847  int packet_size = 0;
4848  ushort repaired_signature, repair_signature;
4850  ubyte cd;
4851 
4852  // use the network signature of the destination object if there is one, -1 otherwise.
4853  // client will piece it all together
4854  repaired_signature = repaired_objp->net_signature;
4855 
4856  // the repair ship may be NULL here since it might have been destroyed
4857  repair_signature = 0;
4858  if ( repair_objp ){
4859  repair_signature = repair_objp->net_signature;
4860  }
4861 
4863  cd = (ubyte)code;
4864  ADD_DATA(cd);
4865  ADD_USHORT( repaired_signature );
4866  ADD_USHORT( repair_signature );
4867 
4868  multi_io_send_to_all_reliable(data, packet_size);
4869 
4870  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));
4871 }
4872 
4874 {
4875  int offset = HEADER_LENGTH;
4876  ushort repaired_signature, repair_signature;
4877  object *repaired_objp, *repair_objp;
4878  ubyte code;
4879 
4880  GET_DATA(code);
4881  GET_USHORT( repaired_signature );
4882  GET_USHORT( repair_signature );
4883  PACKET_SET_SIZE();
4884 
4885  repaired_objp = multi_get_network_object( repaired_signature );
4886  repair_objp = multi_get_network_object( repair_signature );
4887 
4888  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));
4889 
4891  return;
4892  }
4893 
4894  if ( repaired_objp == NULL ) {
4895  Int3(); // Sandeep says this is bad bad bad. No ship to repair.
4896  return;
4897  }
4898 
4899  // the hope is to simply call the routine in the ai code to set/unset flags
4900  // based on the code value and everything else should happen..I hope....
4901  if ( (code != REPAIR_INFO_WARP_ADD) && (code != REPAIR_INFO_WARP_REMOVE ) ) {
4902 
4903  ai_do_objects_repairing_stuff( repaired_objp, repair_objp, (int)code );
4904 
4905  // set the dock flags when repair begins. Prevents problem in lagging docking
4906  // packet. Also set any other flags/modes which need to be set to prevent Asserts.
4907  // bleah.
4908  if ( (code == REPAIR_INFO_BEGIN) && (repair_objp != NULL) ) {
4909 // Karajorma removed this in revision 4808 to fix bug 1088. Problem is, if
4910 // this was originally intended to prevent docking problems, will they return?
4911 /*
4912  // find indexes from goal
4913  ai_info *aip = &Ai_info[Ships[repair_objp->instance].ai_index];
4914  Assert(aip->active_goal >= 0);
4915  ai_goal *aigp = &aip->goals[aip->active_goal];
4916  Assert(aigp->flags & AIGF_DOCK_INDEXES_VALID);
4917 
4918  int docker_index = aigp->docker.index;
4919  int dockee_index = aigp->dockee.index;
4920 
4921  ai_do_objects_docked_stuff( repair_objp, docker_index, repaired_objp, dockee_index );
4922 */
4923  Ai_info[Ships[repair_objp->instance].ai_index].mode = AIM_DOCK;
4924  }
4925 
4926  // if the repair is done (either by abort, or ending), mark the repair ship's goal
4927  // as being done.
4928  if ( ((code == REPAIR_INFO_ABORT) || (code == REPAIR_INFO_END)) && repair_objp ){
4929  ai_mission_goal_complete( &Ai_info[Ships[repair_objp->instance].ai_index] );
4930  }
4931  } else {
4932  if ( code == REPAIR_INFO_WARP_ADD ){
4933  mission_bring_in_support_ship( repaired_objp );
4934  } else {
4935  mission_remove_scheduled_repair( repaired_objp );
4936  }
4937  }
4938 }
4939 
4940 // sends information updating clients on certain AI information that clients will
4941 // need to know about to keep HUD information up to date. objp is the object that we
4942 // are updating, and what is the type of stuff that we are updating.
4943 void send_ai_info_update_packet( object *objp, char what, object * other_objp )
4944 {
4945  int packet_size;
4946  ushort other_signature;
4948  ai_info *aip;
4949  ai_goal *aigp = NULL;
4950  ubyte docker_index, dockee_index;
4951 
4952  // Assert( objp->type == OBJ_SHIP );
4953  if(objp->type != OBJ_SHIP){
4954  return;
4955  }
4956  aip = &Ai_info[Ships[objp->instance].ai_index];
4957 
4958  // do an out here
4959  if ( Ships[objp->instance].flags & (SF_DEPARTING | SF_DYING) )
4960  return;
4961 
4962  switch( what ) {
4963 
4964  case AI_UPDATE_DOCK:
4965  case AI_UPDATE_UNDOCK:
4966  Assert (other_objp != NULL);
4967  if (other_objp == NULL) {
4968  return;
4969  }
4970  break;
4971 
4972  default:
4973  Assert (other_objp == NULL);
4974  break;
4975  }
4976 
4978  ADD_USHORT( objp->net_signature );
4979  ADD_DATA( what );
4980 
4981  // depending on the "what" value, we will send different information
4982  // to the clients
4983  switch( what ) {
4984 
4985  case AI_UPDATE_DOCK:
4986  // for docking ships, add the signature of the ship that we are docked with.
4987  Assert( other_objp != NULL );
4988  other_signature = other_objp->net_signature;
4989 
4990  // Goober5000 - this is sort of weird, but it's the best way to do it
4991  docker_index = (ubyte) dock_find_dockpoint_used_by_object(objp, other_objp);
4992  dockee_index = (ubyte) dock_find_dockpoint_used_by_object(other_objp, objp);
4993 
4994  ADD_USHORT( other_signature );
4995  ADD_DATA( docker_index );
4996  ADD_DATA( dockee_index );
4997  break;
4998 
4999  case AI_UPDATE_UNDOCK:
5000  // same for undocking ships
5001  Assert( other_objp != NULL );
5002  other_signature = other_objp->net_signature;
5003  ADD_USHORT( other_signature );
5004 
5005  break;
5006 
5007  case AI_UPDATE_ORDERS: {
5008  int shipnum;
5009 
5010  // for orders, we only need to send a little bit of information here. Be sure that the
5011  // first order for this ship is active
5013  aigp = &aip->goals[aip->active_goal];
5014 
5015  ADD_INT( aigp->ai_mode );
5016  ADD_INT( aigp->ai_submode );
5017 
5018  shipnum = -1;
5019  if ( aigp->target_name != NULL )
5020  shipnum = ship_name_lookup( aigp->target_name );
5021 
5022  // the ship_name member of the goals structure may or may not contain a real shipname. If we don't
5023  // have a valid shipnum, then don't sweat it since it may not really be a ship.
5024  if ( shipnum != -1 ) {
5025  Assert( Ships[shipnum].objnum != -1 );
5026  other_signature = Objects[Ships[shipnum].objnum].net_signature;
5027  } else
5028  other_signature = 0;
5029 
5030  ADD_USHORT( other_signature );
5031 
5032  // for docking, add the dock and dockee index
5033  if ( aigp->ai_mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5035  Assert( (aigp->docker.index >= 0) && (aigp->docker.index < UCHAR_MAX) );
5036  Assert( (aigp->dockee.index >= 0) && (aigp->dockee.index < UCHAR_MAX) );
5037  docker_index = (ubyte) aigp->docker.index;
5038  dockee_index = (ubyte) aigp->dockee.index;
5039  ADD_DATA( docker_index );
5040  ADD_DATA( dockee_index );
5041  }
5042  break;
5043  }
5044 
5045  default:
5046  Int3();
5047  }
5048 
5049  multi_rate_add(1, "aiu", packet_size);
5050  multi_io_send_to_all_reliable(data, packet_size);
5051 }
5052 
5053 // process an ai_info update packet. Docking/undocking, ai orders, etc. are taken care of here. This
5054 // information is mainly used to keep the clients HUD up to date with the appropriate information.
5056 {
5057  int offset = HEADER_LENGTH;
5058  int mode, submode;
5059  ushort net_signature, other_net_signature;
5060  object *objp, *other_objp;
5061  ai_info *aip;
5062  ai_goal *aigp = NULL;
5063  char code;
5064  ubyte docker_index = 0, dockee_index = 0;
5065 
5066  GET_USHORT( net_signature ); // signature of the object that we are dealing with.
5067  GET_DATA( code ); // code of what we are doing.
5068  objp = multi_get_network_object( net_signature );
5069  if ( !objp )
5070  nprintf(("Network", "Couldn't find object for ai update\n"));
5071 
5072  switch( code ) {
5073  case AI_UPDATE_DOCK:
5074  GET_USHORT( other_net_signature );
5075  GET_DATA( docker_index );
5076  GET_DATA( dockee_index );
5077  other_objp = multi_get_network_object( other_net_signature );
5078  if ( !other_objp )
5079  nprintf(("Network", "Couldn't find other object for ai update on dock\n"));
5080 
5081  // if we don't have an object to work with, break out of loop
5082  if ( !objp || !other_objp || (objp->type != OBJ_SHIP) || (other_objp->type != OBJ_SHIP)){
5083  break;
5084  }
5085 
5086  // don't assign the dock indexes, because they're part of the docking ship's goal code... just dock them
5087  // (and besides, we might be docking initially docked ships and we wouldn't have an active goal)
5088  ai_do_objects_docked_stuff( objp, docker_index, other_objp, dockee_index );
5089  break;
5090 
5091  case AI_UPDATE_UNDOCK:
5092  GET_USHORT( other_net_signature );
5093  other_objp = multi_get_network_object( other_net_signature );
5094 
5095  // if we don't have an object to work with, break out of loop
5096  if ( !objp )
5097  break;
5098 
5099  ai_do_objects_undocked_stuff( objp, other_objp );
5100  break;
5101 
5102  case AI_UPDATE_ORDERS:
5103  GET_INT( mode );
5104  GET_INT( submode );
5105  GET_USHORT( other_net_signature );
5106  if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5107  GET_DATA(docker_index);
5108  GET_DATA(dockee_index);
5109  }
5110 
5111  // be sure that we have a ship object!!!
5112  if ( !objp || (objp->type != OBJ_SHIP) )
5113  break;
5114 
5115  // set up the information in the first goal element of the object in question
5116  aip = &Ai_info[Ships[objp->instance].ai_index];
5117  aip->active_goal = 0;
5118  aigp = &aip->goals[aip->active_goal];
5119  aigp->ai_mode = mode;
5120  aigp->ai_submode = submode;
5121 
5122  // for docking, add the docker and dockee index to the active goal
5123  if ( mode & (AI_GOAL_DOCK|AI_GOAL_REARM_REPAIR) ) {
5124  aigp->docker.index = docker_index;
5125  aigp->dockee.index = dockee_index;
5126  aigp->flags |= AIGF_DOCK_INDEXES_VALID;
5127  }
5128 
5129  // get a shipname if we can.
5130  other_objp = multi_get_network_object( other_net_signature );
5131  if ( other_objp && (other_objp->type == OBJ_SHIP) ) {
5132  // get a pointer to the shipname in question. Use the ship_name value in the
5133  // ship. We are only using this for HUD display, so I think that using this
5134  // method will be fine.
5135  aigp->target_name = ai_get_goal_target_name(Ships[other_objp->instance].ship_name, &aigp->target_name_index);
5136 
5137  // special case for destroy subsystem -- get the ai_info pointer to our target ship
5138  // so that we can properly set up what subsystem this ship is attacking.
5139  if ( (mode == AI_GOAL_DESTROY_SUBSYSTEM ) && (submode >= 0) )
5140  aip->targeted_subsys = ship_get_indexed_subsys( &Ships[other_objp->instance], submode);
5141  }
5142 
5143  break;
5144 
5145  default:
5146  Int3(); // this Int3() should be temporary
5147  nprintf(("Network", "Invalid code for ai update: %d\n", code));
5148  break;
5149  }
5150  PACKET_SET_SIZE();
5151 }
5152 
5153 // tell the standalone to move into the MISSION_SYNC_STATE
5154 void send_mission_sync_packet(int mode,int start_campaign)
5155 {
5156  ubyte data[MAX_PACKET_SIZE],is_campaign;
5157  int packet_size = 0;
5158 
5160 
5161  // build the header and add the sync mode (pre or post briefing)
5163  ADD_INT(mode);
5164 
5165  // if this is a campaign game
5166  if(mode == MULTI_SYNC_PRE_BRIEFING){
5168  // add a byte indicating campaign mode
5169  is_campaign = 1;
5170  ADD_DATA(is_campaign);
5171 
5172  // add a byte indicating if we should be starting a campaign or continuing it
5173  is_campaign = (ubyte)start_campaign;
5174  ADD_DATA(is_campaign);
5175 
5176  // add the campaign filename
5178  }
5179  // otherwise if this is a single mission
5180  else {
5181  // add a byte indicating single mission mode
5182  is_campaign = 0;
5183  ADD_DATA(is_campaign);
5184 
5185  // add the mission filename
5187  }
5188  }
5189  multi_io_send_reliable(Net_player, data, packet_size);
5190 }
5191 
5192 // move into the MISSION_SYNC state when this is received
5193 // this packet is sent only from a game host to a standalone
5195 {
5196  int mode;
5197  ubyte campaign_flag;
5198  int offset = HEADER_LENGTH;
5199 
5201 
5202  // if this is a team vs team situation, lock the players send a final team update
5206  }
5207 
5208  // get the sync mode (pre or post briefing)
5209  GET_INT(mode);
5210 
5211  if(mode == MULTI_SYNC_PRE_BRIEFING){
5212  // get the flag indicating if this is a single mission or a campaign mode
5213  GET_DATA(campaign_flag);
5214  if(campaign_flag){
5215  // get the flag indicating whether we should be starting a new campaign
5216  GET_DATA(campaign_flag);
5217 
5218  // get the campaign filename
5220 
5221  // either start a new campaign or continue on to the next mission in the current campaign
5222  if(campaign_flag){
5224  } else {
5226  }
5227  } else {
5228  // make sure we remove the campaign mode flag
5230 
5231  // get the single mission filename
5234  }
5235  }
5236  else if (mode == MULTI_SYNC_POST_BRIEFING) {
5237  // process the initial orders now (moved from post_process_mission()in missionparse)
5240  }
5241  PACKET_SET_SIZE();
5242 
5243  // set the correct mode and m ove into the state
5246 }
5247 
5248 // tell a player to merge his mission stats into his alltime stats
5249 void send_store_stats_packet(int accept)
5250 {
5251  ubyte data[10],val;
5252  int packet_size = 0;
5253 
5255 
5256  // add whether we're accepting or tossing
5257  val = (ubyte)accept;
5258  ADD_DATA(val);
5259 
5260  // if I'm the server, send to everyone, else send to the standalone to be rebroadcasted
5262  multi_io_send_to_all_reliable(data, packet_size);
5263  } else {
5264  multi_io_send_reliable(Net_player, data, packet_size);
5265  }
5266 }
5267 
5269 {
5270  int offset = HEADER_LENGTH;
5271  ubyte accept;
5272 
5273  GET_DATA(accept);
5274  PACKET_SET_SIZE();
5275 
5276  // if I'm the standalone, rebroadcast. Otherwise, if I'm a client, merge my mission stats with my alltime stats
5278  // rebroadcast the packet to all others in the game
5279  nprintf(("Network","Standalone received store stats packet - rebroadcasting..\n"));
5280  multi_io_send_to_all_reliable(data, offset);
5281  } else {
5282  if(accept){
5283  // all players should mark the stats as being accepted in the debriefing
5285 
5286 
5287  } else {
5288  // all players should mark the stats as being "tossed" in the debriefing
5290  }
5291  }
5292 }
5293 
5294 void send_debris_update_packet(object *objp,int code)
5295 {
5297  ubyte val;
5298  int packet_size = 0;
5299 
5301  ADD_USHORT(objp->net_signature);
5302  val = (ubyte) code;
5303  ADD_DATA(val);
5304 
5305  // add any extra relevant data
5306  switch(code){
5307  case DEBRIS_UPDATE_UPDATE:
5308  ADD_VECTOR(objp->pos); // add position
5309  ADD_ORIENT(objp->orient); // add orientation
5310  ADD_VECTOR(objp->phys_info.vel); // add velocity
5311  ADD_VECTOR(objp->phys_info.rotvel); // add rotational velocity
5312  break;
5313  }
5314  multi_io_send_to_all(data, packet_size);
5315 }
5316 
5318 {
5319  u