2 * Copyright (C) Volition, Inc. 2005. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
11 * $Logfile: /Freespace2/code/Network/multi_fstracker.cpp $
13 * $Date: 9/13/99 11:30a $
16 * $Log: /Freespace2/code/Network/multi_fstracker.cpp $
18 * 19 9/13/99 11:30a Dave
19 * Added checkboxes and functionality for disabling PXO banners as well as
20 * disabling d3d zbuffer biasing.
22 * 18 8/30/99 5:01p Dave
23 * Made d3d do less state changing in the nebula. Use new chat server for
26 * 17 8/25/99 4:38p Dave
27 * Updated PXO stuff. Make squad war report stuff much more nicely.
29 * 16 8/19/99 10:59a Dave
30 * Packet loss detection.
32 * 15 6/07/99 11:30p Dave
35 * 14 4/30/99 12:18p Dave
36 * Several minor bug fixes.
38 * 13 4/09/99 2:21p Dave
39 * Multiplayer beta stuff. CD checking.
41 * 12 2/25/99 4:19p Dave
42 * Added multiplayer_beta defines. Added cd_check define. Fixed a few
43 * release build warnings. Added more data to the squad war request and
46 * 11 2/24/99 2:25p Dave
47 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
48 * bug for dogfight more.
50 * 10 2/17/99 2:11p Dave
51 * First full run of squad war. All freespace and tracker side stuff
54 * 9 2/12/99 6:16p Dave
55 * Pre-mission Squad War code is 95% done.
57 * 8 2/11/99 3:08p Dave
58 * PXO refresh button. Very preliminary squad war support.
60 * 7 2/08/99 5:07p Dave
61 * FS2 chat server support. FS2 specific validated missions.
63 * 6 2/04/99 6:29p Dave
64 * First full working rev of FS2 PXO support. Fixed Glide lighting
67 * 5 2/03/99 6:06p Dave
68 * Groundwork for FS2 PXO usertracker support. Gametracker support next.
70 * 4 12/03/98 5:22p Dave
71 * Ported over Freespace 1 multiplayer ships.tbl and weapons.tbl
74 * 3 10/19/98 11:15a Dave
75 * Changed requirements for stats storing in PXO mode.
77 * 2 10/07/98 10:53a Dave
80 * 1 10/07/98 10:50a Dave
82 * 46 9/18/98 2:22a Dave
83 * Fixed freespace-side PXO api to correctly handle length 10 id strings.
84 * Fixed team select screen to handle alpha/beta/gamma ships which are not
85 * marked as OF_PLAYER_SHIP
87 * 45 9/16/98 6:54p Dave
88 * Upped max sexpression nodes to 1800 (from 1600). Changed FRED to sort
89 * the ship list box. Added code so that tracker stats are not stored with
92 * 44 9/15/98 7:24p Dave
93 * Minor UI changes. Localized bunch of new text.
95 * 43 9/11/98 4:14p Dave
96 * Fixed file checksumming of < file_size. Put in more verbose kicking and
97 * PXO stats store reporting.
99 * 42 9/10/98 1:17p Dave
100 * Put in code to flag missions and campaigns as being MD or not in Fred
101 * and Freespace. Put in multiplayer support for filtering out MD
102 * missions. Put in multiplayer popups for warning of non-valid missions.
104 * 41 9/09/98 5:53p Dave
105 * Put in new tracker packets in API. Change cfile to be able to checksum
106 * portions of a file.
108 * 40 9/04/98 3:51p Dave
109 * Put in validated mission updating and application during stats
112 * 39 9/01/98 6:48p Dave
113 * Energy suck weapon. Removed a couple of now-bogus asserts in tracker
116 * 38 8/21/98 1:14p Dave
117 * Put in log system hooks in useful places.
119 * 37 8/07/98 10:39a Allender
120 * fixed debug standalone problem where stats would continually get sent
121 * to tracker. more debug code to help find stats problem
123 * 36 7/24/98 11:14a Allender
124 * preparation for validated missions
126 * 35 6/17/98 10:56a Dave
127 * Put in debug code for detecting potential tracker stats update
130 * 34 6/13/98 9:32p Mike
131 * Kill last character in file which caused "Find in Files" to report the
132 * file as "not a text file."
134 * 33 6/13/98 6:01p Hoffoss
135 * Externalized all new (or forgot to be added) strings to all the code.
137 * 32 5/24/98 11:33a Dave
138 * Simplified the stats store process somewhat. Put in checks to find
139 * invalid situations.
141 * 31 5/24/98 10:36a Dave
142 * Put in more checks/verifications for tracker stats updating.
144 * 30 5/22/98 9:35p Dave
145 * Put in channel based support for PXO. Put in "shutdown" button for
146 * standalone. UI tweaks for TvT
148 * 29 5/21/98 9:45p Dave
149 * Lengthened tracker polling times. Put in initial support for PXO
150 * servers with channel filters. Fixed several small UI bugs.
152 * 28 5/21/98 1:52a Dave
153 * Remove obsolete command line functions. Reduce shield explosion packets
154 * drastically. Tweak PXO screen even more. Fix file xfer system so that
155 * we can guarantee file uniqueness.
157 * 27 5/20/98 2:24a Dave
158 * Fixed server side voice muting. Tweaked multi debrief/endgame
159 * sequencing a bit. Much friendlier for stats tossing/accepting now.
161 * 26 5/18/98 9:15p Dave
162 * Put in network config file support.
164 * 25 5/18/98 10:39a Dave
165 * Put in support for new tracker stats.
167 * 24 5/14/98 12:40a Dave
168 * Still more additions to the PXO screen. Updated tracker code.
170 * 23 5/13/98 6:54p Dave
171 * More sophistication to PXO interface. Changed respawn checking so
172 * there's no window for desynchronization between the server and the
175 * 22 5/08/98 7:08p Dave
176 * Lots of UI tweaking.
178 * 21 5/07/98 6:26p Dave
179 * Fix strange boundary conditions which arise when players die/respawn
180 * while the game is being ended. Spiff up the chatbox doskey thing a bit.
182 * 20 5/05/98 3:12p Chad
183 * Process _all_ server entries in a tracker game_list struct.
185 * 19 5/05/98 2:10p Dave
186 * Verify campaign support for testing. More new tracker code.
188 * 18 5/04/98 10:39p Dave
189 * Put in endgame sequencing. Need to check campaign situations.
190 * Realigned ship info on team select screen.
192 * 17 5/04/98 1:43p Dave
193 * Fixed up a standalone resetting problem. Fixed multiplayer stats
194 * collection for clients. Make sure all multiplayer ui screens have the
195 * correct palette at all times.
197 * 16 5/02/98 5:38p Dave
198 * Put in new tracker API code. Put in ship information on mp team select
199 * screen. Make standalone server name permanent. Fixed standalone server
202 * 15 4/30/98 12:57a Dave
203 * Put in new mode for ship/weapon selection. Rearranged how game querying
206 * 14 4/29/98 12:11a Dave
207 * Put in first rev of full API support for new master tracker.
209 * 13 4/28/98 7:50p Dave
210 * Fixing a broken makefile.
212 * 12 4/28/98 5:10p Dave
213 * Fixed multi_quit_game() client side sequencing problem. Turn off
214 * afterburners when ending multiplayer mission. Begin integration of mt
215 * API from Kevin Bentley.
217 * 11 4/04/98 4:22p Dave
218 * First rev of UDP reliable sockets is done. Seems to work well if not
221 * 10 3/15/98 4:17p Dave
222 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
223 * of network orientation matrices.
225 * 9 2/10/98 8:39p Dave
226 * Fixed bugs. Made endgame sequencing more clear.
228 * 8 2/07/98 1:51p Dave
229 * Centralized single and multiplayer stats tallying.
231 * 7 2/05/98 7:13p Dave
232 * Added some more security to MT communications.
234 * 6 2/04/98 6:35p Dave
235 * Changed psnet to use raw data with no headers. Started putting in
236 * support for master tracker security measures.
238 * 5 2/03/98 8:18p Dave
239 * More MT stats transfer stuff.
241 * 4 2/02/98 8:44p Dave
242 * Finished redoing master tracker stats transfer.
244 * 3 1/31/98 4:32p Dave
245 * Put in new support for VMT player validation, game logging in, and game
246 * logging out. Need to finish stats transfer.
248 * 2 1/30/98 5:53p Dave
249 * Revamped master tracker API
251 * 1 1/30/98 5:50p Dave
258 #include <netinet/in.h>
261 #include "freespace.h"
263 #include "gamesequence.h"
266 #include "valid.h" // tracker API
267 #include "gtrack.h" // tracker API
268 #include "ptrack.h" // tracker API
270 #include "multi_fstracker.h"
271 #include "multiutil.h"
273 #include "multimsgs.h"
274 #include "multi_log.h"
275 #include "stand_gui.h"
276 #include "multi_pmsg.h"
278 // -----------------------------------------------------------------------------------
279 // FREESPACE MASTER TRACKER DEFINES/VARS
282 // if the fs tracker module has been successfully initialized
283 int Multi_fs_tracker_inited = 0;
285 // if we're currently performing some operation with the tracker
286 int Multi_fs_tracker_busy = 0;
288 // channel to associate when creating a server
289 char Multi_fs_tracker_channel[255] = "";
291 // channel to use when polling the tracker for games
292 char Multi_fs_tracker_filter[255] = "";
295 // -----------------------------------------------------------------------------------
296 // FREESPACE MASTER TRACKER FORWARD DECLARATIONS
299 // used with popup_till_condition() for validating freespace pilots
300 #define MT_VALIDATE_NOT_DONE 0 // still in the process of validation
301 #define MT_VALIDATE_SUCCEED 1 // successfully validated the pilot
302 #define MT_VALIDATE_FAIL 2 // failed in validating the pilot
303 #define MT_VALIDATE_TIMEOUT 3 // timedout on contacting the tracker
304 #define MT_VALIDATE_CANCEL 4 // if the action was cancelled
305 #define MT_PILOT_VAL_TIMEOUT 5000 // timeout for validating a pilot
306 int Multi_validate_mode; // 0 == getting player id, 1 == getting player stats
307 int multi_fs_validate_process();
309 // used with popup_till_condition() for logging in freespace games
310 #define MT_LOGIN_NOT_DONE 0 // still in the process of logging in
311 #define MT_LOGIN_SUCCEED 1 // successfully logged the game in
312 #define MT_LOGIN_TIMEOUT 2 // timedout on contacting the tracker
314 // used with popup_till_condition() for storing player stats at the end of a freespace game
315 #define MT_STATS_NOT_DONE 0 // still in the process of storing stats
316 #define MT_STATS_SUCCEED 1 // successfully logged all player stats
318 // used with popup_till_condition() for validating missions
319 #define MT_MVALID_NOT_DONE 0 // still in the process of validating
320 #define MT_MVALID_VALID 1 // mission is valid
321 #define MT_MVALID_INVALID 2 // mission is invalid
322 #define MT_MVALID_ERROR 3 // error while performing operation. assume invalid
324 // store stats mode defined
325 #define MT_STORE_STATS_VALIDATE 0
326 #define MT_STORE_STATS_GET_STATS 1
327 #define MT_STORE_STATS_ACCEPT 2
328 #define MT_STORE_STATS_SEND_STATS 3
330 int Multi_store_stats_mode; // 0 == initial request for player stats, 1 == waiting for player stats, 2 == tallying stats locally, 3 == sending stats to tracker
331 int Multi_store_stats_player_index; // player we're currently working with
332 int Multi_store_stats_player_flag; // if we're finished with the current guy
333 vmt_freespace2_struct Multi_store_stats_stats; //
334 int multi_fs_store_stats_do(); // manage all master tracker stats storing
335 int multi_fs_store_stats_get_next_player(int cur_player);
337 int Multi_tracker_player_is_valid = 0;
338 int Multi_tracker_got_response = 0;
340 // copy a freespace stats struct to a tracker-freespace stats struct
341 void multi_stats_fs_to_tracker(scoring_struct *fs,vmt_freespace2_struct *vmt,player *pl,int tracker_id);
343 // copy a tracker-freespace stats struct to a freespace stats struct
344 void multi_stats_tracker_to_fs(vmt_freespace2_struct *vmt,scoring_struct *fs);
346 // process an incoming active game item
347 void multi_fs_tracker_process_game_item(game_list *gl);
349 // verify that there are no duplicate tracker id's to this one
350 void multi_fs_tracker_check_dup(int tracker_id,int player_index);
352 // verify that there are no duplicate pilot callsigns
353 void multi_fs_tracker_check_dup_callsign(net_player *player,int player_index);
355 // report on the results of the stats store procedure
356 void multi_fs_tracker_report_stats_results();
358 // tracker specific data structures
359 freespace2_net_game_data Multi_tracker_game_data;
360 vmt_freespace2_struct Multi_tracker_fs_pilot;
361 squad_war_response Multi_tracker_sw_response;
363 // -----------------------------------------------------------------------------------
364 // FREESPACE MASTER TRACKER DEFINITIONS
367 // give some processor time to the tracker API
368 void multi_fs_tracker_process()
372 PSNET_TOP_LAYER_PROCESS();
374 if(Multi_fs_tracker_inited){
375 // pilot validation system
378 // pilot tracing system
381 // game tracking system
384 // set if we've got any pending game list items
387 multi_fs_tracker_process_game_item(gl);
393 // initialize the master tracker API for Freespace
394 void multi_fs_tracker_init()
396 // don't do anything if we're already initialized
397 if(Multi_fs_tracker_inited){
401 // initialize the low-level validation stuff
402 if(!InitValidateClient()){
403 ml_printf("Error initializing tracker api (validateclient)\n");
407 // initialize the low-level pilot tracking stuff
408 if(!InitPilotTrackerClient()){
409 ml_printf("Error initializing tracker api (pilotclient)\n");
413 // intialize the low-level game tracking stuff
414 if(!InitGameTrackerClient(GT_FREESPACE2)){
415 ml_printf("Error initializing tracker api (gameclient)\n");
419 nprintf(("Network","Successfully initialized tracker api\n"));
421 // we've successfully initialized the tracker stuff
422 Multi_fs_tracker_inited = 1;
425 // validate the current player with the master tracker (will create the pilot on the MT if necessary)
426 int multi_fs_tracker_validate(int show_error)
428 validate_id_request vir;
430 if(!Multi_fs_tracker_inited){
431 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("Warning, Parallax Online startup failed. Will not be able to play tracker games!",666));
435 // set this to false for now
436 Multi_tracker_player_is_valid = 0;
437 Multi_tracker_got_response = 0;
439 // mark the module as busy
440 Multi_fs_tracker_busy = 1;
443 // validate our pilot on the master tracker if possible
444 memset(&vir,0,sizeof(vir));
445 SDL_zero(Multi_tracker_id_string);
446 SDL_strlcpy(vir.login, Multi_tracker_login, SDL_arraysize(vir.login));
447 SDL_strlcpy(vir.password, Multi_tracker_passwd, SDL_arraysize(vir.password));
448 ValidateUser(&vir,Multi_tracker_id_string);
450 // set validation mode
451 Multi_validate_mode = 0;
453 int rval = popup_till_condition(multi_fs_validate_process,XSTR("&Cancel",667),XSTR("Attempting to validate pilot ...",668));
455 // if we failed for one reason or another
456 case MT_VALIDATE_FAIL :
457 // if we're supposed to show error codes
459 popup(PF_USE_AFFIRMATIVE_ICON | PF_BODY_BIG,1,XSTR("&Ok",669),XSTR("Pilot rejected by Parallax Online!",670));
462 Multi_validate_mode = -1;
464 Multi_fs_tracker_busy = 0;
467 case MT_VALIDATE_SUCCEED :
469 if(Multi_tracker_fs_pilot.virgin_pilot){
470 multi_common_add_notify(XSTR("Successfully created and validated new pilot!",671));
472 multi_common_add_notify(XSTR("Parallax Online pilot validation succeeded!",672));
475 // copy my statistics into my pilot file
476 multi_stats_tracker_to_fs(&Multi_tracker_fs_pilot,&Player->stats);
478 Multi_validate_mode = -1;
480 Multi_fs_tracker_busy = 0;
483 case MT_VALIDATE_TIMEOUT :
484 rval = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,XSTR("&Abort",673),XSTR("&Retry",674),XSTR("Validation timed out",675));
486 // if the user clicked abort, then leave. otherwise try again
488 Multi_validate_mode = -1;
490 Multi_fs_tracker_busy = 0;
496 Multi_validate_mode = -1;
498 Multi_fs_tracker_busy = 0;
500 // essentially, cancel
506 // attempt to log the current game server in with the master tracker
507 void multi_fs_tracker_login_freespace()
509 if(!Multi_fs_tracker_inited){
510 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("Warning, Parallax Online startup failed. Will not be able to play tracker games!",666));
514 // if we're already logged into a game, don't do anything
515 SDL_assert((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_MT_CONNECTED));
517 // pretty much all we do is make 1 call
518 memset(&Multi_tracker_game_data, 0, sizeof(freespace2_net_game_data));
519 SDL_strlcpy(Multi_tracker_game_data.game_name, Netgame.name, SDL_arraysize(Multi_tracker_game_data.game_name));
520 Multi_tracker_game_data.difficulty = 99;
521 Multi_tracker_game_data.type = 0;
522 Multi_tracker_game_data.state = 1;
523 Multi_tracker_game_data.max_players = 12;
524 Multi_tracker_game_data.current_num_players = 0;
526 // if we have a valid channel string, use it
527 if(strlen(Multi_fs_tracker_channel)){
528 SDL_strlcpy(Multi_tracker_game_data.channel, Multi_fs_tracker_channel, SDL_arraysize(Multi_tracker_game_data.channel));
531 StartTrackerGame(&Multi_tracker_game_data);
532 Net_player->flags |= NETINFO_FLAG_MT_CONNECTED;
535 ml_string(NOX("Server connected to Game Tracker"));
538 // attempt to update all player statistics and scores on the tracker
539 int multi_fs_tracker_store_stats()
544 ml_string(NOX("Server storing stats on User Tracker"));
546 // retrieve stats from tracker
547 Multi_store_stats_mode = MT_STORE_STATS_VALIDATE;
549 // multi_fs_store_stats_do() will handle all details of negotiating stats transfer with the tracker
550 Multi_store_stats_player_index = -1;
551 Multi_store_stats_player_flag = 1;
553 // mark the module as busy
554 Multi_fs_tracker_busy = 1;
556 // unmark everyone's GET_FAILED flag
557 for(idx=0;idx<MAX_PLAYERS;idx++){
558 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_GET_FAILED);
559 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_SEND_FAILED);
560 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_DONE);
564 // if playing with an invalid ships.tbl
565 if(!Game_ships_tbl_valid){
566 send_game_chat_packet(Net_player, XSTR("<Server detected a hacked ships.tbl. Stats will not be saved>", 1044), MULTI_MSG_ALL, NULL, NULL, 1);
567 multi_display_chat_msg(XSTR("<Server detected a hacked ships.tbl. Stats will not be saved>", 1044), 0, 0);
568 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("You are playing with a hacked ships.tbl, your stats will not be saved", 1045) );
569 multi_fs_tracker_report_stats_results();
570 Multi_fs_tracker_busy = 0;
574 // if playing with an invalid weapons.tbl
575 if(!Game_weapons_tbl_valid){
576 send_game_chat_packet(Net_player, XSTR("<Server detected a hacked weapons.tbl. Stats will not be saved>", 1046), MULTI_MSG_ALL, NULL, NULL, 1);
577 multi_display_chat_msg(XSTR("<Server detected a hacked weapons.tbl. Stats will not be saved>", 1046), 0, 0);
578 popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("You are playing with a hacked weapons.tbl, your stats will not be saved", 1047) );
579 multi_fs_tracker_report_stats_results();
580 Multi_fs_tracker_busy = 0;
584 // if there is only 1 player, don't store the stats
585 if((multi_num_players() <= 1) && (Multi_num_players_at_start <= 1)){
586 send_game_chat_packet(Net_player, XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), MULTI_MSG_ALL, NULL, NULL, 1);
587 multi_display_chat_msg(XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), 0, 0);
588 multi_fs_tracker_report_stats_results();
589 Multi_fs_tracker_busy = 0;
593 // if any players have hacked info
594 for(idx=0; idx<MAX_PLAYERS; idx++){
595 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_HAXOR)){
600 // check to see if the mission is valid
601 if(multi_fs_tracker_validate_mission(Game_current_mission_filename) != MVALID_STATUS_VALID){
602 send_game_chat_packet(Net_player, XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), MULTI_MSG_ALL, NULL, NULL, 1);
603 multi_display_chat_msg(XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), 0, 0);
604 popup(PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK, XSTR("This is not a PXO validated mission, your stats will not be saved", 1050));
605 Multi_fs_tracker_busy = 0;
610 popup_till_condition(multi_fs_store_stats_do,XSTR("&Cancel",667), XSTR("Sending player stats requests ...",676));
612 // send appropriate chat messages indicating stats store failure
613 multi_fs_tracker_report_stats_results();
615 // mark the module as not busy anymore
616 Multi_fs_tracker_busy = 0;
621 // attempt to update all player statistics (standalone mode)
622 int multi_fs_std_tracker_store_stats()
627 // don't do anything if this is a tracker game
628 if(!(MULTI_IS_TRACKER_GAME)){
632 if(!Multi_fs_tracker_inited){
637 ml_string(NOX("Standalone server storing stats on User Tracker"));
639 // retrieve stats from tracker
640 Multi_store_stats_mode = MT_STORE_STATS_VALIDATE;
642 // multi_fs_store_stats_do() will handle all details of negotiating stats transfer with the tracker
643 Multi_store_stats_player_index = -1;
644 Multi_store_stats_player_flag = 1;
646 // mark the module as busy
647 Multi_fs_tracker_busy = 1;
649 // unmark everyone's GET_FAILED flag
650 for(idx=0;idx<MAX_PLAYERS;idx++){
651 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_GET_FAILED);
652 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_SEND_FAILED);
653 Net_players[idx].flags &= ~(NETINFO_FLAG_MT_DONE);
657 // if playing with an invalid ships.tbl
658 if(!Game_ships_tbl_valid){
659 send_game_chat_packet(Net_player, XSTR("<Server detected a hacked ships.tbl. Stats will not be saved>", 1044), MULTI_MSG_ALL, NULL, NULL, 1);
660 multi_display_chat_msg(XSTR("<Server detected a hacked ships.tbl. Stats will not be saved>", 1044), 0, 0);
661 multi_fs_tracker_report_stats_results();
662 Multi_fs_tracker_busy = 0;
666 // if playing with an invalid weapons.tbl
667 if(!Game_weapons_tbl_valid){
668 send_game_chat_packet(Net_player, XSTR("<Server detected a hacked weapons.tbl. Stats will not be saved>", 1046), MULTI_MSG_ALL, NULL, NULL, 1);
669 multi_display_chat_msg(XSTR("<Server detected a hacked weapons.tbl. Stats will not be saved>", 1046), 0, 0);
670 multi_fs_tracker_report_stats_results();
671 Multi_fs_tracker_busy = 0;
675 // if any players have hacked info
676 for(idx=0; idx<MAX_PLAYERS; idx++){
677 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_HAXOR)){
682 // if there is only 1 player, don't store the stats
683 if((multi_num_players() <= 1) && (Multi_num_players_at_start <= 1)){
684 send_game_chat_packet(Net_player, XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), MULTI_MSG_ALL, NULL, NULL, 1);
685 multi_display_chat_msg(XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), 0, 0);
686 multi_fs_tracker_report_stats_results();
687 Multi_fs_tracker_busy = 0;
691 // check to see if the mission is valid
692 if(multi_fs_tracker_validate_mission(Game_current_mission_filename) != MVALID_STATUS_VALID){
693 send_game_chat_packet(Net_player, XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), MULTI_MSG_ALL, NULL, NULL, 1);
694 multi_display_chat_msg(XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), 0, 0);
695 Multi_fs_tracker_busy = 0;
700 // multi_fs_store_stats_do() will handle all details of negotiating stats transfer with the tracker
702 ret_val = multi_fs_store_stats_do();
703 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
705 } while(ret_val == MT_STATS_NOT_DONE);
707 // report on the results
708 multi_fs_tracker_report_stats_results();
710 // mark the module as no longer busy
711 Multi_fs_tracker_busy = 0;
716 // log freespace out of the tracker
717 void multi_fs_tracker_logout()
719 if(!Multi_fs_tracker_inited){
723 // make sure we're connected
724 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER) || !(Net_player->flags & NETINFO_FLAG_MT_CONNECTED)){
728 // otherwise, log us out
732 memset(&Multi_tracker_game_data, 0, sizeof(freespace2_net_game_data));
733 Net_player->flags &= ~(NETINFO_FLAG_MT_CONNECTED);
736 ml_string(NOX("Server disconnecting from Game Tracker"));
739 // send a request for a list of games
740 void multi_fs_tracker_send_game_request()
742 filter_game_list_struct filter;
745 // if we're not initialized, don't do anything
746 if(!Multi_fs_tracker_inited){
750 // if we have a valid filter, use that instead
751 len = strlen(Multi_fs_tracker_filter);
752 if((len > 0) && (len < CHANNEL_LEN-1) ){
753 memset(&filter,0,sizeof(filter_game_list_struct));
755 SDL_strlcpy(filter.channel, Multi_fs_tracker_filter, SDL_arraysize(filter.channel));
756 RequestGameListWithFilter(&filter);
763 // if the API has successfully been initialized and is running
764 int multi_fs_tracker_inited()
766 return Multi_fs_tracker_inited;
769 // update our settings on the tracker regarding the current netgame stuff
770 void multi_fs_tracker_update_game(netgame_info *ng)
774 if(!Multi_fs_tracker_inited){
778 // copy in the relevant data
779 Multi_tracker_game_data.max_players = ng->max_players;
780 Multi_tracker_game_data.current_num_players = multi_num_players();
782 memset(Multi_tracker_game_data.players, 0 ,MAX_FREESPACE_PLAYERS * MAX_FREESPACE_PLAYER_NAME_LEN);
784 for(idx=0;idx<MAX_PLAYERS;idx++){
785 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx])){
786 strcpy(Multi_tracker_game_data.players[count], Net_players[idx].player->callsign);
787 Multi_tracker_game_data.player_rank[count] = Net_players[idx].player->stats.rank;
792 SDL_strlcpy(Multi_tracker_game_data.mission_name, ng->name, SDL_arraysize(Multi_tracker_game_data.mission_name));
795 ml_string(NOX("Server updating netgame info for Game Tracker"));
798 // if we're currently busy performing some tracker operation (ie, you should wait or not)
799 int multi_fs_tracker_busy()
801 return Multi_fs_tracker_busy;
805 // -----------------------------------------------------------------------------------
806 // FREESPACE MASTER TRACKER FORWARD DEFINITIONS
809 // used with popup_till_condition() for validating freespace pilots
810 int multi_fs_validate_process()
812 // should never be here if this is not true
813 SDL_assert(Multi_fs_tracker_inited);
815 PSNET_TOP_LAYER_PROCESS();
817 // if we're still in player validation mode
818 if(Multi_validate_mode == 0){
819 switch(ValidateUser(NULL,NULL)){
820 // timeout on waiting for response
822 return MT_VALIDATE_TIMEOUT;
826 // set tracker id to -1
827 SDL_strlcpy(Multi_tracker_id_string, "-1", SDL_arraysize(Multi_tracker_id_string));
828 Multi_tracker_id = -1;
829 return MT_VALIDATE_FAIL;
833 return MT_VALIDATE_NOT_DONE;
837 // now we need to try and receive stats
839 // mark me as being valid
840 Multi_tracker_player_is_valid = 1;
842 // change the popup text
843 popup_change_text(XSTR("Attempting to get pilot stats ...",679));
845 // get my tracker id#
846 Multi_tracker_id = atoi(Multi_tracker_id_string);
847 SDL_assert(Multi_tracker_id != -1);
849 GetFSPilotData((vmt_freespace2_struct*)0xffffffff,NULL,NULL,0);
850 GetFSPilotData(&Multi_tracker_fs_pilot,Player->callsign,Multi_tracker_id_string,1);
853 Multi_validate_mode = 1;
854 return MT_VALIDATE_NOT_DONE;
860 switch(GetFSPilotData(NULL,NULL,NULL,0)){
863 return MT_VALIDATE_TIMEOUT;
867 return MT_VALIDATE_NOT_DONE;
871 return MT_VALIDATE_SUCCEED;
875 return MT_VALIDATE_FAIL;
879 // we're not done yet - probably should never get here
880 return MT_VALIDATE_NOT_DONE;
883 // used with popup_till_condition() for storing player stats at the end of a freespace game
884 int multi_fs_store_stats_do()
886 char tracker_id_string[512];
887 char popup_text[100];
889 SDL_assert(Multi_fs_tracker_inited);
891 PSNET_TOP_LAYER_PROCESS();
893 switch(Multi_store_stats_mode){
894 // get stats for all players
895 case MT_STORE_STATS_VALIDATE :
896 Multi_store_stats_mode = MT_STORE_STATS_GET_STATS;
899 case MT_STORE_STATS_GET_STATS:
900 // if we need to get the next player
901 if(Multi_store_stats_player_flag){
902 Multi_store_stats_player_index = multi_fs_store_stats_get_next_player(Multi_store_stats_player_index);
904 // if it returns < 0 we're done with all players and should move onto the next stage (applying mission stats)
905 if(Multi_store_stats_player_index < 0){
906 Multi_store_stats_mode = MT_STORE_STATS_ACCEPT;
907 return MT_STATS_NOT_DONE;
910 // unset this flag so we process the request
911 Multi_store_stats_player_flag = 0;
913 // fill out the information request
914 memset(tracker_id_string,0,512);
915 SDL_assert(Net_players[Multi_store_stats_player_index].tracker_player_id > 0);
917 // verify that there are no duplicate tracker id's to this one
918 multi_fs_tracker_check_dup(Net_players[Multi_store_stats_player_index].tracker_player_id,Multi_store_stats_player_index);
919 multi_fs_tracker_check_dup_callsign(&Net_players[Multi_store_stats_player_index],Multi_store_stats_player_index);
921 SDL_snprintf(tracker_id_string, SDL_arraysize(tracker_id_string), "%d", Net_players[Multi_store_stats_player_index].tracker_player_id);
922 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = -1;
923 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = 0;
925 // send the request itself
926 GetFSPilotData((vmt_freespace2_struct*)0xffffffff, NULL, NULL,0);
927 memset(&Multi_store_stats_stats, 0, sizeof(vmt_freespace2_struct));
928 if(GetFSPilotData(&Multi_store_stats_stats, Net_players[Multi_store_stats_player_index].player->callsign,tracker_id_string,1) != 0){
931 // move onto the next player
932 Multi_store_stats_player_flag = 1;
933 return MT_STATS_NOT_DONE;
936 // set the popup text
937 if(!(Game_mode & GM_STANDALONE_SERVER)){
938 SDL_snprintf(popup_text, SDL_arraysize(popup_text), XSTR("Getting player stats for %s...\n", 680), Net_players[Multi_store_stats_player_index].player->callsign);
939 popup_change_text(popup_text);
941 return MT_STATS_NOT_DONE;
944 // process the request
945 switch(GetFSPilotData(NULL,NULL,NULL,0)){
948 // copy his stats, then flag him as done so we move onto the next guys
949 multi_stats_tracker_to_fs(&Multi_store_stats_stats,&Net_players[Multi_store_stats_player_index].player->stats);
951 // make sure we apply his mission stats now
952 scoring_do_accept(&Net_players[Multi_store_stats_player_index].player->stats);
956 // debug code to check for bogus stats
957 scoring_struct *ssp = &(Net_players[Multi_store_stats_player_index].player->stats);
958 vmt_freespace2_struct *vmt = &Multi_store_stats_stats;
960 if ( (ssp->missions_flown < vmt->missions_flown) || (ssp->flight_time < ssp->flight_time) || (ssp->kill_count < vmt->kill_count) ) {
966 // flag him as being completed
967 Multi_store_stats_player_flag = 1;
969 // also store this last security value so we can properly update him
970 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = Multi_store_stats_stats.security;
971 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = Multi_store_stats_stats.checksum;
979 case 3: case -2: case 2: case -3: case -1:
980 // this shouldn't be happening under most conditions. For debugging....
983 // flag him as done so we move onto the next guy
984 Multi_store_stats_player_flag = 1;
985 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = -1;
986 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = 0;
988 // mark down that the stats get for him failed
989 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_GET_FAILED;
990 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
995 // update all stats for all players locally and on client machines
996 case MT_STORE_STATS_ACCEPT :
997 // tell everyone to save their stats
998 send_store_stats_packet(1);
1000 // reset status flags and indices
1001 Multi_store_stats_player_index = -1;
1002 Multi_store_stats_player_flag = 1;
1004 Multi_store_stats_mode = MT_STORE_STATS_SEND_STATS;
1007 // send stats to the tracker
1008 case MT_STORE_STATS_SEND_STATS:
1009 // if we need to get the next player
1010 if(Multi_store_stats_player_flag){
1011 Multi_store_stats_player_index = multi_fs_store_stats_get_next_player(Multi_store_stats_player_index);
1013 // if it returns < 0 we need to move onto the next player
1014 if(Multi_store_stats_player_index < 0){
1015 return MT_STATS_SUCCEED;
1018 Multi_store_stats_player_flag = 0;
1020 // fill in the information
1021 memset(&Multi_store_stats_stats,0,sizeof(vmt_freespace2_struct));
1023 SDL_assert(Net_players[Multi_store_stats_player_index].tracker_player_id > 0);
1025 // verify that there are no duplicate tracker id's to this one
1026 multi_fs_tracker_check_dup(Net_players[Multi_store_stats_player_index].tracker_player_id,Multi_store_stats_player_index);
1027 multi_fs_tracker_check_dup_callsign(&Net_players[Multi_store_stats_player_index],Multi_store_stats_player_index);
1028 multi_stats_fs_to_tracker(&Net_players[Multi_store_stats_player_index].player->stats,&Multi_store_stats_stats,Net_players[Multi_store_stats_player_index].player,Net_players[Multi_store_stats_player_index].tracker_player_id);
1030 Multi_store_stats_stats.security = Net_players[Multi_store_stats_player_index].s_info.tracker_security_last;
1032 // SDL_assert(Net_players[Multi_store_stats_player_index].s_info.tracker_checksum != 0);
1033 Multi_store_stats_stats.checksum = Net_players[Multi_store_stats_player_index].s_info.tracker_checksum;
1036 SendFSPilotData((vmt_freespace2_struct*)0xffffffff);
1037 if(SendFSPilotData(&Multi_store_stats_stats) != 0){
1040 // failed to send, try another player the next time around
1041 Multi_store_stats_player_flag = 1;
1042 return MT_STATS_NOT_DONE;
1045 // set the popup text
1046 if(!(Game_mode & GM_STANDALONE_SERVER)){
1047 SDL_snprintf(popup_text, SDL_arraysize(popup_text), XSTR("Updating player stats for %s...\n", 681), Net_players[Multi_store_stats_player_index].player->callsign);
1048 popup_change_text(popup_text);
1051 return MT_STATS_NOT_DONE;
1054 // otherwise check on his status
1055 switch(SendFSPilotData(NULL)){
1057 case -1: case -2: case -3: case 2: case 3:
1058 // flag him as done so we move onto the next guy
1059 Multi_store_stats_player_flag = 1;
1061 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_SEND_FAILED;
1062 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
1067 // flag him as done so we move onto the next guys
1068 Multi_store_stats_player_flag = 1;
1069 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
1076 // return not done yet
1077 return MT_STATS_NOT_DONE;
1080 // copy a freespace stats struct to a tracker-freespace stats struct
1081 void multi_stats_fs_to_tracker(scoring_struct *fs, vmt_freespace2_struct *vmt, player *pl, int tracker_id)
1083 char tracker_id_string[256];
1085 // tracker id string
1086 SDL_snprintf(tracker_id_string, SDL_arraysize(tracker_id_string),"%d", tracker_id);
1087 SDL_strlcpy(vmt->tracker_id, tracker_id_string, SDL_arraysize(vmt->tracker_id));
1090 SDL_strlcpy(vmt->pilot_name, pl->callsign, SDL_arraysize(vmt->pilot_name));
1092 // score, rank and medals
1093 vmt->score = fs->score;
1094 vmt->rank = fs->rank;
1095 SDL_assert(MAX_FS2_MEDALS == NUM_MEDALS);
1096 memcpy(vmt->medals, fs->medals, sizeof(int) * MAX_FS2_MEDALS);
1097 vmt->num_medals = MAX_FS2_MEDALS;
1099 // kills and assists
1100 SDL_assert(MAX_FS2_SHIP_TYPES == MAX_SHIP_TYPES);
1101 memcpy(vmt->kills, fs->kills, sizeof(ushort) * MAX_FS2_SHIP_TYPES);
1102 vmt->assists = fs->assists;
1103 vmt->kill_count = fs->kill_count;
1104 vmt->kill_count_ok = fs->kill_count_ok;
1105 vmt->num_ship_types = MAX_FS2_SHIP_TYPES;
1108 vmt->p_shots_fired = fs->p_shots_fired;
1109 vmt->s_shots_fired = fs->s_shots_fired;
1110 vmt->p_shots_hit = fs->p_shots_hit;
1111 vmt->s_shots_hit = fs->s_shots_hit;
1112 vmt->p_bonehead_hits = fs->p_bonehead_hits;
1113 vmt->s_bonehead_hits = fs->s_bonehead_hits;
1114 vmt->bonehead_kills = fs->bonehead_kills;
1116 // missions flown information
1117 vmt->missions_flown = fs->missions_flown;
1118 vmt->flight_time = fs->flight_time;
1119 vmt->last_flown = (unsigned int)fs->last_flown;
1122 // copy a tracker-freespace stats struct to a freespace stats struct
1123 void multi_stats_tracker_to_fs(vmt_freespace2_struct *vmt,scoring_struct *fs)
1125 int num_medals, num_ship_types;
1127 // score, rank and medals
1128 fs->score = vmt->score;
1129 fs->rank = vmt->rank;
1130 num_medals = vmt->num_medals;
1131 if(num_medals > NUM_MEDALS){
1133 num_medals = NUM_MEDALS;
1135 memset(fs->medals, 0, sizeof(int) * NUM_MEDALS);
1136 memcpy(fs->medals, vmt->medals, sizeof(int) * num_medals);
1138 // kills and assists
1139 num_ship_types = vmt->num_ship_types;
1140 if(num_ship_types > MAX_SHIP_TYPES){
1142 num_ship_types = MAX_SHIP_TYPES;
1144 memset(fs->kills, 0, sizeof(ushort) * MAX_SHIP_TYPES);
1145 memcpy(fs->kills, vmt->kills, sizeof(ushort) * num_ship_types);
1146 fs->assists = vmt->assists;
1147 fs->kill_count = vmt->kill_count;
1148 fs->kill_count_ok = vmt->kill_count_ok;
1151 fs->p_shots_fired = vmt->p_shots_fired;
1152 fs->s_shots_fired = vmt->s_shots_fired;
1153 fs->p_shots_hit = vmt->p_shots_hit;
1154 fs->s_shots_hit = vmt->s_shots_hit;
1155 fs->p_bonehead_hits = vmt->p_bonehead_hits;
1156 fs->s_bonehead_hits = vmt->s_bonehead_hits;
1157 fs->bonehead_kills = vmt->bonehead_kills;
1159 // missions flown information
1160 fs->missions_flown = vmt->missions_flown;
1161 fs->flight_time = vmt->flight_time;
1162 fs->last_flown = (fs_time_t)vmt->last_flown;
1163 if(fs->last_flown < 0){
1168 // process an incoming active game item
1169 void multi_fs_tracker_process_game_item(game_list *gl)
1174 for(idx=0;idx<MAX_GAME_LISTS_PER_PACKET;idx++){
1175 // skip null server addresses
1176 if(gl->game_server[idx] == 0){
1180 // package up the game information
1181 memset(&ag,0,sizeof(active_game));
1182 SDL_strlcpy(ag.name, gl->game_name[idx], SDL_arraysize(ag.name));
1183 memcpy(&ag.server_addr.addr[0],&gl->game_server[idx],sizeof(unsigned long));
1184 ag.server_addr.type = NET_TCP;
1185 ag.server_addr.port = DEFAULT_GAME_PORT;
1187 // add to the active game list
1188 // multi_update_active_games(&ag);
1190 // query this server
1191 send_server_query(&ag.server_addr);
1195 int multi_fs_store_stats_get_next_player(int cur_player)
1199 // if we're at the end of the list
1200 if(cur_player == (MAX_PLAYERS - 1)){
1204 // find the next player
1205 for(idx=cur_player+1;idx<MAX_PLAYERS;idx++){
1207 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].tracker_player_id != -1) && !(Net_players[idx].flags & NETINFO_FLAG_MT_GET_FAILED) ){
1212 // couldn't find one
1216 // verify that there are no duplicate tracker id's to this one
1217 void multi_fs_tracker_check_dup(int tracker_id,int player_index)
1221 // compare against all players except the passed player_index
1222 for(idx=0;idx<MAX_PLAYERS;idx++){
1223 if(idx == player_index){
1227 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].tracker_player_id != -1)){
1228 SDL_assert(Net_players[idx].tracker_player_id != tracker_id);
1233 // verify that there are no duplicate pilot callsigns
1234 void multi_fs_tracker_check_dup_callsign(net_player *player,int player_index)
1238 // compare against all players except the passed player_index
1239 for(idx=0;idx<MAX_PLAYERS;idx++){
1240 if(idx == player_index){
1244 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].tracker_player_id != -1)){
1245 SDL_assert(strcmp(player->player->callsign,Net_players[idx].player->callsign));
1250 // return an MVALID_STATUS_* constant
1251 int multi_fs_tracker_validate_mission_std()
1255 // wait for a response from the tracker
1257 ret_val = ValidateMission(NULL);
1258 } while(ret_val == 0);
1260 // report on the results
1264 std_destroy_gen_dialog();
1265 return MVALID_STATUS_UNKNOWN;
1269 std_destroy_gen_dialog();
1270 return MVALID_STATUS_INVALID;
1274 std_destroy_gen_dialog();
1275 return MVALID_STATUS_VALID;
1282 // special return values :
1286 int multi_fs_tracker_validate_mission_normal()
1288 switch(ValidateMission(NULL)){
1306 // return an MVALID_STATUS_* (see multiui.h) value, or -2 if the user has "cancelled"
1307 int multi_fs_tracker_validate_mission(char *filename)
1309 vmt_validate_mission_req_struct mission;
1310 char popup_string[512] = "";
1312 if(!Multi_fs_tracker_inited){
1313 return MVALID_STATUS_UNKNOWN;
1316 // get the checksum of the local file
1317 memset(&mission, 0, sizeof(mission));
1318 SDL_strlcpy(mission.file_name, filename, SDL_arraysize(mission.file_name));
1319 if(!cf_chksum_long(mission.file_name, (uint*)&mission.checksum)){
1320 return MVALID_STATUS_UNKNOWN;
1323 // try and validate the mission
1324 if(ValidateMission(&mission) != 0){
1325 return MVALID_STATUS_UNKNOWN;
1328 // do frames for standalone and non-standalone
1329 if(Game_mode & GM_STANDALONE_SERVER){
1332 // set the filename in the dialog
1333 std_gen_set_text(filename, 2);
1335 // validate the mission
1336 ret_code = multi_fs_tracker_validate_mission_std();
1338 // if the dialog is no longer active, cancel everything
1339 //if(!std_gen_is_active()){
1340 // return MVALID_STATUS_UNKNOWN;
1345 SDL_snprintf(popup_string, SDL_arraysize(popup_string), XSTR("Validating mission %s", 1074), filename);
1348 switch(popup_till_condition(multi_fs_tracker_validate_mission_normal, XSTR("&Cancel", 667), popup_string)){
1351 // bash some API values here so that next time we try and verify, everything works
1352 extern int MissionValidState;
1353 MissionValidState = VALID_STATE_IDLE;
1358 return MVALID_STATUS_UNKNOWN;
1362 return MVALID_STATUS_INVALID;
1366 return MVALID_STATUS_VALID;
1370 return MVALID_STATUS_UNKNOWN;
1373 // report on the results of the stats store procedure
1374 void multi_fs_tracker_report_stats_results()
1379 // tell everyone stats store is complete
1380 SDL_strlcpy(str, XSTR("<PXO stats store process complete>", 1001), SDL_arraysize(str));
1381 send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL, NULL, 1);
1382 multi_display_chat_msg(str, 0, 0);
1386 for(idx=0; idx<MAX_PLAYERS; idx++){
1387 // for all players who we care about
1388 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1389 // if the stats get or send failed for any player, report as such
1390 if(((Net_players[idx].tracker_player_id <= 0) || (Net_players[idx].flags & NETINFO_FLAG_MT_GET_FAILED) || (Net_players[idx].flags & NETINFO_FLAG_MT_SEND_FAILED) || !(Net_players[idx].flags & NETINFO_FLAG_MT_DONE)) && (Net_players[idx].player != NULL)){
1391 SDL_snprintf(str, SDL_arraysize(str), XSTR("<PXO stats store failed for player %s>", 1002), Net_players[idx].player->callsign);
1392 send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL, NULL, 1);
1394 multi_display_chat_msg(str, 0, 0);
1401 // return an MSW_STATUS_* constant
1402 int multi_fs_tracker_validate_sw_std()
1406 // wait for a response from the tracker
1408 ret_val = ValidateSquadWar(NULL, &Multi_tracker_sw_response);
1409 } while(ret_val == 0);
1411 // report on the results
1415 return MVALID_STATUS_UNKNOWN;
1419 return MVALID_STATUS_INVALID;
1423 return MVALID_STATUS_VALID;
1426 return MVALID_STATUS_UNKNOWN;
1429 // special return values :
1433 int multi_fs_tracker_validate_sw_normal()
1435 switch(ValidateSquadWar(NULL, &Multi_tracker_sw_response)){
1453 #define STUFF_SW_RESPONSE(_c, _len) do {\
1454 SDL_strlcpy(_c, "", _len);\
1457 for(_idx=0; _idx<MAX_SQUAD_RESPONSE_LEN; _idx++){\
1458 if(Multi_tracker_sw_response.reason[_idx] == '\0'){\
1464 SDL_strlcpy(_c, Multi_tracker_sw_response.reason, _len);\
1468 // return an MSW_STATUS_* value
1469 int multi_fs_tracker_validate_sw(squad_war_request *sw_req, char *bad_reply, const int max_reply_len)
1471 char popup_string[512] = "";
1473 if(!Multi_fs_tracker_inited){
1474 return MSW_STATUS_UNKNOWN;
1477 // zero the response
1478 memset(&Multi_tracker_sw_response, 0, sizeof(Multi_tracker_sw_response));
1480 // try and validate the mission
1481 if(ValidateSquadWar(sw_req, &Multi_tracker_sw_response) != 0){
1482 SDL_strlcpy(bad_reply, "Error sending request for Squad War validation", max_reply_len);
1484 return MSW_STATUS_UNKNOWN;
1487 // do frames for standalone and non-standalone
1488 if(Game_mode & GM_STANDALONE_SERVER){
1491 // validate the mission
1492 ret_code = multi_fs_tracker_validate_sw_std();
1494 // copy the return code
1495 STUFF_SW_RESPONSE(bad_reply, max_reply_len);
1499 SDL_strlcpy(popup_string, XSTR("Validating squad war", 1075), SDL_arraysize(popup_string));
1502 switch(popup_till_condition(multi_fs_tracker_validate_sw_normal, XSTR("&Cancel", 645), popup_string)){
1506 // bash some API values here so that next time we try and verify, everything works
1507 extern int SquadWarValidState;
1508 SquadWarValidState = VALID_STATE_IDLE;
1510 // copy the return code
1511 STUFF_SW_RESPONSE(bad_reply, max_reply_len);
1516 // copy the return code
1517 SDL_strlcpy(bad_reply, "Timeout", max_reply_len);
1518 return MSW_STATUS_UNKNOWN;
1522 // copy the return code
1523 STUFF_SW_RESPONSE(bad_reply, max_reply_len);
1524 return MSW_STATUS_INVALID;
1528 // copy the return code
1529 STUFF_SW_RESPONSE(bad_reply, max_reply_len);
1530 return MSW_STATUS_VALID;
1534 SDL_strlcpy(bad_reply, "Unknown error", max_reply_len);
1535 return MSW_STATUS_UNKNOWN;
1538 // popup do function
1539 // -3 Error -- Called with NULL, but no request is waiting
1540 // -2 Error -- Already sending data (hasn't timed out yet)
1541 // -1 Timeout trying to send pilot data
1543 // 1 Data succesfully sent
1544 // 2 Send Cancelled (data may still have been written already, we just haven't been ACK'd yet)
1545 // 3 Pilot not written (for some reason)
1547 int multi_fs_tracker_store_sw_do()
1549 switch(SendSWData(NULL, &Multi_tracker_sw_response)){
1567 // store the results of a squad war mission on PXO, return 1 on success
1568 int multi_fs_tracker_store_sw(squad_war_result *sw_res, char *bad_reply, const int max_reply_len)
1570 char popup_string[512] = "";
1572 // clear any old requests
1573 SendSWData((squad_war_result*)0xffffffff, NULL);
1575 // send this new request
1576 SendSWData(sw_res, &Multi_tracker_sw_response);
1579 if(Game_mode & GM_STANDALONE_SERVER){
1582 ret_code = SendSWData(NULL, &Multi_tracker_sw_response);
1583 } while(ret_code == 0);
1592 SDL_strlcpy(popup_string, XSTR("Storing SquadWar results", 1078), SDL_arraysize(popup_string));
1594 // wait for a response
1595 if(popup_till_condition(multi_fs_tracker_store_sw_do, XSTR("&Cancel", 645), popup_string) == 10){