FS2_Open
Open source remastering of the Freespace 2 engine
multiutil.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 #if defined _WIN32
14 #include <winsock.h>
15 #elif defined SCP_UNIX
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 #include <errno.h>
22 #endif
23 #include <ctype.h>
24 
25 #include "globalincs/pstypes.h"
26 #include "network/multiutil.h"
27 #include "globalincs/linklist.h"
29 #include "hud/hudmessage.h"
30 #include "freespace2/freespace.h"
31 #include "io/key.h"
32 #include "io/timer.h"
33 #include "ship/ship.h"
34 #include "globalincs/alphacolors.h"
35 #include "graphics/font.h"
36 #include "gamesnd/gamesnd.h"
37 #include "playerman/player.h"
38 #include "mission/missionparse.h"
40 #include "network/stand_gui.h"
41 #include "ship/shipfx.h"
42 #include "object/object.h"
43 #include "playerman/managepilot.h"
45 #include "observer/observer.h"
46 #include "mission/missionmessage.h"
47 #include "popup/popup.h"
48 #include "popup/popupdead.h"
49 #include "hud/hudconfig.h"
50 #include "menuui/optionsmenu.h"
51 #include "mission/missionhotkey.h"
52 #include "mission/missiongoals.h"
53 #include "ship/afterburner.h"
54 #include "missionui/chatbox.h"
55 #include "osapi/osregistry.h"
56 #include "hud/hudescort.h"
57 #include "network/multi.h"
58 #include "cmdline/cmdline.h"
59 #include "cfile/cfile.h"
60 #include "cfile/cfilesystem.h"
61 #include "network/multimsgs.h"
62 #include "network/multi_xfer.h"
64 #include "network/multiui.h"
65 #include "network/multi_kick.h"
66 #include "network/multi_data.h"
67 #include "network/multi_voice.h"
68 #include "network/multi_team.h"
69 #include "network/multi_respawn.h"
70 #include "network/multi_ingame.h"
71 #include "network/multi_observer.h"
72 #include "network/multi_pinfo.h"
73 #include "network/multi_endgame.h"
74 #include "network/multi_pmsg.h"
75 #include "network/multi_pause.h"
76 #include "network/multi_log.h"
77 #include "network/multi_rate.h"
78 #include "fs2netd/fs2netd_client.h"
79 #include "parse/parselo.h"
80 #include "debugconsole/console.h"
81 
82 extern int ascii_table[];
83 extern int shifted_ascii_table[];
84 
85 extern int Multi_ping_timestamp;
86 
87 // network object management
88 ushort Next_ship_signature; // next permanent network signature to assign to an object
89 ushort Next_asteroid_signature; // next signature for an asteroid
90 ushort Next_non_perm_signature; // next non-permanent network signature to assign to an object
91 ushort Next_debris_signature; // next debris signature
92 
93 
94 // if a client doesn't receive an update for an object after this many seconds, query server
95 // as to the objects status.
96 #define MULTI_CLIENT_OBJ_TIMEOUT 10
97 #define MAX_SHIPS_PER_QUERY 10
98 
99 
100 // this function assignes the given object with the given signature. If the signature is 0, then we choose
101 // the next signature number from the correct pool. I thought that it might be desireable
102 // to not always have to take the next signature on the list. what_kind is used to assign either a
103 // permanent or non-permanent signature to an object. permanent signatures are used for ships, non_permanent
104 // signatures are used for everything else.
106 {
107  ushort sig;
108 
109  // do limit checking on the permanent and non_permanent signatures. Ships are considered "permanent"
110  // as are debris and asteroids since they don't die very often. It would be vary rare for this
111  // value (the permanent signature) to wrap. For now, this condition is an error condition
112  if ( what_kind == MULTI_SIG_SHIP ) {
115  }
116 
117  sig = Next_ship_signature++;
118 
120  Int3(); // get Allender -- signature stuff wrapped.
122  }
123 
124  // signature stuff for asteroids.
125  } else if ( what_kind == MULTI_SIG_ASTEROID ) {
128  }
129 
130  sig = Next_asteroid_signature++;
132  Int3(); // get Allender -- signature stuff wrapped.
134  }
135 
136  // signatures for debris
137  } else if ( what_kind == MULTI_SIG_DEBRIS ) {
140  }
141 
142  sig = Next_debris_signature++;
144  Int3(); // get Allender -- signature stuff wrapped.
146  }
147 
148  // signature stuff for weapons and other expendable things.
149  } else if ( what_kind == MULTI_SIG_NON_PERMANENT ) {
152  }
153 
154  sig = Next_non_perm_signature++;
157  }
158  } else {
159  Int3(); // get allender - Illegal signature type requested
160  sig = 0;
161  }
162 
163  return sig;
164 }
165 
166 // this function returns the next network signature that will be used for a newly created object
167 // what_kind parameter tells us what kind of signature to get -- permanent or non-permanent
169 {
170  if ( what_kind == MULTI_SIG_SHIP ) {
173  return Next_ship_signature;
174 
175  } else if ( what_kind == MULTI_SIG_DEBRIS ) {
178  return Next_debris_signature;
179 
180  } else if ( what_kind == MULTI_SIG_ASTEROID ) {
184 
185  } else if ( what_kind == MULTI_SIG_NON_PERMANENT ) {
189 
190  } else {
191  Int3(); // get allender
192  return 0;
193  }
194 }
195 
196 // this routine sets the network signature to the given value. Should be called from client only
197 // and is used mainly for firing weapons. what_kind tells us permanent or non-permanent signature
198 void multi_set_network_signature( ushort signature, int what_kind )
199 {
200  Assert( signature != 0 );
201 
202  if ( what_kind == MULTI_SIG_SHIP ) {
203  Assert( (signature >= SHIP_SIG_MIN) && (signature <= SHIP_SIG_MAX) );
204  Next_ship_signature = signature;
205  } else if ( what_kind == MULTI_SIG_DEBRIS ) {
206  Assert( (signature >= DEBRIS_SIG_MIN) && (signature <= DEBRIS_SIG_MAX) );
207  Next_debris_signature = signature;
208  } else if ( what_kind == MULTI_SIG_ASTEROID ) {
209  Assert( (signature >= ASTEROID_SIG_MIN) && (signature <= ASTEROID_SIG_MAX) );
210  Next_asteroid_signature = signature;
211  } else if ( what_kind == MULTI_SIG_NON_PERMANENT ) {
212  Assert( (signature >= NPERM_SIG_MIN) /*&& (signature <= NPERM_SIG_MAX)*/ );
213  Next_non_perm_signature = signature;
214  } else
215  Int3(); // get Allender
216 }
217 
218 // multi_get_network_object() takes a net_signature and tries to locate the object in the object list
219 // with that network signature. Returns NULL if the object cannot be found
220 object *multi_get_network_object( ushort net_signature )
221 {
222  object *objp;
223 
224  if ( net_signature == 0 )
225  return NULL;
226 
227  if(GET_FIRST(&obj_used_list) == NULL)
228  return NULL;
229 
230  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
231  if ( objp->net_signature == net_signature )
232  break;
233 
234  // if not found on used list, check create list
235  if ( objp == END_OF_LIST(&obj_used_list) ) {
236  for ( objp = GET_FIRST(&obj_create_list); objp != END_OF_LIST(&obj_create_list); objp = GET_NEXT(objp) )
237  if ( objp->net_signature == net_signature )
238  break;
239 
240  if ( objp == END_OF_LIST(&obj_create_list) )
241  objp = NULL;
242  }
243 
244  return objp;
245 }
246 
247 
248 // -------------------------------------------------------------------------------------------------
249 // netmisc_calc_checksum() calculates the checksum of a block of memory.
250 //
251 //
252 ushort netmisc_calc_checksum( void * vptr, int len )
253 {
254  ubyte * ptr = (ubyte *)vptr;
255  unsigned int sum1,sum2;
256 
257  sum1 = sum2 = 0;
258 
259  while(len--) {
260  sum1 += *ptr++;
261  if (sum1 >= 255 ) sum1 -= 255;
262  sum2 += sum1;
263  }
264  sum2 %= 255;
265 
266  return (unsigned short)((sum1<<8)+ sum2);
267 }
268 
269 
270 // -------------------------------------------------------------------------------------------------
271 // multi_random_death_word() will return a word from the below list at random.
272 //
273 // Note: Keep words grouped into sections of 10
274 
275 #define NUM_DEATH_WORDS 40
276 
278 {
279  int index;
280 
281  index = rand() % NUM_DEATH_WORDS;
282  switch (index) {
283  case 0:
284  return XSTR("zapped",853);
285  case 1:
286  return XSTR("caulked",854);
287  case 2:
288  return XSTR("killed",855);
289  case 3:
290  return XSTR("waxed",856);
291  case 4:
292  return XSTR("popped",857);
293  case 5:
294  return XSTR("murdered",858);
295  case 6:
296  return XSTR("bludgeoned",859);
297  case 7:
298  return XSTR("destroyed",860);
299  case 8:
300  return XSTR("iced",861);
301  case 9:
302  return XSTR("obliterated",862);
303  case 10:
304  return XSTR("toasted",863);
305  case 11:
306  return XSTR("roasted",864);
307  case 12:
308  return XSTR("turned into anti-matter",865);
309  case 13:
310  return XSTR("killed like a pig",866);
311  case 14:
312  return XSTR("taught a lesson",867);
313  case 15:
314  return XSTR("slaughtered with impunity",868);
315  case 16:
316  return XSTR("spanked like a naughty boy",869);
317  case 17:
318  return XSTR("skunked",870);
319  case 18:
320  return XSTR("beat senseless",871);
321  case 19:
322  return XSTR("shot up",872);
323  case 20:
324  return XSTR("spaced",873);
325  case 21:
326  return XSTR("hosed",874);
327  case 22:
328  return XSTR("capped",875);
329  case 23:
330  return XSTR("beat down",876);
331  case 24:
332  return XSTR("hit wit da shizzo",877);
333  case 25:
334  return XSTR("sk00led",878);
335  case 26:
336  return XSTR("whooped up",879);
337  case 27:
338  return XSTR("brought to the all-you-can-take whoop ass buffet",880);
339  case 28:
340  return XSTR("served up a whoop ass sandwich...hold the mercy",881);
341  case 29:
342  return XSTR("gibbed by Kayser Sozay's rocket",882);
343  case 30:
344  return XSTR("shot down",883);
345  case 31:
346  return XSTR("given early retirement",884);
347  case 32:
348  return XSTR("instructed",885);
349  case 33:
350  return XSTR("eviscerated",886);
351  case 34:
352  return XSTR("pummelled",887);
353  case 35:
354  return XSTR("eradicated",888);
355  case 36:
356  return XSTR("cleansed",889);
357  case 37:
358  return XSTR("perforated",890);
359  case 38:
360  return XSTR("canned",891);
361  case 39:
362  return XSTR("decompressed",892);
363  }
364 
365  return NOX("Error");
366 }
367 
368 // -------------------------------------------------------------------------------------------------
369 // multi_random_chat_start() will return a word from the below list at random.
370 //
371 //
372 
373 #define NUM_CHAT_START_WORDS 8
374 #define MAX_CHAT_PHRASE_LEN 25 // be careful not to exceed (or update if exceeded)
375 
377 {
378  int index;
379 
380  index = rand() % NUM_CHAT_START_WORDS;
381  switch (index) {
382  case 0:
383  return XSTR("says",893);
384  case 1:
385  return XSTR("bleats",894);
386  case 2:
387  return XSTR("opines",895);
388  case 3:
389  return XSTR("postulates",896);
390  case 4:
391  return XSTR("declares",897);
392  case 5:
393  return XSTR("vomits out",898);
394  case 6:
395  return XSTR("whines",899);
396  case 7:
397  return XSTR("barks",900);
398  }
399 
400  return NOX("Error");
401 }
402 
403 // -------------------------------------------------------------------------------------------------
404 // multi_ship_class_lookup() will return the Ship_info[] index for the ship specified as a
405 // parameter.
406 //
407 //
408 
409 int multi_ship_class_lookup(const char* ship_name)
410 {
411  // find the ship_info index for the ship_name
412 
413  int player_ship_class = -1;
414  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
415  if ( !stricmp(it->name, ship_name) ) {
416  player_ship_class = std::distance(Ship_info.cbegin(), it);
417  break;
418  }
419  } // end for
420 
421  return player_ship_class;
422 }
423 
424 // -------------------------------------------------------------------------------------------------
425 // find_player() is called when a packet arrives, and we need to know which net player to update.
426 // The matching is done based on the address and port. Port checking is done in case multiple
427 // instances of FreeSpace are running on the same box.
428 //
429 //
430 
432 {
433  int i;
434 
435  for (i = 0; i < MAX_PLAYERS; i++ ) {
436  if ( !MULTI_CONNECTED(Net_players[i])){
437  continue;
438  }
439  if ( psnet_same( addr, &(Net_players[i].p_info.addr)) ){
440  return i;
441  }
442  }
443 
444  return -1;
445 }
446 
447 // so that we can lookup on the admin port transparently
449 {
450  int i;
451 
452  for (i = 0; i < MAX_PLAYERS; i++ ) {
453  if ( !MULTI_CONNECTED(Net_players[i])){
454  continue;
455  }
456 
457  if ( memcmp(&addr->addr,&Net_players[i].p_info.addr.addr,IP_ADDRESS_LENGTH)== 0){
458  return i;
459  }
460  }
461 
462  return -1;
463 }
464 
465 int find_player_id(short player_id)
466 {
467  int i;
468  for (i = 0; i < MAX_PLAYERS; i++ ) {
469  if ( !MULTI_CONNECTED(Net_players[i])){
470  continue;
471  }
472  if(player_id == Net_players[i].player_id){
473  return i;
474  }
475  }
476 
477  // couldn't find the player
478  return -1;
479 }
480 
481 // note this is only valid to do on a server!
483 {
484  int i;
485  for (i = 0; i < MAX_PLAYERS; i++ ) {
486  if ( !MULTI_CONNECTED(Net_players[i])){
487  continue;
488  }
489  if(sock == Net_players[i].reliable_socket){
490  return i;
491  }
492  }
493 
494  // couldn't find the player
495  return -1;
496 }
497 
498 // multi_find_player_by_object returns a player num (reference by Net_players[x]) when given a object *.
499 // used to find netplayers in game when only the object is known
501 {
502  int i, objnum;
503 
504  objnum = OBJ_INDEX(objp);
505  for (i = 0; i < MAX_PLAYERS; i++ ) {
506  if ( !MULTI_CONNECTED(Net_players[i])){
507  continue;
508  }
509  if ( objnum == Net_players[i].m_player->objnum ){
510  return i;
511  }
512  }
513 
514  // return -1 if the object is not found -- this is a bad situation, but we will handle it in higher
515  // level code
516  return -1;
517 }
518 
519 // returns a player num based upon player object signature
520 int multi_find_player_by_signature( int signature )
521 {
522  int idx;
523 
524  for(idx=0;idx<MAX_PLAYERS;idx++){
525  // compare against each player's object signature
526  if(MULTI_CONNECTED(Net_players[idx]) && (Objects[Net_players[idx].m_player->objnum].signature == signature)){
527  // found the player
528  return idx;
529  }
530  }
531 
532  // didn't find the player
533  return -1;
534 }
535 
536 // returns a player num based upon object net signature
538 {
539  int idx;
540 
541  for(idx=0;idx<MAX_PLAYERS;idx++){
542  // compare against each player's object signature
543  if(MULTI_CONNECTED(Net_players[idx]) && (Objects[Net_players[idx].m_player->objnum].net_signature == net_signature)){
544  // found the player
545  return idx;
546  }
547  }
548 
549  // didn't find the player
550  return -1;
551 }
552 
553 // returns a player num based upon it's parse_object unlike the above functions it can be used on respawning players
555 {
556  int idx;
557 
558  for(idx=0;idx<MAX_PLAYERS;idx++){
559  // compare against each player's object signature
560  if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].p_info.p_objp == p_objp) ){
561  // found the player
562  return idx;
563  }
564  }
565 
566  // didn't find the player
567  return -1;
568 }
569 
570 int multi_find_player_by_ship_name(const char *ship_name, bool inc_respawning)
571 {
572  int idx;
573  p_object *p_objp;
574 
575  // bogus
576  if(ship_name == NULL){
577  return -1;
578  }
579 
580  for(idx=0; idx<MAX_PLAYERS; idx++){
581  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player != NULL) && (Net_players[idx].m_player->objnum >= 0) && (Net_players[idx].m_player->objnum < MAX_OBJECTS) && (Objects[Net_players[idx].m_player->objnum].type == OBJ_SHIP) &&
582  (Objects[Net_players[idx].m_player->objnum].instance >= 0) && (Objects[Net_players[idx].m_player->objnum].instance < MAX_SHIPS) && !stricmp(ship_name, Ships[Objects[Net_players[idx].m_player->objnum].instance].ship_name) ){
583  return idx;
584  }
585  }
586 
587  if (inc_respawning) {
588  p_objp = mission_parse_get_arrival_ship(ship_name);
589  idx = multi_find_player_by_parse_object(p_objp);
590 
591  if((idx >= 0) && (idx < MAX_PLAYERS)){
592  return idx;
593  }
594  }
595  // didn't find the player
596  return -1;
597 }
598 
599 int multi_get_player_ship(int np_index)
600 {
601  // bogus
602  if((np_index < 0) || (np_index >= MAX_PLAYERS)){
603  return -1;
604  }
605 
606  // cool?
607  if(MULTI_CONNECTED(Net_players[np_index]) && !MULTI_OBSERVER(Net_players[np_index]) && !MULTI_STANDALONE(Net_players[np_index]) &&
608  (Net_players[np_index].m_player != NULL) && (Net_players[np_index].m_player->objnum >= 0) && (Net_players[np_index].m_player->objnum < MAX_OBJECTS) && (Objects[Net_players[np_index].m_player->objnum].type == OBJ_SHIP) &&
610 
611  return Objects[Net_players[np_index].m_player->objnum].instance;
612  }
613 
614  // nope
615  return -1;
616 }
617 
618 // find_open_netplayer_slot() attempts to find a free slot in the Net_players structure for a new player.
619 // it returns -1 if there is no new slot, and the slot number if one is found
620 // NOTE : this attempts to preserve a player object as long as possible for him to come back to
622 {
623  int i;
624  int found_first;
625 
626  found_first = -1;
627  for (i = 0; i < MAX_PLAYERS; i++)
628  if ( !MULTI_CONNECTED(Net_players[i]) ){
629  if(found_first == -1) {
630  found_first = i;
631  break;
632  }
633  }
634 
635  if(i == MAX_PLAYERS){
636  if(found_first == -1)
637  return -1;
638  else
639  return found_first;
640  }
641 
642  return i;
643 }
644 
645 // find_open_player_slot() attempts to find an open player array slot. The 0th element of the array
646 // should always be taken by the console player's pilot. All other slots are up for grab though.
648 {
649  int i;
650 
651  for (i = 0; i < MAX_PLAYERS; i++)
653  break;
654 
655  if ( i == MAX_PLAYERS )
656  return -1;
657 
658  return i;
659 }
660 
661 // stuff_netplayer_info stuffs information into the given Net_player structure. It is called when
662 // a new person is entering the game. The state of the Net_player is set to it's basic starting
663 // state
664 void stuff_netplayer_info( net_player *nplayer, net_addr *addr, int ship_class, player *pplayer )
665 {
666  nplayer->p_info.addr = *addr;
667  nplayer->flags |= NETINFO_FLAG_CONNECTED;
668  nplayer->state = NETPLAYER_STATE_JOINING;
669  nplayer->p_info.ship_class = ship_class;
670  nplayer->m_player = pplayer;
671  nplayer->p_info.options.obj_update_level = Cmdline_objupd; // Set the update to the specified value
672 
673  // if setting up my net flags, then set the flag to say I can do networking.
674  if ( nplayer == Net_player ){
675  nplayer->flags |= NETINFO_FLAG_DO_NETWORKING;
676  }
677 }
678 
679 // multi_assign_player_ship takes a Net_player index and an object * and assigned that player to
680 // that object
681 void multi_assign_player_ship( int net_player_num, object *objp,int ship_class )
682 {
683  ship *shipp;
684  int idx;
685 
686  Assert ( MULTI_CONNECTED(Net_players[net_player_num]) );
687 
688  shipp = &Ships[objp->instance];
689 
690  Net_players[net_player_num].m_player->objnum = OBJ_INDEX(objp);
691  Net_players[net_player_num].p_info.ship_class = ship_class;
692 
693  // check to see if we are assigning my player -- if so, then set Player_ship and Player_ai
694  if ( Net_player == &Net_players[net_player_num] ) {
695  Player_obj = objp;
696  Player_ship = shipp;
698  }
699 
700  // find the parse object for this ship. Also, set the wingman status stuff so wingman status gauge
701  // works properly.
703  Assert( Net_players[net_player_num].p_info.p_objp != NULL ); // get allender -- ship should be on list
704 
705  // game server and this client need to initialize this information so object updating
706  // works properly.
707  if ( MULTIPLAYER_MASTER || (Net_player == &Net_players[net_player_num]) ) {
708  Net_players[net_player_num].s_info.eye_pos = objp->pos;
709  Net_players[net_player_num].s_info.eye_orient = objp->orient;
710  }
711 
712  // zero update info
713  for(idx=0; idx<MAX_PLAYERS; idx++){
714  shipp->np_updates[idx].orient_chksum = 0;
715  shipp->np_updates[idx].pos_chksum = 0;
716  shipp->np_updates[idx].seq = 0;
717  shipp->np_updates[idx].status_update_stamp = -1;
718  shipp->np_updates[idx].subsys_update_stamp = -1;
719  shipp->np_updates[idx].update_stamp = -1;
720  }
721 }
722 
723 // -------------------------------------------------------------------------------------------------
724 // create_player() is called when a net player needs to be instantiated. The ship that is created
725 // depends on the parameter ship_class. Note that if ship_class is invalid, the ship default_player_ship
726 // is used. Returns 1 on success, 0 otherwise
727 
728 int multi_create_player( int net_player_num, player *pl, const char* name, net_addr* addr, int ship_class, short id)
729 {
730  int player_ship_class = ship_class;
731  int current_player_count;
732 
733  Assert ( net_player_num < MAX_PLAYERS ); // probably shoudln't be able to even get into this routine if no room
734 
735  // blast _any_ old data
736  memset(&Net_players[net_player_num],0,sizeof(net_player));
737 
738  // get the current # of players
739  current_player_count = multi_num_players();
740 
741  // DOH!!! The lack of this caused many bugs.
742  Net_players[net_player_num].flags = (NETINFO_FLAG_DO_NETWORKING);
743 
744  if ( ship_class == -1 ) {
745  nprintf(("Network","Network ==> ship class is -1, creating a default ship for multiplayer\n"));
746 
747  // find the ship that matches the string stored in default_player_ship
748 
749  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
750  if ( !stricmp(it->name, default_player_ship) ) {
751  player_ship_class = std::distance(Ship_info.cbegin(), it);
752  break;
753  }
754  }
755 
756  if (player_ship_class == -1) // if ship_class is -1 (as the condition to enter this branch at all means), then player_ship_class is initialized to -1 as well.
757  {
758  if(!Ship_info.empty())
759  {
760  player_ship_class = 0;
761  Warning(LOCATION, "Invalid default player ship specified in ship tables. Setting to %s", Ship_info[player_ship_class].name);
762  }
763  else
764  {
765  Error(LOCATION, "No ships have been loaded, but we are attempting to set a ship!!");
766  }
767  }
768  }
769 
770  if ( player_ship_class >= static_cast<int>(Ship_info.size()) ) {
771  nprintf(("Network","Network ==> Ship class was %d Creating a default ship for multiplayer\n", player_ship_class));
772  player_ship_class = multi_ship_class_lookup(default_player_ship);
773  }
774 
775  // blast the old player data
776  pl->reset();
777 
778  // set up the net_player structure
779  stuff_netplayer_info( &Net_players[net_player_num], addr, player_ship_class, pl ); Net_players[net_player_num].s_info.num_last_buttons = 0;
780 
781  // Net_players[net_player_num].respawn_count = 0;
783  Net_players[net_player_num].reliable_socket = INVALID_SOCKET;
784  Net_players[net_player_num].s_info.kick_timestamp = -1;
785  Net_players[net_player_num].s_info.voice_token_timestamp = -1;
786  Net_players[net_player_num].s_info.tracker_security_last = -1;
787  Net_players[net_player_num].s_info.target_objnum = -1;
788  Net_players[net_player_num].s_info.accum_buttons = 0;
789 
790  // zero out this players ping times data
791  multi_ping_reset(&Net_players[net_player_num].s_info.ping);
792 
793  // zero out his object update and control info sequencing data
794  Net_players[net_player_num].client_cinfo_seq = 0;
795  Net_players[net_player_num].client_server_seq = 0;
796 
797  // timestamp his last_full_update_time
798  Net_players[net_player_num].s_info.last_full_update_time = timestamp(0);
799 
800  // nil his file xfer handle
801  Net_players[net_player_num].s_info.xfer_handle = -1;
802 
803  // nil his data rate timestamp stuff
804  Net_players[net_player_num].s_info.rate_stamp = -1;
805  Net_players[net_player_num].s_info.rate_bytes = 0;
806 
807  // nil packet buffer stuff
808  Net_players[net_player_num].s_info.unreliable_buffer_size = 0;
809  Net_players[net_player_num].s_info.reliable_buffer_size = 0;
810 
811  // various ack handles
812  strcpy_s(pl->callsign, name);
813  pilot_set_short_callsign(pl, SHORT_CALLSIGN_PIXEL_W); // calculate the short callsign
815  pl->objnum = -1;
816  pl->insignia_texture = -1;
817 
818  // if we're the standalone server and this is the first guy to join, mark him as the host
819  // and give him all host priveleges
820  if ( (Game_mode & GM_STANDALONE_SERVER) && (current_player_count == 0) ) {
821  Net_players[net_player_num].flags |= NETINFO_FLAG_GAME_HOST;
822  }
823 
824  Net_players[net_player_num].player_id = id;
825 
827  Net_player->sv_last_pl = -1;
829  Net_player->cl_last_pl = -1;
830 
831  // add to the escort list
832  if(MULTI_IN_MISSION){
834  }
835 
836  return 1;
837 }
838 
839 // next function makes a player object an ai object (also decrementing the num_players in the
840 // netgame). It appropiately sets the object flags and other interesting AI information which
841 // ought to get set in order to make this new ai object behave correctly.
842 void multi_make_player_ai( object *pobj )
843 {
844 
845  Assert ( pobj != NULL );
846 
847  if ( pobj->type != OBJ_SHIP )
848  return;
849 
850  pobj->flags &= ~(OF_PLAYER_SHIP);
851  obj_set_flags( pobj, pobj->flags | OF_COULD_BE_PLAYER );
852  obj_set_flags( pobj, pobj->flags & ~(OF_INVULNERABLE)); // Newly respawned players will still be invulnerable
853 
854  // target_objnum must be -1 or else new AI ship will fire on whatever this player
855  // had targeted.
856  set_target_objnum( &(Ai_info[Ships[pobj->instance].ai_index]), -1 );
857 
858 }
859 
860 // delete_player takes an index into the Net_players array to delete. Deletion of a player might happen
861 // because of the player leaving the game on his own, or no net activity from the player after X seconds
862 void delete_player(int player_num,int kicked_reason)
863 {
864  char notify_string[256] = "";
865  int idx;
866 
867  if(!MULTI_CONNECTED(Net_players[player_num])){
868  return;
869  }
870 
871  // NETLOG
872  ml_printf(NOX("Deleting player %s"), Net_players[player_num].m_player->callsign);
873 
874  psnet_rel_close_socket( &(Net_players[player_num].reliable_socket) ); // close out the reliable socket
875 
876  // if this guy was ingame joining, the remove my netgame flag so others may join
877  if ( Net_players[player_num].flags & NETINFO_FLAG_INGAME_JOIN ) {
880  }
881 
882  Net_players[player_num].flags &= ~NETINFO_FLAG_CONNECTED; // person not connected anymore
883  Net_players[player_num].m_player->flags &= ~(PLAYER_FLAGS_STRUCTURE_IN_USE); // free up his player structure
884 
885  Net_players[player_num].s_info.reliable_connect_time = -1;
886 
887  // add to the escort list
888  hud_escort_remove_player(Net_players[player_num].player_id);
889 
890  // is this guy the server
891  if(Net_players[player_num].flags & NETINFO_FLAG_AM_MASTER){
892  // if the server leaves in the debriefing state, we should still wait until the player selects accept before we quit
895  }
896  }
897  // if he was just the host
898  else if(Net_players[player_num].flags & NETINFO_FLAG_GAME_HOST){
899  Net_players[player_num].flags &= ~(NETINFO_FLAG_GAME_HOST);
900 
901  // am I the server
902  if ( (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) ) {
903  // are we a standalone server and in a mission?
905  // choose a new host
906  int found_new_host = 0;
907  for(idx=0; idx<MAX_PLAYERS; idx++){
909  // make this guy the host
911 
912  // send a packet
913  send_host_captain_change_packet(Net_players[idx].player_id, 0);
914 
915  found_new_host = 1;
916  break;
917  }
918  }
919  // end the game
920  if(!found_new_host){
922  }
923  } else {
925  }
926  }
927  }
928 
929  // if we're the server of the game, notify everyone else that this guy has left
930  // if he's marked as being kicked, then other players know about it already, so don't send again
931  if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
932  if(Net_players[player_num].flags & NETINFO_FLAG_KICKED){
933  char str[512];
934  memset(str, 0, 512);
935  multi_kick_get_text(&Net_players[player_num], Net_players[player_num].s_info.kick_reason, str);
936  multi_display_chat_msg(str, player_num, 0);
937  } else {
938  send_leave_game_packet(Net_players[player_num].player_id, kicked_reason);
939  }
940  }
941 
942  // if this guy is an observer, we have to make sure we delete his observer object (only if we're the server however)
943  if( (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_players[player_num].flags & NETINFO_FLAG_OBSERVER) ) {
944  if ( Net_players[player_num].m_player->objnum != -1 ){
945  obj_delete(Net_players[player_num].m_player->objnum); // maybe change this to set flag instead
946  }
947  } else {
948  // otherwise mark it so that he can return to it later if possible
949  if ( (Net_players[player_num].m_player->objnum >= 0) && (Net_players[player_num].m_player->objnum < MAX_OBJECTS) && (Objects[Net_players[player_num].m_player->objnum].type == OBJ_SHIP) && (Objects[Net_players[player_num].m_player->objnum].instance >= 0) && (Objects[Net_players[player_num].m_player->objnum].instance < MAX_SHIPS)) {
950  multi_make_player_ai( &Objects[Net_players[player_num].m_player->objnum] );
951  } else {
953  }
954  }
955 
956  // if we're in the team select, and we're the host, we have to make sure all team select data is correctly updated
957  // MWA 7/28/98. Don't do this for a standalone server. Since he doesn't go through the team selection
958  // screens, his data structures are not 100% accurate. Doing so on a standalone resulted in the wrong
959  // ships getting marked as COULD_BE_PLAYER. On the standalone, these flags will get properly set
960  // in the multi_make_player_ai code above.
963  }
964 
967  }
968 
969  // handle any specific dropping conditions
970  if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
972  }
973  multi_data_handle_drop(player_num);
974 
975  // tell the pinfo popup that a player has left
976  multi_pinfo_notify_drop(&Net_players[player_num]);
977 
978  // tell the datarate stuff that the player has dropped
979  multi_rate_reset(player_num);
980 
981  // display a message that this guy has left
982  if(*Net_players[player_num].m_player->callsign){
983  sprintf(notify_string,XSTR("<%s has left>",901),Net_players[player_num].m_player->callsign);
984  multi_display_chat_msg(notify_string,0,0);
985  }
986 
987  // standalone gui type stuff
988  if (Game_mode & GM_STANDALONE_SERVER) {
989  std_remove_player(&Net_players[player_num]);
991  }
992 
993  // blast this memory clean
994  memset(&Net_players[player_num], 0, sizeof(net_player));
996 
998  Multi_client_update_times[player_num] = -1;
999 }
1000 
1001 #define INACTIVE_LIMIT_NORMAL (15 * F1_0)
1002 #define INACTIVE_LIMIT_WAIT (20 * F1_0)
1003 
1004 // -------------------------------------------------------------------------------------------------
1005 // multi_cull_zombies() will check if there has been any net players or observers that have been inactive for
1006 // INACTIVE_LIMIT milliseconds since last check. If so, they are taken out of the net game.
1007 //
1008 //
1009 
1011 {
1012 #if 0
1013  fix current_time;
1014  int inactive_limit;
1015  int i;
1016 
1017  if(gameseq_get_state() == GS_STATE_MULTI_WAIT)
1018  inactive_limit = INACTIVE_LIMIT_WAIT;
1019  else
1020  inactive_limit = INACTIVE_LIMIT_NORMAL;
1021 
1022  current_time = timer_get_fixed_seconds();
1023 
1024  for (i = 0; i < MAX_PLAYERS; i++) {
1025  if ( !MULTI_CONNECTED(&Net_players[i])){
1026  continue;
1027  }
1028 
1029  // server will(should) cull out players based on their sockets dying.
1030  if ( Net_players[i].flags & NETINFO_FLAG_MASTER ){
1031  continue;
1032  }
1033 
1034  if ( (current_time - Net_players[i].last_heard_time) > inactive_limit) {
1035  HUD_printf(XSTR("Dumping %s after prolonged inactivity",902),Net_players[i].m_player->callsign);
1036  nprintf(("Network", "Assuming %s is a zombie, removing from game\n", Net_players[i].m_player->callsign));
1037 
1038  multi_kick_player(i,0);
1039  }
1040  }
1041 #endif
1042 }
1043 
1044 // -------------------------------------------------------------------------------------------------
1045 // fill_net_addr() calculates the checksum of a block of memory.
1046 //
1047 //
1048 
1050 {
1051  Assert(addr != NULL);
1052  Assert(address != NULL);
1053 
1054  addr->type = Multi_options_g.protocol;
1055  memset( addr->addr, 0x00, 6);
1056  memcpy( addr->addr, address, ADDRESS_LENGTH);
1057  addr->port = port;
1058 }
1059 
1060 
1061 
1062 // -------------------------------------------------------------------------------------------------
1063 // get_text_address()
1064 //
1065 //
1066 
1067 char* get_text_address( char * text, ubyte * address )
1068 {
1069 
1070  in_addr temp_addr;
1071 
1072  switch ( Multi_options_g.protocol ) {
1073  case NET_TCP:
1074  memcpy(&temp_addr.s_addr, address, 4);
1075  strcpy( text, inet_ntoa(temp_addr) );
1076  break;
1077 
1078  default:
1079  Assert(0);
1080  break;
1081 
1082  } // end switch
1083 
1084  return text;
1085 }
1086 
1087 // non-16byte version of matrix packing
1088 // return size of packed matrix
1090 {
1091  data[16] = 0;
1092  float x1, y1, x2, y2;
1093 
1094  if(m->vec.rvec.xyz.z < 0) data[16] |= (1<<0); // X
1095  if(m->vec.uvec.xyz.z < 0) data[16] |= (1<<1); // Y
1096  if(m->vec.fvec.xyz.z < 0) data[16] |= (1<<2); // V
1097  if(m->vec.fvec.xyz.x < 0) data[16] |= (1<<3); // Z
1098  if(m->vec.fvec.xyz.y < 0) data[16] |= (1<<4); // W
1099 
1100  x1 = INTEL_FLOAT(&m->vec.rvec.xyz.x);
1101  y1 = INTEL_FLOAT(&m->vec.rvec.xyz.y);
1102  x2 = INTEL_FLOAT(&m->vec.uvec.xyz.x);
1103  y2 = INTEL_FLOAT(&m->vec.uvec.xyz.y);
1104 
1105  memcpy(&data[0], &x1, 4); // a
1106  memcpy(&data[4], &y1, 4); // b
1107  memcpy(&data[8], &x2, 4); // c
1108  memcpy(&data[12], &y2, 4); // d
1109 }
1110 
1111 // return bytes processed
1112 // non-16 byte version of unpack matrix code
1114 {
1115  float x1, y1, x2, y2;
1116 
1117  memcpy(&x1, &data[0], 4);
1118  memcpy(&y1, &data[4], 4);
1119  memcpy(&x2, &data[8], 4);
1120  memcpy(&y2, &data[12],4);
1121 
1122  m->vec.rvec.xyz.x = INTEL_FLOAT(&x1);
1123  m->vec.rvec.xyz.y = INTEL_FLOAT(&y1);
1124  m->vec.uvec.xyz.x = INTEL_FLOAT(&x2);
1125  m->vec.uvec.xyz.y = INTEL_FLOAT(&y2);
1126 
1127  m->vec.rvec.xyz.z = fl_sqrt(fl_abs(1 - (m->vec.rvec.xyz.x * m->vec.rvec.xyz.x) - (m->vec.rvec.xyz.y * m->vec.rvec.xyz.y))); // X
1128  m->vec.uvec.xyz.z = fl_sqrt(fl_abs(1 - (m->vec.uvec.xyz.x * m->vec.uvec.xyz.x) - (m->vec.uvec.xyz.y * m->vec.uvec.xyz.y))); // Y
1129  m->vec.fvec.xyz.z = fl_sqrt(fl_abs(1 - (m->vec.rvec.xyz.z * m->vec.rvec.xyz.z) - (m->vec.uvec.xyz.z * m->vec.uvec.xyz.z))); // V
1130  m->vec.fvec.xyz.x = fl_sqrt(fl_abs(1 - (m->vec.rvec.xyz.x * m->vec.rvec.xyz.x) - (m->vec.uvec.xyz.x * m->vec.uvec.xyz.x))); // Z
1131  m->vec.fvec.xyz.y = fl_sqrt(fl_abs(1 - (m->vec.rvec.xyz.y * m->vec.rvec.xyz.y) - (m->vec.uvec.xyz.y * m->vec.uvec.xyz.y))); // W
1132 
1133  m->vec.rvec.xyz.z *= (data[16] & (1<<0)) ? -1.0f : 1.0f;
1134  m->vec.uvec.xyz.z *= (data[16] & (1<<1)) ? -1.0f : 1.0f;
1135  m->vec.fvec.xyz.z *= (data[16] & (1<<2)) ? -1.0f : 1.0f;
1136  m->vec.fvec.xyz.x *= (data[16] & (1<<3)) ? -1.0f : 1.0f;
1137  m->vec.fvec.xyz.y *= (data[16] & (1<<4)) ? -1.0f : 1.0f;
1138 }
1139 
1141 {
1142  ship_obj *moveup;
1143 
1144  moveup = GET_FIRST(&Ship_obj_list);
1145  while(moveup!=END_OF_LIST(&Ship_obj_list)){
1146  // do all _necessary_ ship warp in (arrival) processing
1147  if ( Ships[Objects[moveup->objnum].instance].flags & SF_ARRIVING )
1148  shipfx_warpin_frame( &Objects[moveup->objnum], frame_time );
1149  moveup = GET_NEXT(moveup);
1150  }
1151 }
1152 
1153 // ------------------------------------------------------------------------------------
1154 // ship status change stuff
1155 
1156 int lookup_ship_status(net_player *p,int unique_id,int remove)
1157 {
1158  int idx;
1159 
1160  for(idx=0;idx<p->s_info.num_last_buttons;idx++){
1161  if(p->s_info.last_buttons_id[idx] == unique_id){
1162  if(remove){
1163  remove_ship_status_item(p,idx);
1164  p->s_info.num_last_buttons--;
1165  }
1166  return 1;
1167  }
1168  }
1169  return 0;
1170 }
1171 
1173 {
1174  int idx;
1175  for(idx=id;idx<BUTTON_INFO_SAVE_COUNT-1;idx++){
1176  p->s_info.last_buttons[idx] = p->s_info.last_buttons[idx+1];
1179  }
1180 }
1181 
1182 //
1184 {
1185  int lookup,idx;
1186  fix earliest;
1187 
1188  // if the list is full, put it in the oldest slot since it's probably a lost packet anyway
1191  p->s_info.last_buttons_id[p->s_info.num_last_buttons] = unique_id;
1193  p->s_info.num_last_buttons++;
1194  } else {
1195  earliest = 0;
1196  lookup = -1;
1197  for(idx=0;idx<BUTTON_INFO_SAVE_COUNT;idx++){
1198  if((p->s_info.last_buttons_time[idx] < earliest) || (earliest == 0)){
1199  earliest = p->s_info.last_buttons_time[idx];
1200  lookup = idx;
1201  }
1202  }
1203  if(lookup != -1){
1204  p->s_info.last_buttons[lookup] = *bi;
1205  p->s_info.last_buttons_id[lookup] = unique_id;
1207  }
1208  }
1209 }
1210 
1211 extern int button_function_critical(int n,net_player *p = NULL);
1213 {
1214  int i, j;
1216  for ( i = 0; i < NUM_BUTTON_FIELDS; i++ ) {
1217  if ( bi->status[i] == 0 )
1218  continue;
1219  // at least one bit is set in the status integer
1220  for ( j = 0; j < 32; j++ ) {
1221 
1222  // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit
1223  if ( bi->status[i] & (1<<j) ) {
1224  if(locally){
1225  if(button_function_critical(32*i + j,NULL)) // will apply to this console
1226  bi->status[i] &= ~(1<<j);
1227  } else {
1228  if(button_function_critical(32*i + j,p)) // will only apply to a net-player
1229  bi->status[i] &= ~(1<<j);
1230  }
1231  }
1232  }
1233  }
1235 }
1236 
1237 // send 10x a second MAX
1238 #define MULTI_SHIP_STATUS_TIME 350
1241 
1243 {
1244  int idx;
1245  button_info *bi = &Player->bi;
1246 
1247  // strip out noncritical button presses
1249 
1250  // xor all fields into the accum button info
1251  for(idx=0; idx<NUM_BUTTON_FIELDS; idx++){
1252  Multi_ship_status_bi.status[idx] |= bi->status[idx];
1253  }
1254 
1255  // check timestamp
1257  int should_send = 0;
1258  for(idx=0; idx<NUM_BUTTON_FIELDS; idx++){
1259  // we have at least something to send
1260  if(Multi_ship_status_bi.status[idx] != 0){
1261  should_send = 1;
1262  }
1263  }
1264 
1265  // do we have something to send
1266  if(should_send){
1267  // add_net_button_info(Net_player, &Multi_ship_status_bi, Multi_button_info_id);
1268  send_ship_status_packet(Net_player, &Multi_ship_status_bi, Multi_button_info_id++);
1269  }
1270 
1271  // zero it out
1272  memset(&Multi_ship_status_bi, 0, sizeof(button_info));
1273 
1274  // reset timestamp
1276  }
1277 }
1278 
1280 {
1281  /*
1282  int idx;
1283  Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1284  for(idx=0;idx<MAX_PLAYERS;idx++){
1285  if((Net_players[idx].flags & NETINFO_FLAG_CONNECTED) && !psnet_same(&My_addr,&Net_players[idx].addr) && !(Net_players[idx].flags & NETINFO_FLAG_OBSERVER))
1286  send_subsys_update_packet(&Net_players[idx]);
1287  }
1288  */
1289 }
1290 
1291 int multi_find_player_by_callsign(const char *callsign)
1292 {
1293  int idx;
1294  for(idx=0;idx<MAX_PLAYERS;idx++){
1295  if(MULTI_CONNECTED(Net_players[idx]) && (strcmp(callsign,Net_players[idx].m_player->callsign)==0)){
1296  return idx;
1297  }
1298  }
1299 
1300  return -1;
1301 }
1302 
1303 // if Game_current_mission_filename is a builtin multiplayer mission
1305 {
1306  // int idx;
1307  char name[512];
1308 
1309  // get the full filename
1310  memset(name,0,512);
1313 
1314  // if this mission is builtin
1315  if(game_find_builtin_mission(name) != NULL){
1316  return 1;
1317  }
1318 
1319  // not builtin
1320  return 0;
1321 }
1322 
1323 // verify that the player has a valid mission file and do 1 of 3 things
1324 void server_verify_filesig(short player_id, ushort sum_sig, int length_sig)
1325 {
1326  net_player *pl;
1327  int player;
1328  int ok;
1329  int is_builtin;
1330 
1331  player = find_player_id(player_id);
1332  Assert(player >= 0);
1333  if(player < 0){
1334  return;
1335  }
1336  pl = &Net_players[player];
1337 
1338  // if the current mission is a builtin mission, check stuff out
1339  is_builtin = multi_is_builtin_mission();
1340 
1341  if(is_builtin){
1342  // if the player doesn't have it, kick him
1343  if((sum_sig == 0xffff) && (length_sig == -1)){
1345  } else {
1347  }
1348 
1349  // done
1350  return;
1351  }
1352 
1353  if( (length_sig != Multi_current_file_length) || (sum_sig != Multi_current_file_checksum)){
1354  ok = 0;
1355  } else {
1356  ok = 1;
1357  }
1358 
1359  // in an ingame join situation
1360  if(pl->flags & NETINFO_FLAG_INGAME_JOIN){
1361  if(!ok){
1362  // if the netgame settings allow in-mission file xfers
1366  }
1367  // otherwise send him a nak and tell him to get away
1368  else {
1370  }
1371  } else {
1373  }
1374  }
1375  // in a normal join situation
1376  else {
1377  // if the file does not check out, send it to him
1378  if(!ok){
1380  }
1381  // otherwise mark him as having a valid mission
1382  else {
1384  }
1385  }
1386 }
1387 
1388 // check to see if every client has NETINFO_FLAG_MISSION_OK
1390 {
1391  int idx;
1392  int ok = 1;
1393 
1394  for(idx=0;idx<MAX_PLAYERS;idx++){
1396  ok = 0;
1397  break;
1398  }
1399  }
1400 
1401  return ok;
1402 }
1403 
1405 {
1406  ship_obj *moveup;
1407 
1408  moveup = GET_FIRST(&Ship_obj_list);
1409  while(moveup != END_OF_LIST(&Ship_obj_list)){
1410  if(Objects[moveup->objnum].flags & OF_PLAYER_SHIP){
1411  Objects[moveup->objnum].flags &= ~(OF_PLAYER_SHIP);
1413  }
1414  moveup = GET_NEXT(moveup);
1415  }
1416 }
1417 
1418 // broadcast alltime stats to everyone in the game
1419 void multi_broadcast_stats(int stats_code)
1420 {
1421  int idx;
1422 
1423  // broadcast everyone's stats to everyone else
1424  for(idx=0;idx<MAX_PLAYERS;idx++){
1426  send_player_stats_block_packet(&Net_players[idx], stats_code);
1427  }
1428  }
1429 }
1430 
1431 // check to see if all players other than the local player are in a given NETPLAYER_ state
1432 // this is _EXTREMELY_ useful when doing network sequencing with the reliable sockets
1433 int multi_netplayer_state_check(int state,int ignore_standalone)
1434 {
1435  int idx;
1436  for(idx=0;idx<MAX_PLAYERS;idx++){
1438  if(ignore_standalone && ((Net_players[idx].flags & NETINFO_FLAG_AM_MASTER) && !(Net_players[idx].flags & NETINFO_FLAG_GAME_HOST)) ){
1439  continue;
1440  }
1441 
1442  if(Net_players[idx].state != state){
1443  return 0;
1444  }
1445  }
1446  }
1447  return 1;
1448 }
1449 
1450 int multi_netplayer_state_check2(int state, int state2, int ignore_standalone)
1451 {
1452  int idx;
1453  for(idx=0;idx<MAX_PLAYERS;idx++){
1455  if(ignore_standalone && ((Net_players[idx].flags & NETINFO_FLAG_AM_MASTER) && !(Net_players[idx].flags & NETINFO_FLAG_GAME_HOST)) ){
1456  continue;
1457  }
1458 
1459  if((Net_players[idx].state != state) && (Net_players[idx].state != state2)){
1460  return 0;
1461  }
1462  }
1463  }
1464  return 1;
1465 }
1466 
1467 int multi_netplayer_state_check3(int state, int state2, int state3, int ignore_standalone)
1468 {
1469  int idx;
1470  for(idx=0;idx<MAX_PLAYERS;idx++){
1472  if(ignore_standalone && ((Net_players[idx].flags & NETINFO_FLAG_AM_MASTER) && !(Net_players[idx].flags & NETINFO_FLAG_GAME_HOST)) ){
1473  continue;
1474  }
1475 
1476  if((Net_players[idx].state != state) && (Net_players[idx].state != state2) && (Net_players[idx].state != state3)){
1477  return 0;
1478  }
1479  }
1480  }
1481  return 1;
1482 }
1483 
1484 // check to see if all players other than the local player are in a given NETPLAYER_ state
1485 // this is _EXTREMELY_ useful when doing network sequencing with the reliable sockets
1486 int multi_netplayer_flag_check(int flags,int ignore_standalone)
1487 {
1488  int idx;
1489  for(idx=0;idx<MAX_PLAYERS;idx++){
1491  if(ignore_standalone && ((Net_players[idx].flags & NETINFO_FLAG_AM_MASTER) && !(Net_players[idx].flags & NETINFO_FLAG_GAME_HOST)) ){
1492  continue;
1493  }
1494 
1495  if(!(Net_players[idx].flags & flags)){
1496  return 0;
1497  }
1498  }
1499  }
1500  return 1;
1501 }
1502 
1503 // function which gets called from psnet_* code to evaluate an error received on a reliable
1504 // socket. In general, we only want to do drastic measures if the error indicates that the client
1505 // is no longer there.
1507 {
1508  if ( error == WSAENOTSOCK ){
1509  nprintf(("Network","Socket connection terminated and/or nonexistent, bailing..\n"));
1510 
1511  // mwa -- don't go back to main menu. You don't want host to do this. Maybe we can ignore it
1512  // because of a leaving player.
1513  return;
1514  }
1515 
1516  if ( (error != WSAECONNRESET) && (error != WSAECONNABORTED) && (error != WSAESHUTDOWN) ) {
1517  nprintf(("Network", "Error %d received on reliable socket -- ignoring\n", error));
1518  return;
1519  }
1520 
1521  if(error == WSAESHUTDOWN){
1522  nprintf(("Network","Received WSAESHUTDOWN on client socket. Cool.\n"));
1523  }
1524 
1525  // mwa -- always return for now because debugging with the stuff below is a real pain.
1526  // in essence, you can't do it!
1527  //return;
1528 
1530  int idx;
1531 
1532  nprintf(("Network", "pitching player because drop on reliable socket\n"));
1533  // find the netplayer whose socket we have an error on. Dump the player when we find him.
1534  // NOTE : make sure not to ban him
1535  for(idx=0;idx<MAX_PLAYERS;idx++){
1536  if(Net_players[idx].reliable_socket == sock){
1537  delete_player(idx);
1538  return;
1539  }
1540  }
1541  } else {
1542  nprintf(("Network", "Communications to server lost -- quitting game\n"));
1544  }
1545 }
1546 
1547 // send a repair info packet with code == code to a player if his object is the one being acted upon
1548 // dest_objp is the player object (or possible player object). source_objp is the object pointer
1549 // of the repair ship that is the source of the action. code means what is happening -- queueing up
1550 // for repair, getting repaired, aborted, complete, etc.
1551 void multi_maybe_send_repair_info(object *dest_objp, object *source_objp, int code )
1552 {
1553  // only send information on player objects
1554  if ( !MULTIPLAYER_MASTER )
1555  return;
1556 
1557  Assert( dest_objp->type == OBJ_SHIP );
1558  Assert( dest_objp != source_objp );
1559 
1560  send_repair_info_packet( dest_objp, source_objp, code );
1561 }
1562 
1564  return (type == GAME_QUERY) || (type == JOIN) || (type == PING) || (type == PONG) || (type == GAME_INFO)
1565  || (type == ACCEPT) || (type == GAME_ACTIVE) || (type == INGAME_NAK) || (type == DENY)
1566  || (type == UPDATE_DESCRIPT) || (type == ACCEPT_PLAYER_DATA) ? 1 : 0;
1567 }
1568 
1570 {
1571  // now create a dummy ship for the standalone
1573  vec3d v;
1574  int objnum, pobj_num;
1575 
1576  vm_vec_zero(&v);
1577  objnum = observer_create(&m,&v);
1578 
1579  if (objnum < 0) {
1580  Error(LOCATION, "Failed to create standalone observer object! Please investigate!");
1581  return;
1582  }
1583 
1584  Player_obj = &Objects[objnum];
1586  //obj_set_flags(Player_obj, Player_obj->flags | OF_SHOULD_BE_DEAD);
1588  Net_player->m_player->objnum = objnum;
1589 
1590  // create the default player ship object and use that as my default virtual "ship", and make it "invisible"
1592  Assert(pobj_num != -1);
1593  obj_set_flags(&Objects[pobj_num],OF_PLAYER_SHIP);
1595  Player_ship = &Ships[Objects[pobj_num].instance];
1596 
1597  // make ship hidden from sensors so that this observer cannot target it. Observers really have two ships
1598  // one observer, and one "Player_ship". Observer needs to ignore the Player_ship.
1600  strcpy_s(Player_ship->ship_name, XSTR("Standalone Ship",904));
1601  Player_ai = &Ai_info[Ships[Objects[pobj_num].instance].ai_index];
1602 
1603 }
1604 
1606 {
1607  switch (type) {
1608  case MESSAGE_ARRIVE_ENEMY:
1609  case MESSAGE_BETA_ARRIVED:
1610  case MESSAGE_GAMMA_ARRIVED:
1611  case MESSAGE_HELP:
1614  return 1;
1615  default:
1616  return 0;
1617  }
1618 }
1619 
1620 // active game list handling functions
1622 {
1623  active_game *new_game;
1624 
1625  new_game = (active_game *)vm_malloc(sizeof(active_game));
1626  if ( new_game == NULL ) {
1627  nprintf(("Network", "Cannot allocate space for new active game structure\n"));
1628  return NULL;
1629  }
1630 
1631  if ( Active_game_head != NULL ) {
1632  new_game->next = Active_game_head->next;
1633  new_game->next->prev = new_game;
1634  Active_game_head->next = new_game;
1635  new_game->prev = Active_game_head;
1636  } else {
1637  Active_game_head = new_game;
1639  }
1640 
1642 
1643  // notify the join game screen of this new item
1645 
1646  return new_game;
1647 }
1648 
1650 {
1651  active_game *gp = NULL;
1652  active_game *stop = NULL;
1653 
1654  // see if we have a game from this address already -- if not, create one. In either case, get a pointer
1655  // to an active_game structure
1656  if ( Active_game_head != NULL ) { // no games on list at all
1657  int on_list;
1658 
1659  gp = Active_game_head;
1660  stop = Active_game_head;
1661 
1662  on_list = 0;
1663  do {
1664  if ( psnet_same(&gp->server_addr, &ag->server_addr) /*&& (gp->game.security == game->security)*/ ) {
1665  on_list = 1;
1666  break;
1667  }
1668  gp = gp->next;
1669  } while (gp != stop);
1670 
1671  // insert in the list
1672  if (!on_list){
1673  gp = multi_new_active_game();
1674  // gp->ping_time = -1.0f;
1675 
1676  // copy in the game information
1677  memcpy(&gp->server_addr,&ag->server_addr,sizeof(net_addr));
1678  strcpy_s(gp->name,ag->name);
1680  strcpy_s(gp->title,ag->title);
1681  gp->num_players = ag->num_players;
1682  gp->flags = ag->flags;
1683 
1684  // ping him
1685  /*
1686  gp->ping_start = timer_get_fixed_seconds();
1687  gp->ping_end = -1;
1688  send_ping(&gp->server_addr);
1689  */
1690  multi_ping_reset(&gp->ping);
1691  multi_ping_send(&gp->server_addr,&gp->ping);
1692  }
1693  // otherwise update the netgame info we have for this guy
1694  else {
1695  memset(gp->name,0,MAX_GAMENAME_LEN+1);
1696  strcpy_s(gp->name,ag->name);
1697  memset(gp->mission_name,0,NAME_LENGTH+1);
1699  memset(gp->title,0,NAME_LENGTH+1);
1700  strcpy_s(gp->title,ag->title);
1701  gp->num_players = ag->num_players;
1702  gp->flags = ag->flags;
1703  }
1704  } else {
1705  gp = multi_new_active_game();
1706  // gp->ping_time = -1.0f;
1707 
1708  // copy in the game information
1709  memcpy(&gp->server_addr,&ag->server_addr,sizeof(net_addr));
1710  strcpy_s(gp->name,ag->name);
1712  strcpy_s(gp->title,ag->title);
1713  gp->num_players = ag->num_players;
1714  gp->flags = ag->flags;
1715 
1716  // ping him
1717  // gp->ping_start = timer_get_fixed_seconds();
1718  // gp->ping_end = -1;
1719  // send_ping(&gp->server_addr);
1720  multi_ping_reset(&gp->ping);
1721  multi_ping_send(&gp->server_addr,&gp->ping);
1722  }
1723 
1724  // don't do anything if we don't have a game entry
1725  if(gp == NULL){
1726  return NULL;
1727  }
1728 
1729  // update the last time we heard from him
1732  } else {
1734  }
1735 
1736  return gp;
1737 }
1738 
1740 {
1741  active_game *moveup,*backup;
1742 
1743  moveup = Active_game_head;
1744  backup = NULL;
1745  if(moveup != NULL){
1746  do {
1747  backup = moveup;
1748  moveup = moveup->next;
1749 
1750  vm_free(backup);
1751  backup = NULL;
1752  } while(moveup != Active_game_head);
1753  Active_game_head = NULL;
1754  }
1755  Active_game_count = 0;
1756 }
1757 
1759 {
1760  server_item *new_game;
1761 
1762  new_game = (server_item *)vm_malloc(sizeof(server_item));
1763  if ( new_game == NULL ) {
1764  nprintf(("Network", "Cannot allocate space for new server_item structure\n"));
1765  return NULL;
1766  }
1767 
1768  if ( Game_server_head != NULL ) {
1769  new_game->next = Game_server_head->next;
1770  new_game->next->prev = new_game;
1771  Game_server_head->next = new_game;
1772  new_game->prev = Game_server_head;
1773  } else {
1774  Game_server_head = new_game;
1776  }
1777 
1778  return new_game;
1779 }
1780 
1782 {
1783  server_item *moveup,*backup;
1784 
1785  moveup = Game_server_head;
1786  backup = NULL;
1787  if(moveup != NULL){
1788  do {
1789  backup = moveup;
1790  moveup = moveup->next;
1791 
1792  vm_free(backup);
1793  backup = NULL;
1794  } while(moveup != Game_server_head);
1795  Game_server_head = NULL;
1796  }
1797 }
1798 
1800 {
1801  int idx,count;
1802 
1803  // count the players who are actively connected
1804  count = 0;
1805  for(idx=0;idx<MAX_PLAYERS;idx++){
1806  // count all connected players except the standalone server (if any)
1808  count++;
1809  }
1810  }
1811 
1812  return count;
1813 }
1814 
1816 {
1817  int idx,count;
1818 
1819  // count the players who are actively connected
1820  count = 0;
1821  for(idx=0;idx<MAX_PLAYERS;idx++){
1822  // count all connected players except the standalone server (if any)
1824  count++;
1825  }
1826  }
1827 
1828  return count;
1829 
1830 }
1831 
1833 {
1834  int idx,count;
1835 
1836  // count the players who are actively connected
1837  count = 0;
1838  for(idx=0;idx<MAX_PLAYERS;idx++){
1839  // count all connected players except the standalone server (if any)
1841  count++;
1842  }
1843  }
1844 
1845  return count;
1846 }
1847 
1849 {
1850  int max_rank;
1851  ship *sp;
1852 
1853  // if the player is an observer of any kind, he cannot message
1854  if(p->flags & NETINFO_FLAG_OBSERVER){
1855  return 0;
1856  }
1857 
1858  switch(Netgame.options.squad_set){
1859  // only those of the highest rank can message
1860  case MSO_SQUAD_RANK:
1861  max_rank = multi_get_highest_rank();
1862  if(p->m_player->stats.rank < max_rank){
1863  return 0;
1864  }
1865  break;
1866 
1867  // only wing/team leaders can message
1868  case MSO_SQUAD_LEADER:
1869  // if the player has an invalid object #
1870  if(p->m_player->objnum < 0){
1871  return 0;
1872  }
1873 
1874  // check to see if he's a wingleader
1875  sp = &Ships[Objects[p->m_player->objnum].instance];
1876  if (sp->ship_name[strlen(sp->ship_name)-1] == '1')
1877  {
1878  return 0;
1879  }
1880  break;
1881 
1882  // anyone can end message
1883  case MSO_SQUAD_ANY:
1884  break;
1885 
1886  // only the host can message
1887  case MSO_SQUAD_HOST:
1888  if(!(p->flags & NETINFO_FLAG_GAME_HOST)){
1889  return 0;
1890  }
1891  break;
1892  }
1893 
1894  return 1;
1895 }
1896 
1898 {
1899  int max_rank;
1900  ship *sp;
1901 
1902  // the host can _always_ unpause a game
1903  if(p->flags & NETINFO_FLAG_GAME_HOST){
1904  return 1;
1905  }
1906 
1907  switch(Netgame.options.endgame_set){
1908  // only those of the highest rank can end the mission
1909  case MSO_END_RANK:
1910  max_rank = multi_get_highest_rank();
1911  if(p->m_player->stats.rank < max_rank){
1912  return 0;
1913  }
1914  break;
1915 
1916  // only wing/team leaders can end the mission
1917  case MSO_END_LEADER:
1918  // if the player has an invalid object #
1919  if(p->m_player->objnum < 0){
1920  return 0;
1921  }
1922 
1923  // check to see if he's a wingleader
1924  sp = &Ships[Objects[p->m_player->objnum].instance];
1925  if (sp->ship_name[strlen(sp->ship_name)-1] == '1')
1926  {
1927  return 0;
1928  }
1929  break;
1930 
1931  // anyone can end the mission
1932  case MSO_END_ANY:
1933  break;
1934 
1935  // only the host can end the mission
1936  case MSO_END_HOST:
1937  if(!(p->flags & NETINFO_FLAG_GAME_HOST)){
1938  return 0;
1939  }
1940  break;
1941  }
1942 
1943  return 1;
1944 }
1945 
1947 {
1948  int team0_avail,team1_avail;
1949  char knock_message[256], knock_callsign[CALLSIGN_LEN+1], jr_ip_string[16];
1950 
1951  // if the server versions are incompatible
1953  return JOIN_DENY_JR_BAD_VERSION;
1954  }
1955 
1956  // Grab the joiner's callsign as we may need this later if they aren't accepted
1957  strcpy (knock_callsign, jr->callsign);
1958 
1959  // check to make sure we are otherwise in a state to accept
1962 
1963  // If the game isn't password protected pass it on that someone wants to join
1964  if (Netgame.mode != NG_MODE_PASSWORD ) {
1965  sprintf(knock_message, "%s has tried to join!", knock_callsign);
1966  switch(Netgame.game_state) {
1968  case NETGAME_STATE_PAUSED:
1969  case NETGAME_STATE_DEBRIEF:
1971  send_game_chat_packet(&Net_players[MY_NET_PLAYER_NUM],knock_message,MULTI_MSG_ALL, NULL, NULL, 1);
1972  multi_display_chat_msg(knock_message,0,0);
1973  break;
1974 
1975  // in game we only bother the host.
1977  if( MULTIPLAYER_STANDALONE ) {
1978  send_game_chat_packet(&Net_players[MY_NET_PLAYER_NUM],knock_message,MULTI_MSG_TARGET, Netgame.host, NULL, 1);
1979  } else {
1981  HUD_sourced_printf(HUD_SOURCE_HIDDEN, knock_message);
1982  }
1983  break;
1984  }
1985  }
1986 
1987  return JOIN_DENY_JR_STATE;
1988  }
1989 
1990  // the standalone has some oddball situations which we must handle seperately
1992  // if this is the first connection, he will be the host so we must always accept him
1993  if(multi_num_players() == 0){
1994  /*
1995  TODO: We can use this now, but it's not compatible with older builds,
1996  so comment it out until the next release
1997 
1998  // check to see if this is a tracker game, and if so make sure this is a valid MT player
1999  // we probably eventually want to make sure he's not passing us a fake tracker id#
2000  if (MULTI_IS_TRACKER_GAME) {
2001  if (jr->tracker_id < 0) {
2002  return JOIN_DENY_JR_TRACKER_INVAL;
2003  }
2004  }
2005  */
2006 
2007  // if we're password protected
2008  if(std_is_host_passwd() && strcmp(jr->passwd, Multi_options_g.std_passwd)){
2009  return JOIN_DENY_JR_PASSWD;
2010  }
2011 
2012  // don't allow the host to join as an observer
2013  if(jr->flags & JOIN_FLAG_AS_OBSERVER){
2014  return JOIN_DENY_JR_NOOBS;
2015  } else {
2016  return -1;
2017  }
2018  }
2019  }
2020 
2021  // first off check to see if we're violating any of our max players/observers/connections boundaries
2022  // if we've already got the full 16 (MAX_PLAYERS) connections - yow
2024  // if we're full of observers and this guy wants to be an observer
2026  // if we're up to MULTI_MAX_PLAYERS-1 and we're on the standalone
2027  ((multi_num_players() >= (MULTI_MAX_PLAYERS - 1)) && (Game_mode & GM_STANDALONE_SERVER)) ||
2028  // if we're up to MULTI_MAX_PLAYERS
2030  // if the max players for a standalone was set
2032 
2033  // we're full buddy - sorry
2034  return JOIN_DENY_JR_FULL;
2035  }
2036 
2037  /*
2038  TODO: We can use this now, but it's not compatible with older builds,
2039  so comment it out until the next release
2040 
2041  // check to see if this is a tracker game, and if so make sure this is a valid MT player
2042  // we probably eventually want to make sure he's not passing us a fake tracker id#
2043  if (MULTI_IS_TRACKER_GAME) {
2044  if (jr->tracker_id < 0){
2045  return JOIN_DENY_JR_TRACKER_INVAL;
2046  }
2047  }
2048  */
2049 
2050  // check to see if the player is trying to ingame join in a closed game
2052  return JOIN_DENY_JR_CLOSED;
2053  }
2054 
2055  // check to see if the player has passed a valid password in a password protected game
2056  if((Netgame.mode == NG_MODE_PASSWORD) && strcmp(Netgame.passwd,jr->passwd)){
2057  return JOIN_DENY_JR_PASSWD;
2058  }
2059 
2060  // check to see if the netgame is forming and is temporarily marked as closed
2062  return JOIN_DENY_JR_TEMP_CLOSED;
2063  }
2064 
2065  // check to make sure he meets the rank requirement
2067  return JOIN_DENY_JR_RANK_LOW;
2068  }
2069 
2070  // check to make sure he meets the rank requirement
2072  return JOIN_DENY_JR_RANK_HIGH;
2073  }
2074 
2075  // can't ingame join a non-dogfight game
2076 /* if((Netgame.game_state != NETGAME_STATE_FORMING) && !(Netgame.type_flags & NG_TYPE_DOGFIGHT)){
2077  return JOIN_DENY_JR_TYPE;
2078  } */
2079 
2080  // if the player was banned by the standalone
2081  if ( (MULTI_IS_TRACKER_GAME && fs2netd_player_banned(addr)) || ((Game_mode & GM_STANDALONE_SERVER) && std_player_is_banned(jr->callsign)) ) {
2082  // maybe we should log this
2083  sprintf(knock_message, "Banned user %s with IP: %s attempted to join server", knock_callsign, psnet_addr_to_string(jr_ip_string, addr));
2084  ml_string(knock_message);
2085  return JOIN_DENY_JR_BANNED;
2086  }
2087 
2088  // if the game is in-mission, make sure there are ships available
2090  team0_avail = 0;
2091  team1_avail = 0;
2092  multi_player_ships_available(&team0_avail,&team1_avail);
2093 
2094  // if there are no ships available on either team
2095  if((team0_avail == 0) && (team1_avail == 0)){
2096  return JOIN_DENY_JR_FULL;
2097  }
2098  }
2099 
2100  // if my ingame joining flag is set, then deny since we only allow one ingame joiner at a time
2102  return JOIN_DENY_JR_INGAME_JOIN;
2103  }
2104 
2105  // check to make sure the game is not full (of observers, or players, as appropriate)
2106  if((jr->flags & JOIN_FLAG_AS_OBSERVER)){
2108  return JOIN_DENY_JR_FULL;
2109  }
2110  }
2111 
2112  // if the netgame is restricted or is team vs. team
2114  // ingame, we must query the host to see if this guy is accepted
2115  if(MULTI_IN_MISSION){
2116  return JOIN_QUERY_RESTRICTED;
2117  }
2118  }
2119 
2120  // check to make sure this player hasn't been kick/banned
2121  if(multi_kick_is_banned(addr)){
2122  return JOIN_DENY_JR_BANNED;
2123  }
2124 
2125  // check to make sure this player doesn't already exist
2126  if ( find_player(addr) >= 0 ) {
2127  return JOIN_DENY_JR_DUP;
2128  }
2129 
2130  return -1;
2131 }
2132 
2133 // Karajorma - called by any machine (client, host, server, standalone, etc) if the mission ends by any means
2134 // other than a warpout
2136 {
2137  if (!(MULTIPLAYER_STANDALONE)) {
2139  }
2140 }
2141 
2142 // called by any machine (client, host, server, standalone, etc), to begin warping out all player objects
2144 {
2145  int idx;
2146 
2147  // i'f i'm already marked as warping out, don't do this again
2149  return;
2150  }
2151 
2152  // stop my afterburners
2153  if((Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER)){
2155  }
2156 
2157  // traverse through each player
2158  for(idx=0;idx<MAX_PLAYERS;idx++) {
2159  object *objp;
2160 
2161  // only warpout player _ships_ which are not mine
2162  if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx]) && (Objects[Net_players[idx].m_player->objnum].type == OBJ_SHIP)){
2163 
2164  objp = &Objects[Net_players[idx].m_player->objnum];
2165 
2166  obj_set_flags( objp, objp->flags & (~OF_COLLIDES) );
2167  shipfx_warpout_start( objp );
2168  }
2169  }
2170 
2171  // now, mark ourselves as needing to warp out
2173 
2174  // if we're an observer, or we're respawning, or we can't warp out. so just jump into the debrief state
2177 
2179 
2182  } else {
2184  }
2185  }
2186  // if we're a ship, then begin the warpout process
2187  else {
2188  // turn off collision detection for my ship
2190 
2191  // turn off gliding too or ships can't get upt to speed
2194  }
2195 
2197  }
2198 }
2199 
2200 // determine the highest rank of any of the players in the game
2202 {
2203  int idx;
2204  int max_rank = -1;
2205 
2206  // go through all the players
2207  for(idx=0;idx<MAX_PLAYERS;idx++){
2208  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player->stats.rank > max_rank)){
2209  max_rank = Net_players[idx].m_player->stats.rank;
2210  }
2211  }
2212 
2213  // return what we found
2214  return max_rank;
2215 }
2216 
2217 // called on the machine of the player who hit alt+j
2219 {
2220  int idx;
2221 
2222  // all clients should send the request to the server. no exceptions
2225  }
2226  // the server of the game does some further processing
2227  else {
2228  ml_string("Server received endgame request, proceeding...");
2229 
2230  // first we should toss all ingame joiners
2231  for(idx=0;idx<MAX_PLAYERS;idx++){
2234  }
2235  }
2236 
2237  // send the endgame packet to all clients, who will act on it immediately
2241 
2243  // move to the standalone postgame (which is where we'll handle stats packets, etc)
2245  }
2246 
2247  // begin the warpout process for all players and myself
2249  }
2250 }
2251 
2252 // called to handle any special cases where a player is in some submemu when the game is ended
2254 {
2255  int stack_depth,current_depth;
2256 
2257  // first off - kill any active popups
2259 
2260  // kill any popupdeads
2261  if(popupdead_is_active()){
2262  popupdead_close();
2263  }
2264 
2265  // kill off the pilot info popup if its active
2268  }
2269 
2270  // now do any special processing for being in states other then the gameplay states
2271  stack_depth = gameseq_get_depth();
2272 
2273  // if we're not pushed on top of any states, do any special state case handling here
2274  if(stack_depth == 0){
2275  // currently there are no special cases, so return
2276  return;
2277  }
2278  // if we are pushed on any states, post events to pop them off one by one
2279  else {
2280  current_depth = stack_depth;
2281  do {
2282  switch(gameseq_get_state(stack_depth - current_depth)){
2283  // the hotkey screen
2284  case GS_STATE_HOTKEY_SCREEN :
2287  break;
2288  // the options menu
2289  case GS_STATE_OPTIONS_MENU:
2292  break;
2293  // the hud config (1 deeper in the options menu)
2294  case GS_STATE_HUD_CONFIG:
2295  hud_config_cancel();
2297  break;
2298  // controls config (1 deeper than the options menu)
2302  break;
2303  // mission goals screen
2304  case GS_STATE_SHOW_GOALS:
2307  break;
2308  // mission log scrollback
2312  break;
2313  // pause screen
2314  case GS_STATE_MULTI_PAUSED:
2317  break;
2318  }
2319 
2320  // next pushed state
2321  current_depth--;
2322  } while(current_depth > 0);
2323  }
2324 }
2325 
2326 // called by the file xfer subsytem when we start receiving a file
2327 void multi_file_xfer_notify(int handle)
2328 {
2329  char *filename;
2330  int len,idx;
2331  int cf_type;
2332  int is_mission = 0;
2333 
2334  // get the filename of the file we are receiving
2335  filename = NULL;
2336  filename = multi_xfer_get_filename(handle);
2337 
2338  // something is messed up
2339  if(filename == NULL){
2340  return;
2341  }
2342 
2343  // convert the filename to all lowercase
2344  len = strlen(filename);
2345  for(idx=0;idx<len;idx++){
2346  filename[idx] = (char)tolower(filename[idx]);
2347  }
2348 
2349  // if this is a mission file
2350  is_mission = (strstr(filename, FS_MISSION_FILE_EXT) != NULL);
2351 
2352  // determine where its going to go
2353  if(is_mission){
2355  } else {
2356  cf_type = CF_TYPE_MULTI_CACHE;
2357  }
2358 
2359  // QUICK FIX
2360  // check to see if the file is read-only
2361  if((filename[0] != '\0') && !cf_access(filename, cf_type, 00) && (cf_access(filename, cf_type, 02) == -1)){
2363 
2365  popup(PF_USE_AFFIRMATIVE_ICON, 1, XSTR("&Ok", 713), XSTR("An outdated copy of this file exists, but it cannot be overwritten by the server because it is set to be read-only. Change the permissions on this file next time.", 714));
2367  return;
2368  }
2369 
2370  // if the incoming filename is a freespace file, set my netplayer state to be "file xfer"
2371  if(is_mission){
2372  // we'd better not be xferring a file right now
2374 
2375  // force into the multidata directory
2376  multi_xfer_handle_force_dir(handle, cf_type);
2377 
2378  // set my xfer handle
2379  Net_player->s_info.xfer_handle = handle;
2380 
2383  }
2384  // otherwise always hand it off to the multi_data system
2385  else {
2386  multi_data_handle_incoming(handle);
2387  }
2388 }
2389 
2390 // return the lag/disconnected status of the game
2391 #define MULTI_LAG_VAL 400
2393 {
2394  // -1 == not lagged, 0 == lagged, 1 == disconnected
2395 
2396  // if I'm the server of the game, I can't be lagged
2398  return -1;
2399  }
2400 
2401  // if we've been disconnected for some reason or another
2403  return 1;
2404  }
2405 
2406  // if our ping time to the server is over a certain time
2408  return 0;
2409  }
2410 
2411  // not lagged
2412  return -1;
2413 }
2414 
2415 // process a valid join request
2416 void multi_process_valid_join_request(join_request *jr, net_addr *who_from, int ingame_join_team)
2417 {
2418  int net_player_num,player_num;
2419  short id_num;
2420 
2421  // create netplayer and player objects for this guy
2422  net_player_num = multi_find_open_netplayer_slot();
2423  player_num = multi_find_open_player_slot();
2424  id_num = multi_get_new_id();
2425  Assert((net_player_num != -1) && (player_num != -1));
2426 
2427  // if he is requesting to join as an observer
2428  if(jr->flags & JOIN_FLAG_AS_OBSERVER){
2429  // create the (permanently) observer player
2430  if(!multi_obs_create_player(net_player_num, jr->callsign, who_from, &Players[player_num])){
2431  Int3();
2432  }
2433 
2434  // copy his pilot image filename
2435  if(jr->image_filename[0] != '\0'){
2436  strcpy_s(Net_players[net_player_num].m_player->image_filename, jr->image_filename);
2437  } else {
2438  strcpy_s(Net_players[net_player_num].m_player->image_filename, "");
2439  }
2440 
2441  // copy his pilot squad filename
2442  Net_players[net_player_num].m_player->insignia_texture = -1;
2443  player_set_squad_bitmap(Net_players[net_player_num].m_player, jr->squad_filename, true);
2444 
2445  // clear his multi_data info
2446  multi_data_handle_join(net_player_num);
2447 
2448  // set some extra flags for him as appropriate
2449  if(MULTI_IN_MISSION){
2450  Net_players[net_player_num].flags |= NETINFO_FLAG_INGAME_JOIN;
2451  }
2452 
2453  Net_players[net_player_num].flags |= NETINFO_FLAG_CONNECTED;
2454  Net_players[net_player_num].player_id = id_num;
2455  Net_players[net_player_num].tracker_player_id = jr->tracker_id;
2456 
2457  // store pxo info
2458  if(jr->pxo_squad_name[0] != '\0'){
2459  strcpy_s(Net_players[net_player_num].p_info.pxo_squad_name, jr->pxo_squad_name);
2460  } else {
2461  strcpy_s(Net_players[net_player_num].p_info.pxo_squad_name, "");
2462  }
2463 
2464  // if he's using hacked data
2465  if(jr->flags & JOIN_FLAG_HAXOR){
2466  Net_players[net_player_num].flags |= NETINFO_FLAG_HAXOR;
2467  }
2468 
2469  // set his reliable connect time
2470  Net_players[net_player_num].s_info.reliable_connect_time = (int) time(NULL);
2471 
2472  // send the accept packet here
2474  } else {
2475  // create the player object
2476  if(!multi_create_player( net_player_num, &Players[player_num], jr->callsign, who_from, -1, id_num )){
2477  Int3();
2478  }
2479 
2480  // copy his pilot image filename
2481  if(jr->image_filename[0] != '\0'){
2482  strcpy_s(Net_players[net_player_num].m_player->image_filename, jr->image_filename);
2483  } else {
2484  strcpy_s(Net_players[net_player_num].m_player->image_filename, "");
2485  }
2486 
2487  // copy his pilot squad filename
2488  Net_players[net_player_num].m_player->insignia_texture = -1;
2489  player_set_squad_bitmap(Net_players[net_player_num].m_player, jr->squad_filename, true);
2490 
2491  // clear his multi_data info
2492  multi_data_handle_join(net_player_num);
2493 
2494  // mark him as being connected
2495  Net_players[net_player_num].flags |= NETINFO_FLAG_CONNECTED;
2496 
2497  // set his tracker id correctly
2498  Net_players[net_player_num].tracker_player_id = jr->tracker_id;
2499 
2500  // set his player id#
2501  Net_players[net_player_num].player_id = id_num;
2502 
2503  // store pxo info
2504  if(jr->pxo_squad_name[0] != '\0'){
2505  strcpy_s(Net_players[net_player_num].p_info.pxo_squad_name, jr->pxo_squad_name);
2506  } else {
2507  strcpy_s(Net_players[net_player_num].p_info.pxo_squad_name, "");
2508  }
2509 
2510  // if he's using hacked data
2511  if(jr->flags & JOIN_FLAG_HAXOR){
2512  Net_players[net_player_num].flags |= NETINFO_FLAG_HAXOR;
2513  }
2514 
2515  // flag him appropriately if he's doing an ingame join
2516  if(MULTI_IN_MISSION){
2517  Net_players[net_player_num].flags |= NETINFO_FLAG_INGAME_JOIN;
2518  Net_players[net_player_num].s_info.ingame_join_flags = 0;
2519  }
2520 
2521  // set his reliable connect time
2522  Net_players[net_player_num].s_info.reliable_connect_time = (int) time(NULL);
2523 
2524  // if he's joining as a host (on the standalone)
2525  if(Net_players[net_player_num].flags & NETINFO_FLAG_GAME_HOST){
2526  send_accept_packet(net_player_num, ACCEPT_HOST);
2527 
2528  Netgame.host = &Net_players[net_player_num];
2529 
2530  // set the game and player states appropriately
2532  }
2533  // if he's joining ingame
2534  else if(Net_players[net_player_num].flags & NETINFO_FLAG_INGAME_JOIN){
2535  // if we're in team vs. team mode
2537  {
2538  /* int i, j;
2539  int team_nums[MULTI_TS_MAX_TVT_TEAMS] = {0, 0};\
2540 
2541  //First get the number of players on each team
2542  for(i = 0; i < MULTI_TS_MAX_TVT_TEAMS; i++)
2543  {
2544  for(j = 0; j < MULTI_TS_NUM_SHIP_SLOTS; j++)
2545  {
2546  if(Multi_ts_team[i].multi_ts_flag != MULTI_TS_FLAG_EMPTY && Multi_ts_team[i].multi_ts_flag != MULTI_TS_FLAG_NONE)
2547  {
2548  team_nums[i]++;
2549  }
2550  }
2551  }
2552  //Find the lowest team
2553  //Init this to the first team, so it works properly
2554  int lowest_team[2] = {team_nums[0], 0};
2555  for(i = 0; i < MULTI_TS_MAX_TVT_TEAMS;i++)
2556  {
2557  if(Multi_ts_team[i] < lowest_team[0])
2558  {
2559  lowest_team[0] Multi_ts_team[i];
2560  lowest_team[1] = i;
2561  }
2562  }
2563 
2564  ingame_join_team = lowest_team[1];*/
2565  //Assert(ingame_join_team != -1);
2566 
2567  Net_players[net_player_num].p_info.team = ingame_join_team;
2568  }
2569 
2570  send_accept_packet(net_player_num, ACCEPT_INGAME, ingame_join_team);
2571 
2572  // set his last full update time for updating him on ingame join ships
2574  }
2575  // if he's joining as an otherwise ordinary client
2576  else {
2577  send_accept_packet(net_player_num, ACCEPT_CLIENT);
2578  }
2579  }
2580 
2581  // set my ingame joining flag if the new guy is joining ingame
2582  if ( Net_players[net_player_num].flags & NETINFO_FLAG_INGAME_JOIN ){
2584  }
2585 
2586  // copy in his options
2587  memcpy(&Net_players[net_player_num].p_info.options, &jr->player_options, sizeof(multi_local_options));
2588 
2589  // if on the standalone, then do any necessary gui updating
2591  std_add_player(&Net_players[net_player_num]);
2594  } else {
2595  // let the create game screen know someone has joined
2597  multi_create_handle_join(&Net_players[net_player_num]);
2598  }
2599  }
2600 
2602  Multi_client_update_times[net_player_num] = -1;
2603 
2604  // notify datarate
2605  multi_rate_reset(net_player_num);
2606 }
2607 
2608 // if a player is trying to join a restricted game, evaluate the keypress (accept or not, etc)
2610 {
2611  int key1=-1,key2=-1; //JAS: Get rid of optimized warning
2612  int team_val;
2613 
2614  // if the query timestamp is not set, don't do anything
2615  if(Multi_restr_query_timestamp == -1){
2616  return 0;
2617  }
2618 
2619  // determine what keys to look for based upon the mode we're in
2620  switch(Multi_join_restr_mode){
2621  // normal restricted join, Y or N
2623  key1 = KEY_Y;
2624  key2 = KEY_N;
2625  break;
2626 
2627  // team vs team, team 0 only has ships
2629  key1 = KEY_Y;
2630  key2 = KEY_N;
2631  break;
2632 
2633  // team vs team, team 1 only has ships
2635  key1 = KEY_Y;
2636  key2 = KEY_N;
2637  break;
2638 
2639  // team vs team, both teams have ships
2641  key1 = KEY_1;
2642  key2 = KEY_2;
2643  break;
2644 
2645  // illegal mode
2646  default :
2647  Int3();
2648  }
2649 
2650  // check the keypress
2651  if((k == key1) || (k == key2)){
2652  // unset the timestamp
2654 
2655  // MWA -- 5/26/98. Next line commented out. It should be cleared when the ingame joiner
2656  // actually gets into the mission
2657  //Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);
2658 
2659  // determine which team to put him on (if any)
2660  switch(Multi_join_restr_mode){
2661  // normal restricted join, Y or N
2663  team_val = (k == key1) ? 0 : -1;
2664  break;
2665 
2666  // team vs team, team 0 only has ships
2668  team_val = (k == key1) ? 0 : -1;
2669  break;
2670 
2671  // team vs team, team 1 only has ships
2673  team_val = (k == key1) ? 1 : -1;
2674  break;
2675 
2676  // team vs team, both teams have ships
2678  team_val = (k == key1) ? 0 : 1;
2679  break;
2680 
2681  // illegal mode
2682  default :
2683  team_val = -1; // JAS: Get rid of optimized warning
2684  Int3();
2685  }
2686 
2687  // perform the proper response
2689  if(team_val >= 0){
2691  }
2692  }
2693  // otherwise tell the standalone to accept him
2694  else {
2695  if(team_val >= 0){
2696  send_host_restr_packet("null",1,team_val);
2697  } else {
2698  send_host_restr_packet("null",2,-1);
2699  }
2700  }
2701 
2702  // processed a key
2703  return 1;
2704  }
2705 
2706  // didn't process any keys
2707  return 0;
2708 }
2709 
2710 // determine the status of available player ships (use team_0 for non team vs. team situations)
2711 void multi_player_ships_available(int *team_0,int *team_1)
2712 {
2713  ship_obj *moveup;
2714  int mp_team_num;
2715 
2716  *team_0 = 0;
2717  *team_1 = 0;
2718 
2719  moveup = GET_FIRST(&Ship_obj_list);
2720  while(moveup!=END_OF_LIST(&Ship_obj_list)){
2721  // if this ship is flagged as OF_COULD_BE_PLAYER
2722  if(Objects[moveup->objnum].flags & OF_COULD_BE_PLAYER){
2723  // get the team # for this ship
2724  mp_team_num = multi_ts_get_team(Ships[Objects[moveup->objnum].instance].ship_name);
2725  if(mp_team_num == 0){
2726  (*team_0)++;
2727  } else if(mp_team_num == 1){
2728  (*team_1)++;
2729  }
2730  }
2731 
2732  moveup = GET_NEXT(moveup);
2733  }
2734 }
2735 
2736 // server should update the player's bank/link status with the data in the passed ship
2738 {
2739  // don't process when the ship is dying.
2740  if ( (shipp->flags & SF_DYING) || NETPLAYER_IS_DEAD(pl) )
2741  return;
2742 
2743  // primary bank status
2745 
2746  // primary link status
2747  pl->s_info.cur_link_status &= ~(1<<0);
2748  if(shipp->flags & SF_PRIMARY_LINKED){
2749  pl->s_info.cur_link_status |= (1<<0);
2750  }
2751 
2752  // secondary bank status
2753  if ( shipp->weapons.current_secondary_bank < 0 ) {
2754  nprintf(("Network", "bashing %s's current sbank to 0\n", shipp->ship_name));
2755  shipp->weapons.current_secondary_bank = 0;
2756  }
2758 
2759  // secondary link status
2760  pl->s_info.cur_link_status &= ~(1<<1);
2761  if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
2762  pl->s_info.cur_link_status |= (1<<1);
2763  }
2764 
2765  // ets values
2766  pl->s_info.ship_ets = 0x0000;
2767  // shield ets
2768  pl->s_info.ship_ets |= ((ushort)shipp->shield_recharge_index << 8);
2769  // weapon ets
2770  pl->s_info.ship_ets |= ((ushort)shipp->weapon_recharge_index << 4);
2771  // engine ets
2772  pl->s_info.ship_ets |= ((ushort)shipp->engine_recharge_index);
2773 
2774  Assert( pl->s_info.ship_ets != 0 );
2775 }
2776 
2777 // flush the multidata cache directory
2779 {
2780  nprintf(("Network","FLUSHING MULTIDATA CACHE\n"));
2781 
2782  // call the cfile function to flush the directory
2784 }
2785 
2786 // flush all data from a previous mission before starting the next
2788 {
2789  int idx;
2790 
2791  for(idx=0;idx<MAX_PLAYERS;idx++){
2792  if(MULTI_CONNECTED(Net_players[idx])){
2793  // unset all unneeded status bits
2795 
2796  // server is always "mission ok"
2799  }
2800 
2801  // if this guy is a non-permanent observer, unset the appropriate flags
2802  if(MULTI_TEMP_OBSERVER(Net_players[idx])){
2804  }
2805 
2806  // misc
2807  multi_ping_reset(&Net_players[idx].s_info.ping);
2814 
2815  // ack handles
2817 
2818  // objnum
2819  Players[idx].objnum = -1;
2820  }
2821  }
2822 
2823  // reset netgame stuff
2825 
2826  multi_xfer_reset();
2827 
2828  // standalone servers should clear their goal trees now
2831  }
2832 
2833  // object signatures
2834  // this will eventually get reset to Netgame.security the next time an object gets its signature assigned.
2835  // We do this to resynchronize the host/server and all clients
2839 
2840  // everyone will need to either reload the current mission, leave, or load the next mission, so in any case
2842 }
2843 
2844 // should we ignore all controls and keypresses because of some multiplayer
2846 {
2847  // if the multiplayer text messaging system is active, don't return any keys
2848  if((key > 0) && multi_msg_text_process(key)){
2849  return 1;
2850  }
2851 
2852  // if the host of the game is being prompted to accept or deny a player in a restricted game
2853  if((key > 0) && multi_process_restricted_keys(key)){
2854  return 1;
2855  }
2856 
2857  // if we're in text messaging mode, ignore controls
2858  if(multi_msg_text_mode()){
2859  return 1;
2860  }
2861 
2862  // if the pause system wants to eat keys for a while
2863  if(multi_pause_eat_keys()){
2864  return 1;
2865  }
2866 
2867  // multiplayer didn't eat the key
2868  return 0;
2869 }
2870 
2871 // if the kill limit has been reached by any given player
2873 {
2874  int idx;
2875 
2876  // is the kill limit <= 0 ?
2877  // if so, consider it as _no_ kill limit
2878  if(Netgame.options.kill_limit <= 0){
2879  return 0;
2880  }
2881 
2882  // look through all active, non-observer players
2883  for(idx=0;idx<MAX_PLAYERS;idx++){
2884  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player->stats.m_kill_count_ok >= Netgame.options.kill_limit)){
2885  // someone reached the limit
2886  return 1;
2887  }
2888  }
2889 
2890  // limit has not been reached yet
2891  return 0;
2892 }
2893 
2894 // display a chat message (write to the correct spot - hud, standalone gui, chatbox, etc)
2895 void multi_display_chat_msg(const char *msg, int player_index, int add_id)
2896 {
2897  // if i'm a standalone, always add to the gui
2899  std_add_chat_text(msg,player_index,add_id);
2900  return;
2901  }
2902 
2903  // in gameplay
2904  if(Game_mode & GM_IN_MISSION){
2905  // if we're paused, send it to the chatbox
2906  if(Multi_pause_status){
2907  chatbox_add_line(msg, player_index, add_id);
2908  }
2909  // otherwise print to the HUD
2910  else {
2911  multi_msg_display_mission_text(msg, player_index);
2912  }
2913  }
2914  // otherwise add it to the chatbox
2915  else {
2916  chatbox_add_line(msg, player_index, add_id);
2917  }
2918 }
2919 
2920 // fill in Current_file_checksum and Current_file_length
2922 {
2923  CFILE *in;
2924 
2925  Multi_current_file_checksum = 0xffff;
2927 
2928  // get the filename
2929  in = cfopen(filename,"rb");
2930  if(in != NULL){
2931  // get the length of the file
2933  cfclose(in);
2934 
2935  in = cfopen(filename,"rb");
2936  if(in != NULL){
2937  // get the checksum of the file
2939 
2940  // close the file
2941  cfclose(in);
2942  in = NULL;
2943  }
2944  // if the file doesn't exist, setup some special values, so the server recognizes this
2945  else {
2946  Multi_current_file_checksum = 0xffff;
2948  }
2949  } else {
2950  // don't transfew builtin missions
2951  if(multi_is_builtin_mission()){
2953  }
2954  }
2955  nprintf(("Network","NET FILE CHECKSUM : %d %d\n",Multi_current_file_checksum,Multi_current_file_length));
2956 }
2957 
2958 char multi_unit_to_char(float unit)
2959 {
2960  char ret;
2961 
2962  if(unit > 1.0f){
2963  Int3();
2964  unit = 1.0f;
2965  }
2966  if(unit < -1.0f){
2967  Int3();
2968  unit = -1.0f;
2969  }
2970 
2971  ret = (char)(unit * 127.0f);
2972  return ret;
2973 }
2974 
2976 {
2977  float ret;
2978 
2979  ret = (float)val / 127.0f;
2980  if(ret > 1.0f){
2981  Int3();
2982  ret = 1.0f;
2983  }
2984  if(ret < -1.0f){
2985  Int3();
2986  ret = -1.0f;
2987  }
2988 
2989  return ret;
2990 }
2991 
2992 // if we should render our ping time to the server in a multiplayer game
2994 {
2995  // always show it for now
2996  return 1;
2997 }
2998 
3000 {
3001  int cspeed;
3002  const char *connection_speed;
3003 
3004 #ifdef _WIN32
3005  connection_speed = os_config_read_string(NULL, "ConnectionSpeed", "");
3006 #else
3007  connection_speed = os_config_read_string(NULL, "ConnectionSpeed", "Fast");
3008 #endif
3009 
3010  if ( !stricmp(connection_speed, NOX("Slow")) ) {
3011  cspeed = CONNECTION_SPEED_288;
3012  } else if ( !stricmp(connection_speed, NOX("56K")) ) {
3013  cspeed = CONNECTION_SPEED_56K;
3014  } else if ( !stricmp(connection_speed, NOX("ISDN")) ) {
3015  cspeed = CONNECTION_SPEED_SISDN;
3016  } else if ( !stricmp(connection_speed, NOX("Cable")) ) {
3017  cspeed = CONNECTION_SPEED_CABLE;
3018  } else if ( !stricmp(connection_speed, NOX("Fast")) ) {
3019  cspeed = CONNECTION_SPEED_T1;
3020  } else {
3021  cspeed = CONNECTION_SPEED_NONE;
3022  }
3023 
3024  return cspeed;
3025 }
3026 
3027 // return a MVALID_STATUS_* define based upon the passed string
3028 int multi_string_to_status(char *valid_string)
3029 {
3030  if (strstr(valid_string, "invalid"))
3031  return MVALID_STATUS_INVALID;
3032 
3033  if (strstr(valid_string, "valid"))
3034  return MVALID_STATUS_VALID;
3035 
3036 
3037  return MVALID_STATUS_UNKNOWN;
3038 }
3039 
3040 // if we're in tracker mode, do a validation update on all known missions
3042 {
3043  char next_filename[MAX_FILENAME_LEN+1];
3044  char next_line[512];
3045  char status_string[50];
3046  char temp[256];
3047  char *tok;
3048  CFILE *in;
3049  int file_index;
3050  uint idx;
3051  bool was_cancelled = false;
3052 
3053  // if we're a standalone, show a dialog saying "validating missions"
3055  std_create_gen_dialog("Validating missions");
3056  std_gen_set_text("Querying:", 1);
3057  }
3058 
3060 
3061  // mark all missions on our list as being MVALID_STATUS_UNKNOWN
3062  for (idx = 0; idx < Multi_create_mission_list.size(); idx++) {
3064  }
3065 
3066  // attempt to open the valid mission config file
3068 
3069  if (in != NULL) {
3070  // read in all listed missions
3071  while ( !cfeof(in) ) {
3072  // read in a line
3073  memset(next_line, 0, 512);
3074  cfgets(next_line, 512, in);
3075  drop_trailing_white_space(next_line);
3076  drop_leading_white_space(next_line);
3077 
3078  // read in a filename
3079  memset(next_filename, 0, MAX_FILENAME_LEN+1);
3080  memset(temp, 0, 256);
3081  tok = strtok(next_line, " ");
3082 
3083  if (tok == NULL)
3084  continue;
3085 
3086  strcpy_s(temp, tok);
3089  strcpy_s(next_filename, temp);
3090 
3091  // read in the status string
3092  memset(status_string, 0, 50);
3093  memset(temp, 0, 256);
3094  tok = strtok(NULL," \n");
3095 
3096  if (tok == NULL)
3097  continue;
3098 
3099  strcpy_s(temp, tok);
3102  strcpy_s(status_string, temp);
3103 
3104  // try and find the file
3105  file_index = multi_create_lookup_mission(next_filename);
3106 
3107  if (file_index >= 0)
3108  Multi_create_mission_list[file_index].valid_status = (char)multi_string_to_status(status_string);
3109  }
3110 
3111  // close the infile
3112  cfclose(in);
3113  in = NULL;
3114  }
3115 
3116  // now poll for all unknown missions
3117  was_cancelled = !(fs2netd_get_valid_missions());
3118 
3119  // if the operation was cancelled, don't write anything new
3120  if (was_cancelled) {
3121  // if we're a standalone, kill the validate dialog
3122  if(Game_mode & GM_STANDALONE_SERVER){
3124  }
3125 
3126  return;
3127  }
3128 
3129  // now rewrite the outfile with the new mission info
3131  if(in == NULL){
3132  // if we're a standalone, kill the validate dialog
3133  if(Game_mode & GM_STANDALONE_SERVER){
3135  }
3136 
3137  return;
3138  }
3139 
3140  for (idx = 0; idx < Multi_create_mission_list.size(); idx++) {
3141  switch(Multi_create_mission_list[idx].valid_status){
3142  case MVALID_STATUS_VALID:
3144  cfputs(NOX(" valid"), in);
3145  cfputs(NOX("\n"), in);
3146  break;
3147 
3148  case MVALID_STATUS_INVALID:
3149  cfputs(Multi_create_mission_list[idx].filename, in);
3150  cfputs(NOX(" invalid"), in);
3151  cfputs(NOX("\n"), in);
3152  break;
3153  }
3154  }
3155 
3156  // close the outfile
3157  cfclose(in);
3158  in = NULL;
3159 
3160  // if we're a standalone, kill the validate dialog
3161  if (Game_mode & GM_STANDALONE_SERVER) {
3163  }
3164 }
3165 
3166 // get a new id# for a player
3168 {
3169  if(Multi_id_num > 20000){
3170  Multi_id_num = 0;
3171  }
3172 
3173  return Multi_id_num++;
3174 }
3175 
3176 
3177 // ------------------------------------
3178 
3179 //XSTR:OFF
3180 DCF(multi,"changes multiplayer settings (Multiplayer)")
3181 {
3182  if (dc_optional_string("kick")) {
3183  // kick a player
3184  multi_dcf_kick();
3185 
3186 #ifndef NDEBUG
3187  } else if (dc_optional_string("stats")) {
3188  // multi_toggle_stats();
3189 
3190  } else if (dc_optional_string("show_stats")) {
3191  // multi_show_basic_stats(0);
3192 
3193  } else if (dc_optional_string("dump_stats")) {
3194  // multi_show_basic_stats(1);
3195 #endif
3196 
3197  } else if (dc_optional_string("voice")) {
3198  // settings for multiplayer voice
3199  multi_voice_dcf();
3200 
3201  } else if (dc_optional_string("respawn_chump")){
3202  // set a really large # of respawns
3203  if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
3204  Netgame.respawn = 9999;
3205  Netgame.options.respawn = 9999;
3206 
3207  // if i'm the server, send a netgame update
3210  }
3211  }
3212 
3213  } else if (dc_optional_string("ss_leaders")) {
3214  // only host or team captains can modify ships
3215  if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_GAME_HOST)) {
3218  }
3219 
3220  } else if (dc_optional_string("make_players")) {
3221 #ifndef NDEBUG
3223 #endif
3224 
3225  } else if (dc_optional_string("givecd")) {
3226  extern int Multi_has_cd;
3227  Multi_has_cd = 1;
3228 
3229  } else if (dc_optional_string("oo")) {
3230  int new_flags;
3231 
3232  if(!dc_maybe_stuff_int(&new_flags))
3233  new_flags = -1;
3234 
3235  dc_printf("Interesting flags\n");
3236  dc_printf("Pos : %d\n", 1 << 0);
3237  dc_printf("Velocity : %d\n", 1 << 7);
3238  dc_printf("Desired vel : %d\n", 1 << 8);
3239  dc_printf("Orient : %d\n", 1 << 1);
3240  dc_printf("Rotvel : %d\n", 1 << 9);
3241  dc_printf("Desired rotvel : %d\n", 1 << 10);
3242 
3243  } else if (dc_optional_string("oo_sort")) {
3244  extern int OO_sort;
3245 
3246  OO_sort = !OO_sort;
3247  dc_printf("Network object sorting %s\n", OO_sort ? "ENABLED" : "DISABLED");
3248  }
3249 }
3250 
3251 //XSTR:ON
3252 
3253 // PXO crc checking stuff
3254 
3255 
3256 void multi_spew_pxo_checksums(int max_files, const char *outfile)
3257 {
3258  char **file_names;
3259  char full_name[MAX_PATH_LEN];
3260  char wild_card[10];
3261  int count = 0, idx;
3262  uint checksum;
3263  FILE *out;
3264  char description[512] = { 0 };
3265  char filename[65] = { 0 };
3266  char gametype[32] = { 0 };
3267  size_t offset = 0;
3268  char *p = NULL;
3269 
3270  // allocate filename space
3271  file_names = (char**)vm_malloc(sizeof(char*) * max_files);
3272 
3273  if (file_names != NULL) {
3274  memset(wild_card, 0, 10);
3275  strcpy_s(wild_card, NOX("*"));
3276  strcat_s(wild_card, FS_MISSION_FILE_EXT);
3277  count = cf_get_file_list(max_files, file_names, CF_TYPE_MISSIONS, wild_card);
3278 
3279  if (count <= 0)
3280  goto Done;
3281 
3282  cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);
3283 
3284  // open the outfile
3285  out = fopen(full_name, "wt");
3286 
3287  if (out == NULL)
3288  goto Done;
3289 
3291 
3292  while (*p && (offset < sizeof(description))) {
3293  if (*p == '"') {
3294  description[offset++] = '"';
3295  description[offset++] = '"';
3296  } else {
3297  description[offset++] = *p;
3298  }
3299 
3300  p++;
3301  }
3302 
3303  // header
3304  fprintf(out, "filename,CRC32,mission type,max players,description\r\n");
3305 
3306  // do all the checksums
3307  for (idx = 0; idx < count; idx++) {
3308  memset( full_name, 0, sizeof(full_name) );
3309  strcpy_s( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT) );
3310 
3311  if ( !cf_chksum_long(full_name, &checksum) ) {
3312  continue;
3313  }
3314 
3315  if (get_mission_info(full_name)) {
3316  continue;
3317  }
3318 
3320  continue;
3321  }
3322 
3323  offset = 0;
3324  p = full_name;
3325 
3326  while (*p && (offset < sizeof(filename))) {
3327  if (*p == '"') {
3328  filename[offset++] = '"';
3329  filename[offset++] = '"';
3330  } else {
3331  filename[offset++] = *p;
3332  }
3333 
3334  p++;
3335  }
3336 
3337  filename[offset] = '\0';
3338 
3340  strcpy_s(gametype, "dogfight");
3341  } else if (IS_MISSION_MULTI_COOP) {
3342  strcpy_s(gametype, "coop");
3343  } else if (IS_MISSION_MULTI_TEAMS) {
3344  strcpy_s(gametype, "TvT");
3345  }
3346 
3347  fprintf(out, "\"%s\",%u,\"%s\",%d,\"%s\"\r\n", filename, checksum, gametype, The_mission.num_players, description);
3348  }
3349 
3350  fflush(out);
3351  fclose(out);
3352 
3353 Done:
3354  if (file_names != NULL) {
3355  for (idx = 0; idx < count; idx++) {
3356  if (file_names[idx] != NULL) {
3357  vm_free(file_names[idx]);
3358  file_names[idx] = NULL;
3359  }
3360  }
3361 
3362  vm_free(file_names);
3363  file_names = NULL;
3364  }
3365  }
3366 }
3367 
3368 /*
3369 void multi_spew_table_checksums(int max_files, char *outfile)
3370 {
3371  char **file_names;
3372  char full_name[MAX_PATH_LEN];
3373  int count, idx;
3374  uint checksum;
3375  FILE *out = NULL;
3376  char modname[128];
3377  time_t my_time = 0;
3378 
3379  // allocate filename space
3380  file_names = (char**)vm_malloc(sizeof(char*) * max_files);
3381 
3382  if (file_names != NULL) {
3383  count = cf_get_file_list(max_files, file_names, CF_TYPE_TABLES, NOX("*.tbl"));
3384 
3385  if (count <= 0)
3386  goto Done;
3387 
3388  cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);
3389 
3390  // open the outfile
3391  out = fopen(full_name, "wt");
3392 
3393  if (out == NULL)
3394  goto Done;
3395 
3396  memset( modname, 0, sizeof(modname) );
3397  strcpy_s( modname, Cmdline_spew_table_crcs );
3398 
3399  my_time = time(NULL);
3400 
3401  fprintf(out, "-- Table CRCs generated on %s \n", ctime(&my_time));
3402 
3403  fprintf(out, "LOCK TABLES `fstables` WRITE;\n");
3404  fprintf(out, "INSERT INTO `fstables` VALUES ");
3405 
3406  // do all the checksums
3407  for (idx = 0; idx < count; idx++) {
3408  memset( full_name, 0, sizeof(full_name) );
3409  strcpy_s( full_name, cf_add_ext(file_names[idx], ".tbl") );
3410 
3411  if ( cf_chksum_long(full_name, &checksum) ) {
3412  if (idx == 0)
3413  fprintf(out, "('%s',%u,'%s')", full_name, checksum, modname);
3414  else
3415  fprintf(out, ",('%s',%u,'%s')", full_name, checksum, modname);
3416  }
3417  }
3418 
3419  fprintf(out, ";\n");
3420  fprintf(out, "UNLOCK TABLES;\n");
3421 
3422  fclose(out);
3423 
3424 Done:
3425  for (idx = 0; idx < count; idx++) {
3426  if (file_names[idx] != NULL) {
3427  vm_free(file_names[idx]);
3428  file_names[idx] = NULL;
3429  }
3430  }
3431 
3432  vm_free(file_names);
3433  file_names = NULL;
3434  }
3435 }
3436 */
3437 
3438 DCF(pxospew,"spew PXO 32 bit checksums for all visible mission files (Multiplayer)")
3439 {
3440  int max_files;
3441  char file_str[MAX_NAME_LEN];
3442 
3443  if (dc_optional_string_either("help", "--help")) {
3444  dc_printf("Usage: pxospew <max_files> <filename>\n");
3445  return;
3446  }
3447 
3448  dc_stuff_int(&max_files);
3450 
3451  multi_spew_pxo_checksums(max_files, file_str);
3452 }
3453 
3454 
3455 
3456 // make a bunch of fake players - don't rely on this to be very safe - its mostly used for interface testing
3457 #ifndef NDEBUG
3458 void multi_make_fake_players(int count)
3459 {
3460  int idx;
3461 
3462  for(idx=0;idx<count;idx++){
3463  if(!MULTI_CONNECTED(Net_players[idx])){
3465  sprintf(Net_players[idx].m_player->callsign,"Player %d",idx);
3467  }
3468  }
3469 }
3470 #endif
3471 
3472 // ---------------------------------------------------------------------------------------------------------------------
3473 // PACK UNPACK STUFF
3474 //
3475 
3476 #ifdef _MSC_VER
3477 #pragma optimize("", off)
3478 #endif
3479 
3480 typedef struct bitbuffer {
3481  ubyte mask;
3482  int rack;
3483  ubyte *data;
3484  ubyte *org_data;
3485 } bitbuffer;
3486 
3487 void bitbuffer_init( bitbuffer *bitbuf, ubyte *data )
3488 {
3489  bitbuf->rack = 0;
3490  bitbuf->mask = 0x80;
3491  bitbuf->data = data;
3492  bitbuf->org_data = data;
3493 }
3494 
3495 int bitbuffer_write_flush( bitbuffer *bitbuf )
3496 {
3497  // Flush to next byte
3498  if ( bitbuf->mask != 0x80 ) {
3499  *bitbuf->data++ = (ubyte)bitbuf->rack;
3500  }
3501  return bitbuf->data-bitbuf->org_data;
3502 }
3503 
3504 int bitbuffer_read_flush( bitbuffer *bitbuf )
3505 {
3506  return bitbuf->data-bitbuf->org_data;
3507 }
3508 
3509 void bitbuffer_put( bitbuffer *bitbuf, uint data, int bit_count )
3510 {
3511  uint mask;
3512 
3513  mask = 1L << ( bit_count - 1 );
3514  while ( mask != 0) {
3515  if ( mask & data ) {
3516  bitbuf->rack |= bitbuf->mask;
3517  }
3518  bitbuf->mask >>= 1;
3519  if ( bitbuf->mask == 0 ) {
3520  *bitbuf->data++=(ubyte)bitbuf->rack;
3521  bitbuf->rack = 0;
3522  bitbuf->mask = 0x80;
3523  }
3524  mask >>= 1;
3525  }
3526 }
3527 
3528 uint bitbuffer_get_unsigned( bitbuffer *bitbuf, int bit_count )
3529 {
3530  uint mask;
3531  uint return_value;
3532 
3533  mask = 1L << ( bit_count - 1 );
3534  return_value = 0;
3535 
3536  while ( mask != 0) {
3537  if ( bitbuf->mask == 0x80 ) {
3538  bitbuf->rack = *bitbuf->data++;
3539  }
3540  if ( bitbuf->rack & bitbuf->mask ) {
3541  return_value |= mask;
3542  }
3543  mask >>= 1;
3544  bitbuf->mask >>= 1;
3545  if ( bitbuf->mask == 0 ) {
3546  bitbuf->mask = 0x80;
3547  }
3548  }
3549 
3550  return return_value;
3551 }
3552 
3553 int bitbuffer_get_signed( bitbuffer *bitbuf, int bit_count )
3554 {
3555  uint mask;
3556  uint return_value;
3557 
3558  mask = 1L << ( bit_count - 1 );
3559  return_value = 0;
3560 
3561  while ( mask != 0) {
3562  if ( bitbuf->mask == 0x80 ) {
3563  bitbuf->rack = *bitbuf->data++;
3564  }
3565  if ( bitbuf->rack & bitbuf->mask ) {
3566  return_value |= mask;
3567  }
3568  mask >>= 1;
3569  bitbuf->mask >>= 1;
3570  if ( bitbuf->mask == 0 ) {
3571  bitbuf->mask = 0x80;
3572  }
3573  }
3574 
3575  // sign extend return value
3576  return_value <<= (32-bit_count);
3577 
3578  return ((int)return_value)>>(32-bit_count);
3579 }
3580 
3581 
3582 
3583 // Packs/unpacks an object position.
3584 // Returns number of bytes read or written.
3585 // #define OO_POS_RET_SIZE 9
3587 {
3588  bitbuffer buf;
3589 
3590  bitbuffer_init(&buf,data);
3591 
3592  int a, b, c;
3593 
3594  if ( write ) {
3595  // Output pos
3596 
3597  a = fl2i(pos->xyz.x*105.0f+0.5f);
3598  b = fl2i(pos->xyz.y*105.0f+0.5f);
3599  c = fl2i(pos->xyz.z*105.0f+0.5f);
3600  CAP(a,-8388608,8388607);
3601  CAP(b,-8388608,8388607);
3602  CAP(c,-8388608,8388607);
3603 
3604  bitbuffer_put( &buf, (uint)a, 24 );
3605  bitbuffer_put( &buf, (uint)b, 24 );
3606  bitbuffer_put( &buf, (uint)c, 24 );
3607 
3608 
3609  return bitbuffer_write_flush(&buf);
3610 
3611  } else {
3612 
3613  // unpack pos
3614  a = bitbuffer_get_signed(&buf,24);
3615  b = bitbuffer_get_signed(&buf,24);
3616  c = bitbuffer_get_signed(&buf,24);
3617 
3618  pos->xyz.x = i2fl(a)/105.0f;
3619  pos->xyz.y = i2fl(b)/105.0f;
3620  pos->xyz.z = i2fl(c)/105.0f;
3621 
3622  return bitbuffer_read_flush(&buf);
3623  }
3624 }
3625 
3628 
3629 /*
3630 hack = ((ushort)orient->vec.fvec.x * 32767);
3631  memcpy(&hack, &orient->vec.fvec.x, 4);
3632  bitbuffer_put( &buf, hack, 32 );
3633  memcpy(&hack, &orient->vec.fvec.y, 4);
3634  bitbuffer_put( &buf, hack, 32 );
3635  memcpy(&hack, &orient->vec.fvec.z, 4);
3636  bitbuffer_put( &buf, hack, 32 );
3637 
3638  memcpy(&hack, &orient->vec.uvec.x, 4);
3639  bitbuffer_put( &buf, hack, 32 );
3640  memcpy(&hack, &orient->vec.uvec.y, 4);
3641  bitbuffer_put( &buf, hack, 32 );
3642  memcpy(&hack, &orient->vec.uvec.z, 4);
3643  bitbuffer_put( &buf, hack, 32 );
3644 
3645  memcpy(&hack, &orient->vec.rvec.x, 4);
3646  bitbuffer_put( &buf, hack, 32 );
3647  memcpy(&hack, &orient->vec.rvec.y, 4);
3648  bitbuffer_put( &buf, hack, 32 );
3649  memcpy(&hack, &orient->vec.rvec.z, 4);
3650  bitbuffer_put( &buf, hack, 32 );*/
3651 
3652 /*
3653 hack = bitbuffer_get_unsigned(&buf, 32);
3654  memcpy(&orient->vec.fvec.x, &hack, 4);
3655  hack = bitbuffer_get_unsigned(&buf, 32);
3656  memcpy(&orient->vec.fvec.y, &hack, 4);
3657  hack = bitbuffer_get_unsigned(&buf, 32);
3658  memcpy(&orient->vec.fvec.z, &hack, 4);
3659 
3660  hack = bitbuffer_get_unsigned(&buf, 32);
3661  memcpy(&orient->vec.uvec.x, &hack, 4);
3662  hack = bitbuffer_get_unsigned(&buf, 32);
3663  memcpy(&orient->vec.uvec.y, &hack, 4);
3664  hack = bitbuffer_get_unsigned(&buf, 32);
3665  memcpy(&orient->vec.uvec.z, &hack, 4);
3666 
3667  hack = bitbuffer_get_unsigned(&buf, 32);
3668  memcpy(&orient->vec.rvec.x, &hack, 4);
3669  hack = bitbuffer_get_unsigned(&buf, 32);
3670  memcpy(&orient->vec.rvec.y, &hack, 4);
3671  hack = bitbuffer_get_unsigned(&buf, 32);
3672  memcpy(&orient->vec.rvec.z, &hack, 4);*/
3673 
3674 // Packs/unpacks an orientation matrix.
3675 // Returns number of bytes read or written.
3676 // #define OO_ORIENT_RET_SIZE 6
3678 {
3679  bitbuffer buf;
3680 
3681  bitbuffer_init(&buf, data + 1);
3682 
3683  vec3d rot_axis;
3684  float theta;
3685  int a, b, c, d;
3686  angles ang;
3687  ubyte flag = 0x00;
3688 
3689  #define D_SCALE 32768.0f
3690  #define D_MAX_RANGE 32767
3691  #define D_MIN_RANGE -32768
3692 
3693  #define N_SCALE 2048.0f
3694  #define N_MAX_RANGE 2047
3695  #define N_MIN_RANGE -2048
3696 
3697  if ( write ) {
3698  // degenerate case - send the whole orient matrix
3699  vm_extract_angles_matrix(&ang, orient);
3700  if((ang.h > 3.130) && (ang.h < 3.150)){
3701  degenerate_count++;
3702 
3703  flag = 0xff;
3704 
3705  // stuff it
3706  a = fl2i(orient->vec.fvec.xyz.x * D_SCALE);
3707  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3708  bitbuffer_put( &buf, a, 16 );
3709  a = fl2i(orient->vec.fvec.xyz.y * D_SCALE);
3710  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3711  bitbuffer_put( &buf, a, 16 );
3712  a = fl2i(orient->vec.fvec.xyz.z * D_SCALE);
3713  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3714  bitbuffer_put( &buf, a, 16 );
3715 
3716  a = fl2i(orient->vec.uvec.xyz.x * D_SCALE);
3717  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3718  bitbuffer_put( &buf, a, 16 );
3719  a = fl2i(orient->vec.uvec.xyz.y * D_SCALE);
3720  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3721  bitbuffer_put( &buf, a, 16 );
3722  a = fl2i(orient->vec.uvec.xyz.z * D_SCALE);
3723  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3724  bitbuffer_put( &buf, a, 16 );
3725 
3726  a = fl2i(orient->vec.rvec.xyz.x * D_SCALE);
3727  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3728  bitbuffer_put( &buf, a, 16 );
3729  a = fl2i(orient->vec.rvec.xyz.y * D_SCALE);
3730  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3731  bitbuffer_put( &buf, a, 16 );
3732  a = fl2i(orient->vec.rvec.xyz.z * D_SCALE);
3733  CAP(a, D_MIN_RANGE, D_MAX_RANGE);
3734  bitbuffer_put( &buf, a, 16 );
3735  } else {
3736  non_degenerate_count++;
3737 
3738  vm_matrix_to_rot_axis_and_angle(orient, &theta, &rot_axis);
3739  // Have theta, which is an angle between 0 and PI.
3740  // Convert it to be between -1.0f and 1.0f
3741  theta = theta*2.0f/PI-1.0f;
3742 
3743  // -1 to 1
3744  a = fl2i(rot_axis.xyz.x*N_SCALE);
3745  b = fl2i(rot_axis.xyz.y*N_SCALE);
3746  c = fl2i(rot_axis.xyz.z*N_SCALE);
3747  d = fl2i(theta*N_SCALE);
3748 
3753 
3754  bitbuffer_put( &buf, (uint)a, 12 );
3755  bitbuffer_put( &buf, (uint)b, 12 );
3756  bitbuffer_put( &buf, (uint)c, 12 );
3757  bitbuffer_put( &buf, (uint)d, 12 );
3758  }
3759 
3760  // flag for degenerate case
3761  data[0] = flag;
3762 
3763  return bitbuffer_write_flush(&buf) + 1;
3764  } else {
3765  flag = data[0];
3766 
3767  // degenerate
3768  if(flag){
3769  a = bitbuffer_get_signed(&buf, 16);
3770  orient->vec.fvec.xyz.x = i2fl(a) / D_SCALE;
3771  a = bitbuffer_get_signed(&buf, 16);
3772  orient->vec.fvec.xyz.y = i2fl(a) / D_SCALE;
3773  a = bitbuffer_get_signed(&buf, 16);
3774  orient->vec.fvec.xyz.z = i2fl(a) / D_SCALE;
3775 
3776  a = bitbuffer_get_signed(&buf, 16);
3777  orient->vec.uvec.xyz.x = i2fl(a) / D_SCALE;
3778  a = bitbuffer_get_signed(&buf, 16);
3779  orient->vec.uvec.xyz.y = i2fl(a) / D_SCALE;
3780  a = bitbuffer_get_signed(&buf, 16);
3781  orient->vec.uvec.xyz.z = i2fl(a) / D_SCALE;
3782 
3783  a = bitbuffer_get_signed(&buf, 16);
3784  orient->vec.rvec.xyz.x = i2fl(a) / D_SCALE;
3785  a = bitbuffer_get_signed(&buf, 16);
3786  orient->vec.rvec.xyz.y = i2fl(a) / D_SCALE;
3787  a = bitbuffer_get_signed(&buf, 16);
3788  orient->vec.rvec.xyz.z = i2fl(a) / D_SCALE;
3789  } else {
3790  a = bitbuffer_get_signed(&buf,12);
3791  b = bitbuffer_get_signed(&buf,12);
3792  c = bitbuffer_get_signed(&buf,12);
3793  d = bitbuffer_get_signed(&buf,12);
3794 
3795  // special case
3796  rot_axis.xyz.x = i2fl(a)/N_SCALE;
3797  rot_axis.xyz.y = i2fl(b)/N_SCALE;
3798  rot_axis.xyz.z = i2fl(c)/N_SCALE;
3799  theta = i2fl(d)/N_SCALE;
3800 
3801  // Convert theta back to range 0-PI
3802  theta = (theta+1.0f)*PI_2;
3803 
3804  vm_quaternion_rotate(orient, theta, &rot_axis);
3805 
3806  vm_orthogonalize_matrix(orient);
3807  }
3808 
3809  return bitbuffer_read_flush(&buf) + 1;
3810  }
3811 }
3812 
3813 
3814 // Packs/unpacks an orientation matrix.
3815 // Returns number of bytes read or written.
3816 // #define OO_ORIENT_RET_SIZE 6
3817 /*
3818 int multi_pack_unpack_orient( int write, ubyte *data, matrix *orient)
3819 {
3820  bitbuffer buf;
3821 
3822  bitbuffer_init(&buf,data);
3823 
3824  vec3d rot_axis;
3825  float theta;
3826  int a, b, c, d;
3827 
3828  if ( write ) {
3829 
3830  // if our heading is 3.14 radians
3831  //angles ang;
3832  //vm_extract_angles_matrix(&a, orient);
3833  //if((ang.h > 3.1300) && (ang.h < 3.1500)){
3834  //} else {
3835 
3836  util_matrix_to_rot_axis_and_angle(orient, &theta, &rot_axis);
3837  // Have theta, which is an angle between 0 and PI.
3838  // Convert it to be between -1.0f and 1.0f
3839  theta = theta*2.0f/PI-1.0f;
3840 
3841  #define SCALE 2048.0f
3842 
3843  #define MAX_RANGE 2047
3844  #define MIN_RANGE -2048
3845 
3846  // -1 to 1
3847  a = fl2i(rot_axis.x*SCALE);
3848  b = fl2i(rot_axis.y*SCALE);
3849  c = fl2i(rot_axis.z*SCALE);
3850  d = fl2i(theta*SCALE);
3851 
3852  CAP(a,MIN_RANGE,MAX_RANGE);
3853  CAP(b,MIN_RANGE,MAX_RANGE);
3854  CAP(c,MIN_RANGE,MAX_RANGE);
3855  CAP(d,MIN_RANGE,MAX_RANGE);
3856  //}
3857 
3858  bitbuffer_put( &buf, (uint)a, 12 );
3859  bitbuffer_put( &buf, (uint)b, 12 );
3860  bitbuffer_put( &buf, (uint)c, 12 );
3861  bitbuffer_put( &buf, (uint)d, 12 );
3862 
3863  return bitbuffer_write_flush(&buf);
3864 
3865  } else {
3866 
3867  a = bitbuffer_get_signed(&buf,12);
3868  b = bitbuffer_get_signed(&buf,12);
3869  c = bitbuffer_get_signed(&buf,12);
3870  d = bitbuffer_get_signed(&buf,12);
3871 
3872  // special case
3873  rot_axis.x = i2fl(a)/SCALE;
3874  rot_axis.y = i2fl(b)/SCALE;
3875  rot_axis.z = i2fl(c)/SCALE;
3876  theta = i2fl(d)/SCALE;
3877 
3878  // Convert theta back to range 0-PI
3879  theta = (theta+1.0f)*PI_2;
3880 
3881  vm_quaternion_rotate(orient, theta, &rot_axis);
3882 
3883  vm_orthogonalize_matrix(orient);
3884 
3885  return bitbuffer_read_flush(&buf);
3886  }
3887 }
3888 */
3889 
3890 // Packs/unpacks velocity
3891 // Returns number of bytes read or written.
3892 // #define OO_VEL_RET_SIZE 4
3894 {
3895  bitbuffer buf;
3896 
3897  bitbuffer_init(&buf,data);
3898 
3899  int a, b, c;
3900  float r, u, f;
3901 
3902  if ( write ) {
3903  // output velocity
3904  r = vm_vec_dot( &orient->vec.rvec, &pi->vel );
3905  u = vm_vec_dot( &orient->vec.uvec, &pi->vel );
3906  f = vm_vec_dot( &orient->vec.fvec, &pi->vel );
3907 
3908  a = fl2i(r * 0.5f);
3909  b = fl2i(u * 0.5f);
3910  c = fl2i(f * 0.5f);
3911  CAP(a,-512,511);
3912  CAP(b,-512,511);
3913  CAP(c,-512,511);
3914  bitbuffer_put( &buf, (uint)a, 10 );
3915  bitbuffer_put( &buf, (uint)b, 10 );
3916  bitbuffer_put( &buf, (uint)c, 10 );
3917 
3918  return bitbuffer_write_flush(&buf);
3919  } else {
3920  // unpack velocity
3921  a = bitbuffer_get_signed(&buf,10);
3922  b = bitbuffer_get_signed(&buf,10);
3923  c = bitbuffer_get_signed(&buf,10);
3924  r = i2fl(a)/0.5f;
3925  u = i2fl(b)/0.5f;
3926  f = i2fl(c)/0.5f;
3927 
3928  // Convert into world coordinates
3929  vm_vec_zero(&pi->vel);
3930  vm_vec_scale_add2( &pi->vel, &orient->vec.rvec, r );
3931  vm_vec_scale_add2( &pi->vel, &orient->vec.uvec, u );
3932  vm_vec_scale_add2( &pi->vel, &orient->vec.fvec, f );
3933 
3934  return bitbuffer_read_flush(&buf);
3935  }
3936 }
3937 
3938 // Packs/unpacks desired_velocity
3939 // Returns number of bytes read or written.
3940 // #define OO_DESIRED_VEL_RET_SIZE 3
3942 {
3943  bitbuffer buf;
3944 
3945  bitbuffer_init(&buf,data);
3946 
3947  int a;
3948  vec3d max_vel;
3949  float r,u,f;
3950  int fields = 0;
3951 
3952  max_vel.xyz.x = MAX( sip->max_vel.xyz.x, sip->afterburner_max_vel.xyz.x );
3953  max_vel.xyz.y = MAX( sip->max_vel.xyz.y, sip->afterburner_max_vel.xyz.y );
3954  max_vel.xyz.z = MAX( sip->max_vel.xyz.z, sip->afterburner_max_vel.xyz.z );
3955 
3956  if ( write ) {
3957  // Find desired vel in local coordinates
3958  // Velocity can be from -1024 to 1024
3959 
3960  // bitfields for each value
3961  if(max_vel.xyz.x > 0.0f){
3962  fields |= (1<<0);
3963  }
3964  if(max_vel.xyz.y > 0.0f){
3965  fields |= (1<<1);
3966  }
3967  if(max_vel.xyz.z > 0.0f){
3968  fields |= (1<<2);
3969  }
3970  // fields = sip - Ship_info;
3971  bitbuffer_put(&buf, (uint)fields, 8);
3972 
3973  r = vm_vec_dot( &orient->vec.rvec, &pi->desired_vel );
3974  u = vm_vec_dot( &orient->vec.uvec, &pi->desired_vel );
3975  f = vm_vec_dot( &orient->vec.fvec, &pi->desired_vel );
3976 
3977  if ( max_vel.xyz.x > 0.0f ) {
3978  r = r / max_vel.xyz.x;
3979  a = fl2i( r * 128.0f );
3980  CAP(a,-128, 127 );
3981  bitbuffer_put( &buf, (uint)a, 8 );
3982  }
3983 
3984  if ( max_vel.xyz.y > 0.0f ) {
3985  u = u / max_vel.xyz.y;
3986  a = fl2i( u * 128.0f );
3987  CAP(a,-128, 127 );
3988  bitbuffer_put( &buf, (uint)a, 8 );
3989  }
3990 
3991  if ( max_vel.xyz.z > 0.0f ) {
3992  f = f / max_vel.xyz.z;
3993  a = fl2i( f * 128.0f );
3994  CAP(a,-128, 127 );
3995  bitbuffer_put( &buf, (uint)a, 8 );
3996  }
3997 
3998  return bitbuffer_write_flush(&buf);
3999  } else {
4000 
4001  // Find desired vel in local coordinates
4002  // Velocity can be from -1024 to 1024
4003 
4004  // get the fields bitbuffer
4005  fields = bitbuffer_get_signed(&buf, 8);
4006 
4007  if ( fields & (1<<0) ) {
4008  a = bitbuffer_get_signed(&buf,8);
4009  r = i2fl(a)/128.0f;
4010  } else {
4011  r = 0.0f;
4012  }
4013 
4014  if ( fields & (1<<1) ) {
4015  a = bitbuffer_get_signed(&buf,8);
4016  u = i2fl(a)/128.0f;
4017  } else {
4018  u = 0.0f;
4019  }
4020 
4021  if ( fields & (1<<2) ) {
4022  a = bitbuffer_get_signed(&buf,8);
4023  f = i2fl(a)/128.0f;
4024  } else {
4025  f = 0.0f;
4026  }
4027 
4028  // Convert into world coordinates
4029  vm_vec_zero(&pi->vel);
4030  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.rvec, r*max_vel.xyz.x );
4031  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.uvec, u*max_vel.xyz.y );
4032  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.fvec, f*max_vel.xyz.z );
4033 
4034  return bitbuffer_read_flush(&buf);
4035  }
4036 }
4037 
4038 // Packs/unpacks rotational velocity
4039 // Returns number of bytes read or written.
4040 // #define OO_ROTVEL_RET_SIZE 4
4042 {
4043  bitbuffer buf;
4044 
4045  bitbuffer_init(&buf,data);
4046 
4047  int a, b, c;
4048 
4049  if ( write ) {
4050  // output rotational velocity
4051  a = fl2i(pi->rotvel.xyz.x*32.0f);
4052  b = fl2i(pi->rotvel.xyz.y*32.0f);
4053  c = fl2i(pi->rotvel.xyz.z*32.0f);
4054  CAP(a,-512,511);
4055  CAP(b,-512,511);
4056  CAP(c,-512,511);
4057  bitbuffer_put( &buf, (uint)a, 10 );
4058  bitbuffer_put( &buf, (uint)b, 10 );
4059  bitbuffer_put( &buf, (uint)c, 10 );
4060 
4061 
4062  return bitbuffer_write_flush(&buf);
4063 
4064  } else {
4065 
4066  // unpack rotational velocity
4067  a = bitbuffer_get_signed(&buf,10);
4068  b = bitbuffer_get_signed(&buf,10);
4069  c = bitbuffer_get_signed(&buf,10);
4070  pi->rotvel.xyz.x = i2fl(a)/32.0f;
4071  pi->rotvel.xyz.y = i2fl(b)/32.0f;
4072  pi->rotvel.xyz.z = i2fl(c)/32.0f;
4073 
4074  return bitbuffer_read_flush(&buf);
4075  }
4076 }
4077 
4078 // Packs/unpacks desired rotvel
4079 // Returns number of bytes read or written.
4080 // #define OO_DESIRED_ROTVEL_RET_SIZE 3
4082 {
4083  bitbuffer buf;
4084  int fields = 0;
4085 
4086  bitbuffer_init(&buf,data);
4087 
4088  int a;
4089  float r,u,f;
4090 
4091  if ( write ) {
4092  // use ship_info values for max_rotvel instead of taking it from physics info
4093 
4094  // bitfields for each value
4095  if(sip->max_rotvel.xyz.x > 0.0f){
4096  fields |= (1<<0);
4097  }
4098  if(sip->max_rotvel.xyz.y > 0.0f){
4099  fields |= (1<<1);
4100  }
4101  if(sip->max_rotvel.xyz.z > 0.0f){
4102  fields |= (1<<2);
4103 
4104  }
4105  bitbuffer_put(&buf, (uint)fields, 8);
4106 
4107  // output desired rotational velocity as a percent of max
4108  if ( sip->max_rotvel.xyz.x > 0.0f ) {
4109  a = fl2i( pi->desired_rotvel.xyz.x*128.0f / sip->max_rotvel.xyz.x );
4110  CAP(a,-128, 127 );
4111  bitbuffer_put( &buf, (uint)a, 8 );
4112  }
4113 
4114  if ( sip->max_rotvel.xyz.y > 0.0f ) {
4115  a = fl2i( pi->desired_rotvel.xyz.y*128.0f / sip->max_rotvel.xyz.y );
4116  CAP(a,-128, 127 );
4117  bitbuffer_put( &buf, (uint)a, 8 );
4118  }
4119 
4120  if ( sip->max_rotvel.xyz.z > 0.0f ) {
4121  a = fl2i( pi->desired_rotvel.xyz.z*128.0f / sip->max_rotvel.xyz.z );
4122  CAP(a,-128, 127 );
4123  bitbuffer_put( &buf, (uint)a, 8 );
4124  }
4125 
4126  return bitbuffer_write_flush(&buf);
4127  } else {
4128  fields = bitbuffer_get_signed(&buf, 8);
4129 
4130  // unpack desired rotational velocity
4131  if ( fields & (1<<0) ) {
4132  a = bitbuffer_get_signed(&buf,8);
4133  r = i2fl(a)/128.0f;
4134  } else {
4135  r = 0.0f;
4136  }
4137  if ( fields & (1<<1) ) {
4138  a = bitbuffer_get_signed(&buf,8);
4139  u = i2fl(a)/128.0f;
4140  } else {
4141  u = 0.0f;
4142  }
4143  if ( fields & (1<<2) ) {
4144  a = bitbuffer_get_signed(&buf,8);
4145  f = i2fl(a)/128.0f;
4146  } else {
4147  f = 0.0f;
4148  }
4149  pi->desired_rotvel.xyz.x = r*sip->max_rotvel.xyz.x;
4150  pi->desired_rotvel.xyz.y = u*sip->max_rotvel.xyz.y;
4151  pi->desired_rotvel.xyz.z = f*sip->max_rotvel.xyz.z;
4152 
4153  return bitbuffer_read_flush(&buf);
4154  }
4155 }
4156 
4157 // Karajorma - sends the player to the correct debrief for this game type
4158 // Currently supports the dogfight kill matrix and normal debriefing stages but if new types are created they should be added here
4160  // we have a special debriefing screen multiplayer furballs use by default
4163  }
4164  // do the normal debriefing for all other situations
4165  else {
4167  }
4168 }
4169 
4170 // sends out a ping if we are multi so that psnet2 doesn't kill us off for a long load
4172 {
4173  if (Game_mode & GM_MULTIPLAYER) {
4176  Multi_ping_timestamp = timer_get_milliseconds() + 10000; // timeout is 10 seconds between pings
4177  }
4178  }
4179 }
4180 
4181 #ifdef _MSC_VER
4182 #pragma optimize("", on)
4183 #endif
#define NETINFO_FLAG_WARPING_OUT
Definition: multi.h:618
#define NG_MODE_RANK_BELOW
Definition: multi.h:635
void multi_pinfo_notify_drop(net_player *np)
int Multi_button_info_ok
Definition: multi.cpp:100
#define ASTEROID_SIG_MAX
Definition: multi.h:745
uint respawn
Definition: multi.h:507
#define OF_INVULNERABLE
Definition: object.h:107
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int Multi_client_update_times[MAX_PLAYERS]
Definition: multi.cpp:129
int timestamp(int delta_ms)
Definition: timer.cpp:226
void multi_update_valid_missions()
Definition: multiutil.cpp:3041
#define GAME_INFO
Definition: multi.h:218
#define FS_MISSION_FILE_EXT
Definition: missionparse.h:25
#define CFILE_NORMAL
Definition: cfile.h:89
#define MY_NET_PLAYER_NUM
Definition: multi.h:127
#define NET_TCP
Definition: psnet2.h:29
#define NETGAME_STATE_DEBRIEF
Definition: multi.h:669
#define MULTI_JOIN_SERVER_TIMEOUT_LOCAL
Definition: multiui.h:33
void obj_set_flags(object *obj, uint new_flags)
Definition: object.cpp:1000
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
int observer_create(matrix *orient, vec3d *pos)
Definition: observer.cpp:32
int multi_show_ingame_ping()
Definition: multiutil.cpp:2993
#define MSO_END_HOST
void vm_matrix_to_rot_axis_and_angle(const matrix *m, float *theta, vec3d *rot_axis)
Definition: vecmat.cpp:1612
int Multi_ping_timestamp
Definition: fredstubs.cpp:30
ushort client_server_seq
Definition: multi.h:468
#define timestamp_elapsed_safe(_a, _b)
Definition: timer.h:114
int multi_netplayer_flag_check(int flags, int ignore_standalone)
Definition: multiutil.cpp:1486
#define INACTIVE_LIMIT_WAIT
Definition: multiutil.cpp:1002
ai_info * Player_ai
Definition: ai.cpp:24
#define MESSAGE_REINFORCEMENTS
int ship_class
Definition: multi.h:451
int flags
Definition: player.h:104
void player_set_squad_bitmap(player *p, char *fname, bool ismulti)
#define KEY_Y
Definition: key.h:106
int Multi_mission_loaded
Definition: multi.cpp:98
np_update np_updates[MAX_PLAYERS]
Definition: ship.h:731
#define SF_CANNOT_WARP
Definition: ship.h:476
#define CONNECTION_SPEED_SISDN
Definition: multi.h:713
active_game * next
Definition: multi.h:545
#define JOIN_FLAG_HAXOR
Definition: multi.h:567
int Game_mode
Definition: systemvars.cpp:24
int std_is_host_passwd()
vec3d rotvel
Definition: physics.h:78
int multi_num_connections()
Definition: multiutil.cpp:1832
int game_type
Definition: missionparse.h:138
char name[MAX_GAMENAME_LEN+1]
Definition: multi.h:548
void multi_subsys_update_all()
Definition: multiutil.cpp:1279
net_addr server_addr
Definition: multi.h:552
int multi_pack_unpack_orient(int write, ubyte *data, matrix *orient)
Definition: multiutil.cpp:3677
void hud_escort_add_player(short id)
Definition: hudescort.cpp:1054
#define NETGAME_STATE_PAUSED
Definition: multi.h:668
active_game * multi_new_active_game(void)
Definition: multiutil.cpp:1621
#define INGAME_SHIP_UPDATE_TIME
Definition: multi_ingame.h:77
char Game_current_mission_filename[MAX_FILENAME_LEN]
Definition: fredstubs.cpp:26
ship_weapon weapons
Definition: ship.h:658
#define JOIN_DENY_JR_NOOBS
Definition: multi.h:295
net_player * Net_player
Definition: multi.cpp:94
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
ushort client_cinfo_seq
Definition: multi.h:467
int ADDRESS_LENGTH
Definition: multi.cpp:104
#define MESSAGE_BETA_ARRIVED
int Multi_pause_status
Definition: multi_pause.cpp:38
char default_player_ship[255]
#define MULTI_IN_MISSION
Definition: multi.h:718
char image_filename[MAX_FILENAME_LEN+1]
Definition: multi.h:572
void mission_goal_exit()
ushort Next_non_perm_signature
Definition: multiutil.cpp:90
void drop_trailing_white_space(char *str)
Definition: parselo.cpp:93
server_item * multi_new_server_item(void)
Definition: multiutil.cpp:1758
#define IS_MISSION_MULTI_TEAMS
Definition: missionparse.h:96
char * multi_xfer_get_filename(int handle)
Definition: multi_xfer.cpp:370
#define MULTI_SHIP_STATUS_TIME
Definition: multiutil.cpp:1238
#define MULTI_JOIN_SERVER_TIMEOUT
Definition: multiui.h:32
#define MULTI_SIG_DEBRIS
Definition: multiutil.h:35
#define NETINFO_FLAG_DO_NETWORKING
Definition: multi.h:610
vec3d desired_vel
Definition: physics.h:70
GLuint index
Definition: Glext.h:5608
int find_player(net_addr *addr)
Definition: multiutil.cpp:431
uint PSNET_SOCKET_RELIABLE
Definition: multi_xfer.h:20
void multi_send_anti_timeout_ping()
Definition: multiutil.cpp:4171
ushort multi_get_next_network_signature(int what_kind)
Definition: multiutil.cpp:168
int multi_eval_join_request(join_request *jr, net_addr *addr)
Definition: multiutil.cpp:1946
#define CONNECTION_SPEED_T1
Definition: multi.h:715
int multi_ignore_controls(int key)
Definition: multiutil.cpp:2845
player * m_player
Definition: multi.h:459
void multi_untag_player_ships()
Definition: multiutil.cpp:1404
#define DEBRIS_SIG_MIN
Definition: multi.h:741
#define MAX_SHIPS
Definition: globals.h:37
int Multi_restr_query_timestamp
Definition: multi.cpp:135
void multi_respawn_player_leave(net_player *pl)
#define MULTI_SIG_SHIP
Definition: multiutil.h:32
int mode
Definition: multi.h:494
#define CONNECTION_SPEED_288
Definition: multi.h:711
#define MISSION_FLAG_TOGGLE_DEBRIEFING
Definition: missionparse.h:79
int ascii_table[]
Definition: key.cpp:72
const char * multi_random_chat_start()
Definition: multiutil.cpp:376
#define NETGAME_STATE_BRIEFING
Definition: multi.h:665
void object_set_gliding(object *objp, bool enable, bool force)
Definition: object.cpp:2036
ushort Next_ship_signature
Definition: multiutil.cpp:88
#define NG_FLAG_INGAME_JOINING_CRITICAL
Definition: multi.h:641
void shipfx_warpin_frame(object *objp, float frametime)
Definition: shipfx.cpp:605
void send_netplayer_update_packet(net_player *pl)
Definition: multimsgs.cpp:2308
ubyte flags
Definition: multi.h:575
void multi_team_handle_drop()
Definition: multi_team.cpp:356
#define MULTI_STANDALONE(np)
Definition: multi.h:139
#define MVALID_STATUS_INVALID
Definition: multi.h:114
int gameseq_get_state(void)
Definition: fredstubs.cpp:60
int insignia_texture
Definition: player.h:195
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
void std_destroy_gen_dialog()
Assert(pm!=NULL)
#define KEY_1
Definition: key.h:72
int multi_process_restricted_keys(int k)
Definition: multiutil.cpp:2609
int multi_obs_create_player(int player_num, char *name, net_addr *addr, player *pl)
void multi_ping_send_all()
Definition: multi_ping.cpp:114
bool dc_maybe_stuff_int(int *i)
Tries to stuff an int from the Command_string.
Definition: pstypes.h:88
int ai_index
Definition: ship.h:538
#define NETINFO_FLAG_OBSERVER
Definition: multi.h:605
#define MESSAGE_SUPPORT_KILLED
ushort net_signature
Definition: object.h:163
#define MESSAGE_ARRIVE_ENEMY
#define MULTI_VALID_MISSION_FILE
Definition: multi.h:40
int weapon_recharge_index
Definition: ship.h:638
int heard_from_timer
Definition: multi.h:546
void server_verify_filesig(short player_id, ushort sum_sig, int length_sig)
Definition: multiutil.cpp:1324
#define ACCEPT_HOST
Definition: multi.h:326
int multi_kill_limit_reached()
Definition: multiutil.cpp:2872
int multi_is_builtin_mission()
Definition: multiutil.cpp:1304
int multi_netplayer_state_check(int state, int ignore_standalone)
Definition: multiutil.cpp:1433
void multi_maybe_send_repair_info(object *dest_objp, object *source_objp, int code)
Definition: multiutil.cpp:1551
void multi_msg_display_mission_text(const char *msg, int player_index)
Definition: multi_pmsg.cpp:302
#define WSAENOTSOCK
Definition: config.h:133
int bitbuffer_read_flush(bitbuffer *bitbuf)
Definition: multiutil.cpp:3504
void multi_make_player_ai(object *pobj)
Definition: multiutil.cpp:842
int multi_find_player_by_signature(int signature)
Definition: multiutil.cpp:520
struct vec3d::@225::@227 xyz
int Multi_button_info_id
Definition: multi.cpp:101
int find_player_id(short player_id)
Definition: multiutil.cpp:465
#define NETPLAYER_STATE_JOINING
Definition: multi.h:676
void ml_string(const char *string, int add_time)
Definition: multi_log.cpp:131
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define DENY
Definition: multi.h:214
server_item * next
Definition: multi.h:560
#define JOIN_FLAG_AS_OBSERVER
Definition: multi.h:566
void multi_ping_send(net_player *p)
Definition: multi_ping.cpp:100
#define MISSION_TYPE_MULTI
Definition: missionparse.h:62
Definition: cfile.h:28
int multi_get_highest_rank()
Definition: multiutil.cpp:2201
void bitbuffer_put(bitbuffer *bitbuf, uint data, int bit_count)
Definition: multiutil.cpp:3509
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
#define MULTI_END_ERROR_CONTACT_LOST
Definition: multi_endgame.h:44
int multi_get_connection_speed()
Definition: multiutil.cpp:2999
void multi_spew_pxo_checksums(int max_files, const char *outfile)
#define INVALID_SOCKET
Definition: psnet2.h:53
int multi_client_server_dead()
Definition: multi.cpp:376
#define WSAESHUTDOWN
Definition: config.h:136
object obj_used_list
Definition: object.cpp:53
int Multi_has_cd
Definition: multi.cpp:112
int multi_pack_unpack_vel(int write, ubyte *data, matrix *orient, vec3d *pos, physics_info *pi)
Definition: multiutil.cpp:3893
enum_h * u
Definition: lua.cpp:12649
ubyte version
Definition: multi.h:578
int multi_pinfo_popup_active()
char mission_name[NAME_LENGTH+1]
Definition: multi.h:549
int status_update_stamp
Definition: multi_obj.h:41
int current_primary_bank
Definition: ship.h:106
int update_stamp
Definition: multi_obj.h:40
#define SF_ARRIVING
Definition: ship.h:453
#define NETGAME_STATE_STD_HOST_SETUP
Definition: multi.h:672
int degenerate_count
Definition: multiutil.cpp:3626
uint PSNET_SOCKET
Definition: psnet2.h:46
#define MULTI_JOIN_RESTR_MODE_2
Definition: multi.h:781
#define NETINFO_FLAG_OBS_PLAYER
Definition: multi.h:606
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
#define OF_COLLIDES
Definition: object.h:104
int multi_ship_class_lookup(const char *ship_name)
Definition: multiutil.cpp:409
const char * os_config_read_string(const char *section, const char *name, const char *default_value)
Definition: osregistry.cpp:322
void send_netgame_update_packet(net_player *pl)
Definition: multimsgs.cpp:2008
uint flags
Definition: ship.h:644
hull_check orient
Definition: lua.cpp:5049
#define MSO_END_ANY
int flags
Definition: multi.h:463
#define OF_PLAYER_SHIP
Definition: object.h:109
void reset()
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize)
int key
int OO_sort
Definition: multi_obj.cpp:160
int tracker_id
Definition: multi.h:576
ubyte addr[6]
Definition: psnet2.h:41
object * objp
Definition: lua.cpp:3105
void send_repair_info_packet(object *repaired_objp, object *repair_objp, int code)
Definition: multimsgs.cpp:4845
int current_secondary_bank
Definition: ship.h:107
#define Int3()
Definition: pstypes.h:292
#define MESSAGE_GAMMA_ARRIVED
void multi_handle_sudden_mission_end()
Definition: multiutil.cpp:2135
void multi_cull_zombies()
Definition: multiutil.cpp:1010
#define WSAECONNABORTED
Definition: config.h:135
void HUD_sourced_printf(int source, const char *format,...)
Definition: hudmessage.cpp:571
char * Cmdline_spew_mission_crcs
Definition: cmdline.cpp:410
int button_function_critical(int n, net_player *p=NULL)
GLuint in
Definition: Glext.h:9087
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
void multi_msg_text_flush()
Definition: multi_pmsg.cpp:329
multi_local_options player_options
Definition: multi.h:577
void multi_create_handle_join(net_player *pl)
Definition: multiui.cpp:5058
#define STANDALONE_SHIP_SIG
Definition: multi.h:738
#define BUTTON_INFO_SAVE_COUNT
Definition: multi.h:105
#define CF_TYPE_MULTI_CACHE
Definition: cfile.h:73
void multi_do_client_warp(float frame_time)
Definition: multiutil.cpp:1140
char callsign[CALLSIGN_LEN+1]
Definition: player.h:91
int game_state
Definition: multi.h:498
int psnet_same(net_addr *a1, net_addr *a2)
Definition: psnet2.cpp:785
#define ASTEROID_SIG_MIN
Definition: multi.h:744
#define MULTI_JOIN_RESTR_MODE_4
Definition: multi.h:783
int multi_find_player_by_ship_name(const char *ship_name, bool inc_respawning)
Definition: multiutil.cpp:570
#define GAME_ACTIVE
Definition: multi.h:254
int signature
Definition: object.h:145
#define MULTI_JOIN_RESTR_MODE_1
Definition: multi.h:780
int multi_netplayer_state_check2(int state, int state2, int ignore_standalone)
Definition: multiutil.cpp:1450
GLenum type
Definition: Gl.h:1492
int Multi_ship_status_stamp
Definition: multiutil.cpp:1239
#define DCF(function_name, help_text)
The potent DCF macro, used to define new debug commands for the console.
Definition: console.h:60
void send_host_restr_packet(char *callsign, int code, int mode)
Definition: multimsgs.cpp:6832
void multi_make_fake_players(int count)
#define SHIP_SIG_MAX
Definition: multi.h:736
void multi_handle_end_mission_request()
Definition: multiutil.cpp:2218
#define MSO_SQUAD_ANY
void multi_ping_reset(ping_struct *ps)
Definition: multi_ping.cpp:41
active_game * prev
Definition: multi.h:545
#define MULTI_END_ERROR_HOST_LEFT
Definition: multi_endgame.h:51
HWND DWORD code
Definition: vddraw.h:425
int objnum
Definition: ship.h:1483
int multi_num_observers()
Definition: multiutil.cpp:1815
#define MSO_END_RANK
player Players[MAX_PLAYERS]
#define CONNECTION_SPEED_56K
Definition: multi.h:712
void multi_eval_socket_error(PSNET_SOCKET sock, int error)
Definition: multiutil.cpp:1506
#define CF_TYPE_ROOT
Definition: cfile.h:45
int tracker_player_id
Definition: multi.h:461
void std_connect_set_host_connect_status()
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
int multi_num_players()
Definition: multiutil.cpp:1799
#define NG_MODE_RANK_ABOVE
Definition: multi.h:634
void afterburners_stop(object *objp, int key_released)
void multi_display_chat_msg(const char *msg, int player_index, int add_id)
Definition: multiutil.cpp:2895
#define JOIN_DENY_JR_INGAME_JOIN
Definition: multi.h:296
GLintptr offset
Definition: Glext.h:5497
Definition: player.h:85
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
void multi_kick_player(int player_index, int ban, int reason)
Definition: multi_kick.cpp:82
void multi_data_handle_incoming(int handle)
Definition: multi_data.cpp:143
net_player_info p_info
Definition: multi.h:473
int type_flags
Definition: multi.h:493
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
#define N_SCALE
int multi_create_lookup_mission(char *fname)
Definition: multiui.cpp:5385
vec3d desired_rotvel
Definition: physics.h:71
struct matrix::@228::@230 vec
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
int non_degenerate_count
Definition: multiutil.cpp:3627
unsigned int uint
Definition: pstypes.h:64
void send_debrief_event()
Definition: multiutil.cpp:4159
char * get_text_address(char *text, ubyte *address)
Definition: multiutil.cpp:1067
void ml_printf(const char *format,...)
Definition: multi_log.cpp:112
uint bitbuffer_get_unsigned(bitbuffer *bitbuf, int bit_count)
Definition: multiutil.cpp:3528
#define cfopen(...)
Definition: cfile.h:134
int ping_avg
Definition: multi_ping.h:32
#define JOIN_DENY_JR_FULL
Definition: multi.h:292
int state
Definition: multi.h:464
#define MULTI_FS_SERVER_COMPATIBLE_VERSION
Definition: multi.h:67
#define nprintf(args)
Definition: pstypes.h:239
multi_server_options options
Definition: multi.h:514
#define GM_MULTIPLAYER
Definition: systemvars.h:18
PSNET_SOCKET_RELIABLE reliable_socket
Definition: multi.h:465
int Game_do_state_should_skip
Definition: fredstubs.cpp:201
void multi_flush_multidata_cache()
Definition: multiutil.cpp:2778
void send_game_chat_packet(net_player *from, const char *msg, int msg_mode, net_player *to, const char *expr, int server_msg)
Definition: multimsgs.cpp:615
#define MSO_FLAG_INGAME_XFER
char * cfgets(char *buf, int n, CFILE *cfile)
Definition: cfile.cpp:1571
#define CONNECTION_SPEED_CABLE
Definition: multi.h:714
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
void bitbuffer_init(bitbuffer *bitbuf, ubyte *data)
Definition: multiutil.cpp:3487
int unreliable_buffer_size
Definition: multi.h:441
fix last_heard_time
Definition: multi.h:470
#define MULTI_LAG_VAL
Definition: multiutil.cpp:2391
void multi_flush_mission_stuff()
Definition: multiutil.cpp:2787
void multi_maybe_send_ship_status()
Definition: multiutil.cpp:1242
bool object_get_gliding(object *objp)
Definition: object.cpp:2059
char * filename
netgame_info Netgame
Definition: multi.cpp:97
#define MULTI_END_NOTIFY_SERVER_LEFT
Definition: multi_endgame.h:34
#define NUM_BUTTON_FIELDS
Definition: keycontrol.h:18
#define ACCEPT_PLAYER_DATA
Definition: multi.h:222
void send_accept_packet(int new_player_num, int code, int ingame_join_team)
Definition: multimsgs.cpp:1451
int cfile_flush_dir(int dir_type)
Definition: cfile.cpp:394
void gameseq_pop_state()
#define NG_MODE_CLOSED
Definition: multi.h:631
void multi_xfer_handle_force_dir(int handle, int cf_type)
Definition: multi_xfer.cpp:401
object obj_create_list
Definition: object.cpp:54
#define MULTI_SIG_NON_PERMANENT
Definition: multiutil.h:34
void multi_broadcast_stats(int stats_code)
Definition: multiutil.cpp:1419
void multi_rate_reset(int np_index)
void vm_orthogonalize_matrix(matrix *m_src)
Definition: vecmat.cpp:1247
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
#define NG_TYPE_TEAM
Definition: multi.h:650
int bitbuffer_write_flush(bitbuffer *bitbuf)
Definition: multiutil.cpp:3495
GLuint64EXT GLuint GLuint GLenum GLenum GLuint GLuint GLenum GLuint GLuint key1
Definition: Glext.h:10079
void std_gen_set_text(char *str, int field_num)
net_player * host
Definition: multi.h:504
#define MULTI_TEMP_OBSERVER(np)
Definition: multi.h:141
int multi_pack_unpack_position(int write, ubyte *data, vec3d *pos)
Definition: multiutil.cpp:3586
#define SF_HIDDEN_FROM_SENSORS
Definition: ship.h:464
#define NETINFO_FLAG_MISSION_OK
Definition: multi.h:608
void mission_hotkey_exit()
#define KEY_N
Definition: key.h:95
#define IS_MISSION_MULTI_DOGFIGHT
Definition: missionparse.h:97
void multi_xfer_xor_flags(int handle, int flags)
Definition: multi_xfer.cpp:414
#define MULTI_OBSERVER(np)
Definition: multi.h:140
#define NETINFO_FLAG_INGAME_JOIN
Definition: multi.h:604
char * tok
Definition: fred.cpp:120
void std_add_chat_text(const char *text, int player_index, int add_id)
#define NUM_CHAT_START_WORDS
Definition: multiutil.cpp:373
#define MSO_SQUAD_RANK
#define HUD_SOURCE_HIDDEN
Definition: hudmessage.h:23
#define MSO_FLAG_SS_LEADERS
ushort flags
Definition: multi.h:553
#define MULTI_XFER_FLAG_REJECT
Definition: multi_xfer.h:32
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
int multi_xfer_send_file(PSNET_SOCKET_RELIABLE who, char *filename, int cfile_flags, int flags)
Definition: multi_xfer.cpp:201
int engine_recharge_index
Definition: ship.h:639
#define SF_PRIMARY_LINKED
Definition: ship.h:458
#define fl_abs(fl)
Definition: floating.h:31
void pilot_set_short_callsign(player *p, int max_width)
void multi_data_handle_drop(int player_index)
Definition: multi_data.cpp:90
void fill_net_addr(net_addr *addr, ubyte *address, ushort port)
Definition: multiutil.cpp:1049
void multi_xfer_reset()
Definition: multi_xfer.cpp:185
net_player_server_info s_info
Definition: multi.h:472
#define CONNECTION_SPEED_NONE
Definition: multi.h:709
#define NETGAME_STATE_MISSION_SYNC
Definition: multi.h:670
void multi_voice_dcf()
#define JOIN_DENY_JR_BAD_VERSION
Definition: multi.h:297
const char * multi_random_death_word()
Definition: multiutil.cpp:277
#define MAX_PLAYERS
Definition: pstypes.h:32
short player_id
Definition: multi.h:460
#define NETINFO_FLAG_HAXOR
Definition: multi.h:624
#define ACCEPT_CLIENT
Definition: multi.h:328
char mission_name[NAME_LENGTH+1]
Definition: multi.h:488
#define OF_COULD_BE_PLAYER
Definition: object.h:112
#define NETINFO_FLAG_GAME_HOST
Definition: multi.h:603
int multi_netplayer_state_check3(int state, int state2, int state3, int ignore_standalone)
Definition: multiutil.cpp:1467
void multi_data_handle_join(int player_index)
Definition: multi_data.cpp:79
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
int multi_find_open_netplayer_slot()
Definition: multiutil.cpp:621
angles * vm_extract_angles_matrix(angles *a, const matrix *m)
Definition: vecmat.cpp:1027
#define KICK_REASON_CANT_XFER
Definition: multi_kick.h:25
char passwd[MAX_PASSWD_LEN+1]
Definition: multi.h:491
void multi_pinfo_popup_kill()
Definition: ship.h:534
GLenum GLuint id
Definition: Glext.h:5156
#define NG_MODE_PASSWORD
Definition: multi.h:632
int multi_find_open_player_slot()
Definition: multiutil.cpp:647
#define D_MAX_RANGE
int Cmdline_objupd
Definition: cmdline.cpp:412
void debrief_handle_player_drop()
bool fs2netd_player_banned(net_addr *addr)
#define NETPLAYER_IS_DEAD(player)
Definition: multi.h:627
int multi_pack_unpack_desired_vel(int write, ubyte *data, matrix *orient, vec3d *pos, physics_info *pi, ship_info *sip)
Definition: multiutil.cpp:3941
ubyte player_rank
Definition: multi.h:574
int idx
Definition: multiui.cpp:761
void multi_file_xfer_notify(int handle)
Definition: multiutil.cpp:2327
void multi_join_notify_new_game()
Definition: multiui.cpp:792
void multi_free_server_list()
Definition: multiutil.cpp:1781
float multi_char_to_unit(float val)
Definition: multiutil.cpp:2975
int Cmdline_ingamejoin
Definition: cmdline.cpp:408
button_info Multi_ship_status_bi
Definition: multiutil.cpp:1240
int multi_find_player_by_callsign(const char *callsign)
Definition: multiutil.cpp:1291
int find_player_no_port(net_addr *addr)
Definition: multiutil.cpp:448
#define MULTI_MAX_PLAYERS
Definition: multi.h:77
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
void add_net_button_info(net_player *p, button_info *bi, int unique_id)
Definition: multiutil.cpp:1183
long fix
Definition: pstypes.h:54
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
int get_mission_info(const char *filename, mission *mission_p, bool basic)
void multi_warpout_all_players()
Definition: multiutil.cpp:2143
ushort Multi_current_file_checksum
Definition: multi.cpp:150
#define vm_vec_zero(v)
Definition: vecmat.h:37
char pxo_squad_name[LOGIN_LEN]
Definition: multi.h:581
#define MULTI_MSG_ALL
Definition: multi_pmsg.h:27
#define MULTI_JOIN_RESTR_MODE_3
Definition: multi.h:782
net_addr addr
Definition: multi.h:453
ubyte seq
Definition: multi_obj.h:39
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
void multi_kick_get_text(net_player *pl, int reason, char *str)
Definition: multi_kick.cpp:165
void multi_assign_player_ship(int net_player_num, object *objp, int ship_class)
Definition: multiutil.cpp:681
int objnum
Definition: player.h:124
#define IS_MISSION_MULTI_COOP
Definition: missionparse.h:95
int cl_last_pl
Definition: multi.h:482
#define OBJ_INDEX(objp)
Definition: object.h:235
#define INGAME_NAK
Definition: multi.h:234
int rank_base
Definition: multi.h:496
#define DEBRIS_SIG_MAX
Definition: multi.h:742
ship * Player_ship
Definition: ship.cpp:124
#define GM_IN_MISSION
Definition: systemvars.h:23
int multi_string_to_status(char *valid_string)
Definition: multiutil.cpp:3028
matrix orient
Definition: object.h:153
#define JOIN_DENY_JR_PASSWD
Definition: multi.h:287
button_info last_buttons[BUTTON_INFO_SAVE_COUNT]
Definition: multi.h:400
ubyte num_players
Definition: multi.h:551
int cfeof(CFILE *cfile)
#define NOX(s)
Definition: pstypes.h:473
int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_type)
Definition: cfile.cpp:1791
#define OBJ_SHIP
Definition: object.h:32
#define MULTIPLAYER_STANDALONE
Definition: multi.h:133
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
void multi_create_standalone_object()
Definition: multiutil.cpp:1569
int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type)
Definition: cfile.cpp:1841
#define JOIN_DENY_JR_RANK_LOW
Definition: multi.h:290
void hud_scrollback_exit()
#define NPERM_SIG_MAX
Definition: multi.h:748
#define MULTI_END_NOTIFY_NONE
Definition: multi_endgame.h:32
int last_buttons_id[BUTTON_INFO_SAVE_COUNT]
Definition: multi.h:401
GLbitfield flags
Definition: Glext.h:6722
short Multi_id_num
Definition: multi.cpp:115
#define vm_malloc(size)
Definition: pstypes.h:547
#define MVALID_STATUS_VALID
Definition: multi.h:113
void stuff_netplayer_info(net_player *nplayer, net_addr *addr, int ship_class, player *pplayer)
Definition: multiutil.cpp:664
#define INGAME_JOIN_FLAG_FILE_XFER
Definition: multi_ingame.h:75
#define NETGAME_STATE_IN_MISSION
Definition: multi.h:666
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
GLuint const GLchar * name
Definition: Glext.h:5608
#define INTEL_FLOAT(x)
Definition: pstypes.h:391
void remove_ship_status_item(net_player *p, int id)
Definition: multiutil.cpp:1172
#define NETINFO_FLAG_CONNECTED
Definition: multi.h:598
#define PROMPT_NONE
Definition: multi_endgame.h:26
#define IDENTITY_MATRIX
Definition: vecmat.h:64
void multi_server_update_player_weapons(net_player *pl, ship *shipp)
Definition: multiutil.cpp:2737
ushort Next_asteroid_signature
Definition: multiutil.cpp:89
GLuint GLfloat * val
Definition: Glext.h:6741
#define MAX_PATH_LEN
Definition: pstypes.h:325
#define JOIN_DENY_JR_STATE
Definition: multi.h:285
vec3d vel
Definition: physics.h:77
#define NETPLAYER_STATE_MISSION_XFER
Definition: multi.h:701
char * cf_add_ext(const char *filename, const char *ext)
Definition: cfile.cpp:458
int lookup_ship_status(net_player *p, int unique_id, int remove)
Definition: multiutil.cpp:1156
#define NPERM_SIG_MIN
Definition: multi.h:747
int multi_message_should_broadcast(int type)
Definition: multiutil.cpp:1605
void dc_stuff_string_white(char *out_str, size_t maxlen)
Stuffs a whitespace delimited string to out_str from the command line, stopping at the end of the com...
#define MULTI_SIG_ASTEROID
Definition: multiutil.h:33
int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error)
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
#define CF_TYPE_DATA
Definition: cfile.h:46
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define MULTI_PERM_OBSERVER(np)
Definition: multi.h:142
ping_struct ping
Definition: multi.h:395
void popupdead_close()
Definition: popupdead.cpp:522
#define D_SCALE
void send_host_captain_change_packet(short player_id, int captain_change)
Definition: multimsgs.cpp:8566
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
join_request Multi_restr_join_request
Definition: multi.cpp:136
SCP_vector< multi_create_info > Multi_create_mission_list
Definition: multiui.cpp:3326
void multi_free_active_games()
Definition: multiutil.cpp:1739
void obj_delete(int objnum)
Definition: object.cpp:522
void multi_options_update_netgame()
void multi_process_valid_join_request(join_request *jr, net_addr *who_from, int ingame_join_team)
Definition: multiutil.cpp:2416
#define CALLSIGN_LEN
Definition: globals.h:31
float frame_time
Definition: multi.cpp:1426
int Multi_join_restr_mode
Definition: multi.cpp:138
void CAP(T &v, T mn, T mx)
Definition: pstypes.h:478
#define MSO_SQUAD_LEADER
void options_cancel_exit()
void hud_escort_remove_player(short id)
Definition: hudescort.cpp:1074
int multi_query_lag_status()
Definition: multiutil.cpp:2392
int cfputs(const char *str, CFILE *cfile)
Definition: cfile.cpp:1504
#define strcat_s(...)
Definition: safe_strings.h:68
#define NG_FLAG_TEMP_CLOSED
Definition: multi.h:638
#define NAME_LENGTH
Definition: globals.h:15
#define SF_SECONDARY_DUAL_FIRE
Definition: ship.h:459
#define NG_MODE_RESTRICTED
Definition: multi.h:633
void multi_unpack_orient_matrix(ubyte *data, matrix *m)
Definition: multiutil.cpp:1113
server_item * prev
Definition: multi.h:560
int set_target_objnum(ai_info *aip, int objnum)
Definition: aicode.cpp:1250
#define N_MAX_RANGE
void delete_player(int player_num, int kicked_reason)
Definition: multiutil.cpp:862
#define INACTIVE_LIMIT_NORMAL
Definition: multiutil.cpp:1001
#define NUM_DEATH_WORDS
Definition: multiutil.cpp:275
#define fl2i(fl)
Definition: floating.h:33
#define MULTI_CONNECTED(np)
Definition: multi.h:136
#define MULTI_END_NOTIFY_KICKED_CANT_XFER
Definition: multi_endgame.h:39
#define ACCEPT
Definition: multi.h:213
int std_remove_player(net_player *p)
fix timer_get_fixed_seconds()
Definition: timer.cpp:116
int multi_find_player_by_parse_object(p_object *p_objp)
Definition: multiutil.cpp:554
player * Player