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 memset(Multi_tracker_id_string,0,255);
446 strcpy(vir.login,Multi_tracker_login);
447 strcpy(vir.password,Multi_tracker_passwd);
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 strcpy(Multi_tracker_game_data.game_name, Netgame.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 strcpy(Multi_tracker_game_data.channel,Multi_fs_tracker_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 strcpy(filter.channel,Multi_fs_tracker_filter);
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 memset(Multi_tracker_game_data.mission_name, 0, MAX_FREESPACE_MISSION_NAME_LEN);
793 strcpy(Multi_tracker_game_data.mission_name, ng->name);
796 ml_string(NOX("Server updating netgame info for Game Tracker"));
799 // if we're currently busy performing some tracker operation (ie, you should wait or not)
800 int multi_fs_tracker_busy()
802 return Multi_fs_tracker_busy;
806 // -----------------------------------------------------------------------------------
807 // FREESPACE MASTER TRACKER FORWARD DEFINITIONS
810 // used with popup_till_condition() for validating freespace pilots
811 int multi_fs_validate_process()
813 // should never be here if this is not true
814 SDL_assert(Multi_fs_tracker_inited);
816 PSNET_TOP_LAYER_PROCESS();
818 // if we're still in player validation mode
819 if(Multi_validate_mode == 0){
820 switch(ValidateUser(NULL,NULL)){
821 // timeout on waiting for response
823 return MT_VALIDATE_TIMEOUT;
827 // set tracker id to -1
828 strcpy(Multi_tracker_id_string,"-1");
829 Multi_tracker_id = -1;
830 return MT_VALIDATE_FAIL;
834 return MT_VALIDATE_NOT_DONE;
838 // now we need to try and receive stats
840 // mark me as being valid
841 Multi_tracker_player_is_valid = 1;
843 // change the popup text
844 popup_change_text(XSTR("Attempting to get pilot stats ...",679));
846 // get my tracker id#
847 Multi_tracker_id = atoi(Multi_tracker_id_string);
848 SDL_assert(Multi_tracker_id != -1);
850 GetFSPilotData((vmt_freespace2_struct*)0xffffffff,NULL,NULL,0);
851 GetFSPilotData(&Multi_tracker_fs_pilot,Player->callsign,Multi_tracker_id_string,1);
854 Multi_validate_mode = 1;
855 return MT_VALIDATE_NOT_DONE;
861 switch(GetFSPilotData(NULL,NULL,NULL,0)){
864 return MT_VALIDATE_TIMEOUT;
868 return MT_VALIDATE_NOT_DONE;
872 return MT_VALIDATE_SUCCEED;
876 return MT_VALIDATE_FAIL;
880 // we're not done yet - probably should never get here
881 return MT_VALIDATE_NOT_DONE;
884 // used with popup_till_condition() for storing player stats at the end of a freespace game
885 int multi_fs_store_stats_do()
887 char tracker_id_string[512];
888 char popup_text[100];
890 SDL_assert(Multi_fs_tracker_inited);
892 PSNET_TOP_LAYER_PROCESS();
894 switch(Multi_store_stats_mode){
895 // get stats for all players
896 case MT_STORE_STATS_VALIDATE :
897 Multi_store_stats_mode = MT_STORE_STATS_GET_STATS;
900 case MT_STORE_STATS_GET_STATS:
901 // if we need to get the next player
902 if(Multi_store_stats_player_flag){
903 Multi_store_stats_player_index = multi_fs_store_stats_get_next_player(Multi_store_stats_player_index);
905 // if it returns < 0 we're done with all players and should move onto the next stage (applying mission stats)
906 if(Multi_store_stats_player_index < 0){
907 Multi_store_stats_mode = MT_STORE_STATS_ACCEPT;
908 return MT_STATS_NOT_DONE;
911 // unset this flag so we process the request
912 Multi_store_stats_player_flag = 0;
914 // fill out the information request
915 memset(tracker_id_string,0,512);
916 SDL_assert(Net_players[Multi_store_stats_player_index].tracker_player_id > 0);
918 // verify that there are no duplicate tracker id's to this one
919 multi_fs_tracker_check_dup(Net_players[Multi_store_stats_player_index].tracker_player_id,Multi_store_stats_player_index);
920 multi_fs_tracker_check_dup_callsign(&Net_players[Multi_store_stats_player_index],Multi_store_stats_player_index);
922 sprintf(tracker_id_string,"%d",Net_players[Multi_store_stats_player_index].tracker_player_id);
923 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = -1;
924 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = 0;
926 // send the request itself
927 GetFSPilotData((vmt_freespace2_struct*)0xffffffff, NULL, NULL,0);
928 memset(&Multi_store_stats_stats, 0, sizeof(vmt_freespace2_struct));
929 if(GetFSPilotData(&Multi_store_stats_stats, Net_players[Multi_store_stats_player_index].player->callsign,tracker_id_string,1) != 0){
932 // move onto the next player
933 Multi_store_stats_player_flag = 1;
934 return MT_STATS_NOT_DONE;
937 // set the popup text
938 if(!(Game_mode & GM_STANDALONE_SERVER)){
939 memset(popup_text,0,100);
940 sprintf(popup_text,XSTR("Getting player stats for %s...\n",680),Net_players[Multi_store_stats_player_index].player->callsign);
941 popup_change_text(popup_text);
943 return MT_STATS_NOT_DONE;
946 // process the request
947 switch(GetFSPilotData(NULL,NULL,NULL,0)){
950 // copy his stats, then flag him as done so we move onto the next guys
951 multi_stats_tracker_to_fs(&Multi_store_stats_stats,&Net_players[Multi_store_stats_player_index].player->stats);
953 // make sure we apply his mission stats now
954 scoring_do_accept(&Net_players[Multi_store_stats_player_index].player->stats);
958 // debug code to check for bogus stats
959 scoring_struct *ssp = &(Net_players[Multi_store_stats_player_index].player->stats);
960 vmt_freespace2_struct *vmt = &Multi_store_stats_stats;
962 if ( (ssp->missions_flown < vmt->missions_flown) || (ssp->flight_time < ssp->flight_time) || (ssp->kill_count < vmt->kill_count) ) {
968 // flag him as being completed
969 Multi_store_stats_player_flag = 1;
971 // also store this last security value so we can properly update him
972 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = Multi_store_stats_stats.security;
973 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = Multi_store_stats_stats.checksum;
981 case 3: case -2: case 2: case -3: case -1:
982 // this shouldn't be happening under most conditions. For debugging....
985 // flag him as done so we move onto the next guy
986 Multi_store_stats_player_flag = 1;
987 Net_players[Multi_store_stats_player_index].s_info.tracker_security_last = -1;
988 Net_players[Multi_store_stats_player_index].s_info.tracker_checksum = 0;
990 // mark down that the stats get for him failed
991 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_GET_FAILED;
992 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
997 // update all stats for all players locally and on client machines
998 case MT_STORE_STATS_ACCEPT :
999 // tell everyone to save their stats
1000 send_store_stats_packet(1);
1002 // reset status flags and indices
1003 Multi_store_stats_player_index = -1;
1004 Multi_store_stats_player_flag = 1;
1006 Multi_store_stats_mode = MT_STORE_STATS_SEND_STATS;
1009 // send stats to the tracker
1010 case MT_STORE_STATS_SEND_STATS:
1011 // if we need to get the next player
1012 if(Multi_store_stats_player_flag){
1013 Multi_store_stats_player_index = multi_fs_store_stats_get_next_player(Multi_store_stats_player_index);
1015 // if it returns < 0 we need to move onto the next player
1016 if(Multi_store_stats_player_index < 0){
1017 return MT_STATS_SUCCEED;
1020 Multi_store_stats_player_flag = 0;
1022 // fill in the information
1023 memset(&Multi_store_stats_stats,0,sizeof(vmt_freespace2_struct));
1025 SDL_assert(Net_players[Multi_store_stats_player_index].tracker_player_id > 0);
1027 // verify that there are no duplicate tracker id's to this one
1028 multi_fs_tracker_check_dup(Net_players[Multi_store_stats_player_index].tracker_player_id,Multi_store_stats_player_index);
1029 multi_fs_tracker_check_dup_callsign(&Net_players[Multi_store_stats_player_index],Multi_store_stats_player_index);
1030 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);
1032 Multi_store_stats_stats.security = Net_players[Multi_store_stats_player_index].s_info.tracker_security_last;
1034 // SDL_assert(Net_players[Multi_store_stats_player_index].s_info.tracker_checksum != 0);
1035 Multi_store_stats_stats.checksum = Net_players[Multi_store_stats_player_index].s_info.tracker_checksum;
1038 SendFSPilotData((vmt_freespace2_struct*)0xffffffff);
1039 if(SendFSPilotData(&Multi_store_stats_stats) != 0){
1042 // failed to send, try another player the next time around
1043 Multi_store_stats_player_flag = 1;
1044 return MT_STATS_NOT_DONE;
1047 // set the popup text
1048 if(!(Game_mode & GM_STANDALONE_SERVER)){
1049 memset(popup_text,0,100);
1050 sprintf(popup_text,XSTR("Updating player stats for %s...\n",681),Net_players[Multi_store_stats_player_index].player->callsign);
1051 popup_change_text(popup_text);
1054 return MT_STATS_NOT_DONE;
1057 // otherwise check on his status
1058 switch(SendFSPilotData(NULL)){
1060 case -1: case -2: case -3: case 2: case 3:
1061 // flag him as done so we move onto the next guy
1062 Multi_store_stats_player_flag = 1;
1064 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_SEND_FAILED;
1065 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
1070 // flag him as done so we move onto the next guys
1071 Multi_store_stats_player_flag = 1;
1072 Net_players[Multi_store_stats_player_index].flags |= NETINFO_FLAG_MT_DONE;
1079 // return not done yet
1080 return MT_STATS_NOT_DONE;
1083 // copy a freespace stats struct to a tracker-freespace stats struct
1084 void multi_stats_fs_to_tracker(scoring_struct *fs, vmt_freespace2_struct *vmt, player *pl, int tracker_id)
1086 char tracker_id_string[256];
1088 // tracker id string
1089 memset(vmt->tracker_id,0,TRACKER_ID_LEN);
1090 memset(tracker_id_string, 0, 256);
1091 sprintf(tracker_id_string,"%d",tracker_id);
1092 strncpy(vmt->tracker_id, tracker_id_string, TRACKER_ID_LEN);
1095 memset(vmt->pilot_name,0,PILOT_NAME_LEN);
1096 strcpy(vmt->pilot_name,pl->callsign);
1098 // score, rank and medals
1099 vmt->score = fs->score;
1100 vmt->rank = fs->rank;
1101 SDL_assert(MAX_FS2_MEDALS == NUM_MEDALS);
1102 memcpy(vmt->medals, fs->medals, sizeof(int) * MAX_FS2_MEDALS);
1103 vmt->num_medals = MAX_FS2_MEDALS;
1105 // kills and assists
1106 SDL_assert(MAX_FS2_SHIP_TYPES == MAX_SHIP_TYPES);
1107 memcpy(vmt->kills, fs->kills, sizeof(ushort) * MAX_FS2_SHIP_TYPES);
1108 vmt->assists = fs->assists;
1109 vmt->kill_count = fs->kill_count;
1110 vmt->kill_count_ok = fs->kill_count_ok;
1111 vmt->num_ship_types = MAX_FS2_SHIP_TYPES;
1114 vmt->p_shots_fired = fs->p_shots_fired;
1115 vmt->s_shots_fired = fs->s_shots_fired;
1116 vmt->p_shots_hit = fs->p_shots_hit;
1117 vmt->s_shots_hit = fs->s_shots_hit;
1118 vmt->p_bonehead_hits = fs->p_bonehead_hits;
1119 vmt->s_bonehead_hits = fs->s_bonehead_hits;
1120 vmt->bonehead_kills = fs->bonehead_kills;
1122 // missions flown information
1123 vmt->missions_flown = fs->missions_flown;
1124 vmt->flight_time = fs->flight_time;
1125 vmt->last_flown = (unsigned int)fs->last_flown;
1128 // copy a tracker-freespace stats struct to a freespace stats struct
1129 void multi_stats_tracker_to_fs(vmt_freespace2_struct *vmt,scoring_struct *fs)
1131 int num_medals, num_ship_types;
1133 // score, rank and medals
1134 fs->score = vmt->score;
1135 fs->rank = vmt->rank;
1136 num_medals = vmt->num_medals;
1137 if(num_medals > NUM_MEDALS){
1139 num_medals = NUM_MEDALS;
1141 memset(fs->medals, 0, sizeof(int) * NUM_MEDALS);
1142 memcpy(fs->medals, vmt->medals, sizeof(int) * num_medals);
1144 // kills and assists
1145 num_ship_types = vmt->num_ship_types;
1146 if(num_ship_types > MAX_SHIP_TYPES){
1148 num_ship_types = MAX_SHIP_TYPES;
1150 memset(fs->kills, 0, sizeof(ushort) * MAX_SHIP_TYPES);
1151 memcpy(fs->kills, vmt->kills, sizeof(ushort) * num_ship_types);
1152 fs->assists = vmt->assists;
1153 fs->kill_count = vmt->kill_count;
1154 fs->kill_count_ok = vmt->kill_count_ok;
1157 fs->p_shots_fired = vmt->p_shots_fired;
1158 fs->s_shots_fired = vmt->s_shots_fired;
1159 fs->p_shots_hit = vmt->p_shots_hit;
1160 fs->s_shots_hit = vmt->s_shots_hit;
1161 fs->p_bonehead_hits = vmt->p_bonehead_hits;
1162 fs->s_bonehead_hits = vmt->s_bonehead_hits;
1163 fs->bonehead_kills = vmt->bonehead_kills;
1165 // missions flown information
1166 fs->missions_flown = vmt->missions_flown;
1167 fs->flight_time = vmt->flight_time;
1168 fs->last_flown = (fs_time_t)vmt->last_flown;
1169 if(fs->last_flown < 0){
1174 // process an incoming active game item
1175 void multi_fs_tracker_process_game_item(game_list *gl)
1180 for(idx=0;idx<MAX_GAME_LISTS_PER_PACKET;idx++){
1181 // skip null server addresses
1182 if(gl->game_server[idx] == 0){
1186 // package up the game information
1187 memset(&ag,0,sizeof(active_game));
1188 strcpy(ag.name,gl->game_name[idx]);
1189 memcpy(&ag.server_addr.addr[0],&gl->game_server[idx],sizeof(unsigned long));
1190 ag.server_addr.type = NET_TCP;
1191 ag.server_addr.port = DEFAULT_GAME_PORT;
1193 // add to the active game list
1194 // multi_update_active_games(&ag);
1196 // query this server
1197 send_server_query(&ag.server_addr);
1201 int multi_fs_store_stats_get_next_player(int cur_player)
1205 // if we're at the end of the list
1206 if(cur_player == (MAX_PLAYERS - 1)){
1210 // find the next player
1211 for(idx=cur_player+1;idx<MAX_PLAYERS;idx++){
1213 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) ){
1218 // couldn't find one
1222 // verify that there are no duplicate tracker id's to this one
1223 void multi_fs_tracker_check_dup(int tracker_id,int player_index)
1227 // compare against all players except the passed player_index
1228 for(idx=0;idx<MAX_PLAYERS;idx++){
1229 if(idx == player_index){
1233 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].tracker_player_id != -1)){
1234 SDL_assert(Net_players[idx].tracker_player_id != tracker_id);
1239 // verify that there are no duplicate pilot callsigns
1240 void multi_fs_tracker_check_dup_callsign(net_player *player,int player_index)
1244 // compare against all players except the passed player_index
1245 for(idx=0;idx<MAX_PLAYERS;idx++){
1246 if(idx == player_index){
1250 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].tracker_player_id != -1)){
1251 SDL_assert(strcmp(player->player->callsign,Net_players[idx].player->callsign));
1256 // return an MVALID_STATUS_* constant
1257 int multi_fs_tracker_validate_mission_std()
1261 // wait for a response from the tracker
1263 ret_val = ValidateMission(NULL);
1264 } while(ret_val == 0);
1266 // report on the results
1270 std_destroy_gen_dialog();
1271 return MVALID_STATUS_UNKNOWN;
1275 std_destroy_gen_dialog();
1276 return MVALID_STATUS_INVALID;
1280 std_destroy_gen_dialog();
1281 return MVALID_STATUS_VALID;
1288 // special return values :
1292 int multi_fs_tracker_validate_mission_normal()
1294 switch(ValidateMission(NULL)){
1312 // return an MVALID_STATUS_* (see multiui.h) value, or -2 if the user has "cancelled"
1313 int multi_fs_tracker_validate_mission(char *filename)
1315 vmt_validate_mission_req_struct mission;
1316 char popup_string[512] = "";
1318 if(!Multi_fs_tracker_inited){
1319 return MVALID_STATUS_UNKNOWN;
1322 // get the checksum of the local file
1323 memset(&mission, 0, sizeof(mission));
1324 strcpy(mission.file_name, filename);
1325 if(!cf_chksum_long(mission.file_name, (uint*)&mission.checksum)){
1326 return MVALID_STATUS_UNKNOWN;
1329 // try and validate the mission
1330 if(ValidateMission(&mission) != 0){
1331 return MVALID_STATUS_UNKNOWN;
1334 // do frames for standalone and non-standalone
1335 if(Game_mode & GM_STANDALONE_SERVER){
1338 // set the filename in the dialog
1339 std_gen_set_text(filename, 2);
1341 // validate the mission
1342 ret_code = multi_fs_tracker_validate_mission_std();
1344 // if the dialog is no longer active, cancel everything
1345 //if(!std_gen_is_active()){
1346 // return MVALID_STATUS_UNKNOWN;
1351 memset(popup_string, 0, 512);
1352 sprintf(popup_string, XSTR("Validating mission %s", 1074),filename);
1355 switch(popup_till_condition(multi_fs_tracker_validate_mission_normal, XSTR("&Cancel", 667), popup_string)){
1358 // bash some API values here so that next time we try and verify, everything works
1359 extern int MissionValidState;
1360 MissionValidState = VALID_STATE_IDLE;
1365 return MVALID_STATUS_UNKNOWN;
1369 return MVALID_STATUS_INVALID;
1373 return MVALID_STATUS_VALID;
1377 return MVALID_STATUS_UNKNOWN;
1380 // report on the results of the stats store procedure
1381 void multi_fs_tracker_report_stats_results()
1386 // tell everyone stats store is complete
1387 memset(str, 0, 512);
1388 strcpy(str, XSTR("<PXO stats store process complete>", 1001));
1389 send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL, NULL, 1);
1390 multi_display_chat_msg(str, 0, 0);
1394 for(idx=0; idx<MAX_PLAYERS; idx++){
1395 // for all players who we care about
1396 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx])){
1397 // if the stats get or send failed for any player, report as such
1398 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)){
1399 memset(str, 0, 512);
1400 sprintf(str, XSTR("<PXO stats store failed for player %s>", 1002), Net_players[idx].player->callsign);
1401 send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL, NULL, 1);
1403 multi_display_chat_msg(str, 0, 0);
1410 // return an MSW_STATUS_* constant
1411 int multi_fs_tracker_validate_sw_std()
1415 // wait for a response from the tracker
1417 ret_val = ValidateSquadWar(NULL, &Multi_tracker_sw_response);
1418 } while(ret_val == 0);
1420 // report on the results
1424 return MVALID_STATUS_UNKNOWN;
1428 return MVALID_STATUS_INVALID;
1432 return MVALID_STATUS_VALID;
1435 return MVALID_STATUS_UNKNOWN;
1438 // special return values :
1442 int multi_fs_tracker_validate_sw_normal()
1444 switch(ValidateSquadWar(NULL, &Multi_tracker_sw_response)){
1462 #define STUFF_SW_RESPONSE(_c) do {\
1466 for(_idx=0; _idx<MAX_SQUAD_RESPONSE_LEN; _idx++){\
1467 if(Multi_tracker_sw_response.reason[_idx] == '\0'){\
1473 strcpy(_c, Multi_tracker_sw_response.reason);\
1477 // return an MSW_STATUS_* value
1478 int multi_fs_tracker_validate_sw(squad_war_request *sw_req, char *bad_reply)
1480 char popup_string[512] = "";
1482 if(!Multi_fs_tracker_inited){
1483 return MSW_STATUS_UNKNOWN;
1486 // zero the response
1487 memset(&Multi_tracker_sw_response, 0, sizeof(Multi_tracker_sw_response));
1489 // try and validate the mission
1490 if(ValidateSquadWar(sw_req, &Multi_tracker_sw_response) != 0){
1491 sprintf(bad_reply, "Error sending request for Squad War validation");
1493 return MSW_STATUS_UNKNOWN;
1496 // do frames for standalone and non-standalone
1497 if(Game_mode & GM_STANDALONE_SERVER){
1500 // validate the mission
1501 ret_code = multi_fs_tracker_validate_sw_std();
1503 // copy the return code
1504 STUFF_SW_RESPONSE(bad_reply);
1508 SDL_strlcpy(popup_string, XSTR("Validating squad war", 1075), sizeof(popup_string));
1511 switch(popup_till_condition(multi_fs_tracker_validate_sw_normal, XSTR("&Cancel", 645), popup_string)){
1515 // bash some API values here so that next time we try and verify, everything works
1516 extern int SquadWarValidState;
1517 SquadWarValidState = VALID_STATE_IDLE;
1519 // copy the return code
1520 STUFF_SW_RESPONSE(bad_reply);
1525 // copy the return code
1526 sprintf(bad_reply, "Timeout");
1527 return MSW_STATUS_UNKNOWN;
1531 // copy the return code
1532 STUFF_SW_RESPONSE(bad_reply);
1533 return MSW_STATUS_INVALID;
1537 // copy the return code
1538 STUFF_SW_RESPONSE(bad_reply);
1539 return MSW_STATUS_VALID;
1543 sprintf(bad_reply, "Unknown error");
1544 return MSW_STATUS_UNKNOWN;
1547 // popup do function
1548 // -3 Error -- Called with NULL, but no request is waiting
1549 // -2 Error -- Already sending data (hasn't timed out yet)
1550 // -1 Timeout trying to send pilot data
1552 // 1 Data succesfully sent
1553 // 2 Send Cancelled (data may still have been written already, we just haven't been ACK'd yet)
1554 // 3 Pilot not written (for some reason)
1556 int multi_fs_tracker_store_sw_do()
1558 switch(SendSWData(NULL, &Multi_tracker_sw_response)){
1576 // store the results of a squad war mission on PXO, return 1 on success
1577 int multi_fs_tracker_store_sw(squad_war_result *sw_res, char *bad_reply)
1579 char popup_string[512] = "";
1581 // clear any old requests
1582 SendSWData((squad_war_result*)0xffffffff, NULL);
1584 // send this new request
1585 SendSWData(sw_res, &Multi_tracker_sw_response);
1588 if(Game_mode & GM_STANDALONE_SERVER){
1591 ret_code = SendSWData(NULL, &Multi_tracker_sw_response);
1592 } while(ret_code == 0);
1601 SDL_strlcpy(popup_string, XSTR("Storing SquadWar results", 1078), sizeof(popup_string));
1603 // wait for a response
1604 if(popup_till_condition(multi_fs_tracker_store_sw_do, XSTR("&Cancel", 645), popup_string) == 10){