CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

STATS.CPP (23371B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 
     17 /***********************************************************************************************
     18  ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Command & Conquer                                            *
     22  *                                                                                             *
     23  *                    File Name : WINSTUB.CPP                                                  *
     24  *                                                                                             *
     25  *                   Programmer : Steve Tall                                                   *
     26  *                                                                                             *
     27  *                   Start Date : 05/29/1996                                                   *
     28  *                                                                                             *
     29  *                  Last Update : May 29th 1996 [ST]                                           *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Overview:                                                                                   *
     33  *  Internet game statistics to collect and upload to the server                               *
     34  *                                                                                             *
     35  *                                                                                             *
     36  *---------------------------------------------------------------------------------------------*
     37  *                                                                                             *
     38  * Functions:                                                                                  *
     39  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     40 
     41 #include	"function.h"
     42 #include "tcpip.h"
     43 #include "packet.h"
     44 #include "ccdde.h"
     45 
     46 #define FIELD_PACKET_TYPE					"TYPE"
     47 #define FIELD_GAME_ID							"IDNO"
     48 #define FIELD_START_CREDITS					"CRED"
     49 #define FIELD_BASES							"BASE"
     50 #define FIELD_TIBERIUM						"TIBR"
     51 #define FIELD_CRATES							"CRAT"
     52 #define FIELD_AI_PLAYERS						"AIPL"
     53 #define FIELD_CAPTURE_THE_FLAG				"FLAG"
     54 #define FIELD_START_UNIT_COUNT				"UNIT"
     55 #define FIELD_TECH_LEVEL						"TECH"
     56 #define FIELD_SCENARIO						"SCEN"
     57 #define FIELD_COMPLETION						"CMPL"
     58 #define FIELD_START_TIME						"TIME"
     59 #define FIELD_GAME_DURATION					"DURA"
     60 #define FIELD_FRAME_RATE						"AFPS"
     61 #define FIELD_SPEED_SETTING					"SPED"
     62 #define FIELD_GAME_VERSION					"VERS"
     63 #define FIELD_GAME_BUILD_DATE				"DATE"
     64 #define FIELD_COVERT_PRESENT				"COVT"
     65 #define FIELD_CPU_TYPE						"PROC"
     66 #define FIELD_MEMORY							"MEMO"
     67 #define FIELD_VIDEO_MEMORY					"VIDM"
     68 #define FIELD_PLAYER1_HANDLE				"NAM1"
     69 #define FIELD_PLAYER2_HANDLE				"NAM2"
     70 #define FIELD_PLAYER1_TEAM					"SID1"
     71 #define FIELD_PLAYER2_TEAM					"SID2"
     72 #define FIELD_PLAYER1_COLOR					"COL1"
     73 #define FIELD_PLAYER2_COLOR					"COL2"
     74 #define FIELD_PLAYER1_CREDITS				"CRD1"
     75 #define FIELD_PLAYER2_CREDITS				"CRD2"
     76 
     77 #define FIELD_PLAYER1_UNITS_LEFT			"UNL1"
     78 #define FIELD_PLAYER2_UNITS_LEFT			"UNL2"
     79 #define FIELD_PLAYER1_INFANTRY_LEFT		"INL1"
     80 #define FIELD_PLAYER2_INFANTRY_LEFT		"INL2"
     81 #define FIELD_PLAYER1_PLANES_LEFT			"PLL1"
     82 #define FIELD_PLAYER2_PLANES_LEFT			"PLL2"
     83 #define FIELD_PLAYER1_BUILDINGS_LEFT		"BLL1"
     84 #define FIELD_PLAYER2_BUILDINGS_LEFT		"BLL2"
     85 
     86 #define FIELD_PLAYER1_UNITS_BOUGHT		"UNB1"
     87 #define FIELD_PLAYER2_UNITS_BOUGHT		"UNB2"
     88 #define FIELD_PLAYER1_INFANTRY_BOUGHT	"INB1"
     89 #define FIELD_PLAYER2_INFANTRY_BOUGHT	"INB2"
     90 #define FIELD_PLAYER1_PLANES_BOUGHT		"PLB1"
     91 #define FIELD_PLAYER2_PLANES_BOUGHT		"PLB2"
     92 #define FIELD_PLAYER1_BUILDINGS_BOUGHT	"BLB1"
     93 #define FIELD_PLAYER2_BUILDINGS_BOUGHT	"BLB2"
     94 
     95 #define FIELD_PLAYER1_UNITS_KILLED		"UNK1"
     96 #define FIELD_PLAYER2_UNITS_KILLED		"UNK2"
     97 #define FIELD_PLAYER1_INFANTRY_KILLED	"INK1"
     98 #define FIELD_PLAYER2_INFANTRY_KILLED	"INK2"
     99 #define FIELD_PLAYER1_PLANES_KILLED		"PLK1"
    100 #define FIELD_PLAYER2_PLANES_KILLED		"PLK2"
    101 #define FIELD_PLAYER1_BUILDINGS_KILLED	"BLK1"
    102 #define FIELD_PLAYER2_BUILDINGS_KILLED	"BLK2"
    103 
    104 #define FIELD_PLAYER1_BUILDINGS_CAPTURED "BLC1"
    105 #define FIELD_PLAYER2_BUILDINGS_CAPTURED "BLC2"
    106 
    107 #define FIELD_PLAYER1_CRATES_FOUND		"CRA1"
    108 #define FIELD_PLAYER2_CRATES_FOUND		"CRA2"
    109 #define FIELD_PLAYER1_HARVESTED			"HRV1"
    110 #define FIELD_PLAYER2_HARVESTED			"HRV2"
    111 
    112 
    113 #define	PACKET_TYPE_HOST_GAME_INFO		(unsigned char) 50
    114 #define	PACKET_TYPE_GUEST_GAME_INFO	(unsigned char) 51
    115 
    116 enum {
    117 	COMPLETION_CONNECTION_LOST,
    118 	COMPLETION_PLAYER_1_WON,
    119 	COMPLETION_PLAYER_1_WON_BY_RESIGNATION,
    120 	COMPLETION_PLAYER_1_WON_BY_DISCONNECTION,
    121 	COMPLETION_PLAYER_2_WON,
    122 	COMPLETION_PLAYER_2_WON_BY_RESIGNATION,
    123 	COMPLETION_PLAYER_2_WON_BY_DISCONNECTION
    124 };
    125 
    126 
    127 extern unsigned long 	PlanetWestwoodGameID;
    128 extern HINSTANCE		ProgramInstance;
    129 extern unsigned long 	PlanetWestwoodStartTime;
    130 
    131 extern "C" char	CPUType;
    132 
    133 
    134 bool			GameTimerInUse = false;
    135 TimerClass	GameTimer;
    136 long			GameEndTime;
    137 void			*PacketLater = NULL;
    138 
    139 /***********************************************************************************************
    140  * Send_Statistics_To_Server -- sends internet game statistics to the Westeood server          *
    141  *                                                                                             *
    142  *                                                                                             *
    143  *                                                                                             *
    144  * INPUT:    Nothing                                                                           *
    145  *                                                                                             *
    146  * OUTPUT:   Nothing                                                                           *
    147  *                                                                                             *
    148  * WARNINGS: None                                                                              *
    149  *                                                                                             *
    150  * HISTORY:                                                                                    *
    151  *    5/29/96 12:38PM ST : Created                                                             *
    152  *=============================================================================================*/
    153 
    154 void Send_Statistics_Packet(void)
    155 {
    156 //PG_TO_FIX
    157 #if (0)
    158 #ifndef DEMO
    159 
    160 	PacketClass	stats;
    161 	HouseClass	*player;
    162 	static int	packet_size;
    163 	int			index;
    164 	bool			packet_later = false;	// Should the packet be sent later
    165 	void			*packet;
    166 
    167 	static char	field_player_handle[5] 				= { "NAM?" };
    168 	static char	field_player_team[5] 				= { "SID?" };
    169 	static char	field_player_color[5]				= { "COL?" };
    170 	static char field_player_credits[5]				= { "CRD?" };
    171 	static char field_player_units_left[5]			= { "UNL?" };
    172 	static char field_player_infantry_left[5]		= { "INL?" };
    173 	static char field_player_planes_left[5]		= { "PLL?" };
    174 	static char field_player_buildings_left[5]	= { "BLL?" };
    175 	static char field_player_units_bought[5] 		= { "UNB?" };
    176 	static char field_player_infantry_bought[5] 	= { "INB?" };
    177 	static char field_player_planes_bought[5]		= { "PLB?" };
    178 	static char field_player_buildings_bought[5]	= { "BLB?" };
    179 	static char field_player_units_killed[5] 		= { "UNK?" };
    180 	static char field_player_infantry_killed[5] 	= { "INK?" };
    181 	static char field_player_planes_killed[5]		= { "PLK?" };
    182 	static char field_player_buildings_killed[5]	= { "BLK?" };
    183 	static char field_player_buildings_captured[5] = { "BLC?" };
    184 	static char field_player_crates_found[5]		= { "CRA?" };
    185 	static char field_player_harvested[5]			= { "HRV?" };
    186 
    187 	static char *houses[] = {
    188 		"GDI",
    189 		"NOD",
    190 		"NUT",
    191 		"JUR",
    192 		"M01",
    193 		"M02",
    194 		"M03",
    195 		"M04",
    196 		"M05",
    197 		"M06"
    198 	};
    199 
    200 	CCDebugString ("C&C95 - In Send_Statistics_Packet.\n");
    201 
    202 
    203 	if (!PacketLater){
    204 
    205 		CCDebugString ("C&C95 - PacketLater is false.\n");
    206 
    207 
    208 		/*
    209 		** Field to identify this as C&C 95 internet game statistics packet
    210 		*/
    211 		if (Server){
    212 			stats.Add_Field(FIELD_PACKET_TYPE, PACKET_TYPE_HOST_GAME_INFO);
    213 		}else{
    214 			stats.Add_Field(FIELD_PACKET_TYPE, PACKET_TYPE_GUEST_GAME_INFO);
    215 		}
    216 
    217 		/*
    218 		** Game ID. A unique game identifier assigned by WChat.
    219 		*/
    220 		stats.Add_Field(FIELD_GAME_ID, PlanetWestwoodGameID);
    221 
    222 		/*
    223 		** Start credits.
    224 		*/
    225 		stats.Add_Field(FIELD_START_CREDITS, (unsigned long)MPlayerCredits);
    226 
    227 		/*
    228 		** Bases (On/Off)
    229 		*/
    230 		stats.Add_Field(FIELD_BASES, MPlayerBases ? "ON" : "OFF");
    231 
    232 		/*
    233 		** Tiberium (On/Off)
    234 		*/
    235 		stats.Add_Field(FIELD_TIBERIUM, MPlayerTiberium ? "ON" : "OFF");
    236 
    237 		/*
    238 		** Crates (On/Off)
    239 		*/
    240 		stats.Add_Field(FIELD_CRATES, MPlayerGoodies ? "ON" : "OFF");
    241 
    242 		/*
    243 		** AI Players (On/Off/Capture the flag)
    244 		*/
    245 		stats.Add_Field(FIELD_AI_PLAYERS, MPlayerGhosts ? "ON" : "OFF");
    246 		stats.Add_Field(FIELD_CAPTURE_THE_FLAG, Special.IsCaptureTheFlag ? "ON" : "OFF");
    247 
    248 		/*
    249 		** Start unit count
    250 		*/
    251 		stats.Add_Field(FIELD_START_UNIT_COUNT, (unsigned long)MPlayerUnitCount);
    252 
    253 		/*
    254 		** Tech level.
    255 		*/
    256 		stats.Add_Field(FIELD_TECH_LEVEL, (unsigned long)BuildLevel);
    257 
    258 		CCDebugString ("C&C95 - Adding stats field for scenario.\n");
    259 		/*
    260 		** Scenario
    261 		*/
    262 		char fname[128];
    263 		char namebuffer[40];
    264 		char *abuffer = (char *)_ShapeBuffer;
    265 		memset(abuffer, '\0', _ShapeBufferSize);
    266 		sprintf(fname,"%s.INI",ScenarioName);
    267 		CCFileClass fileo;
    268 		fileo.Set_Name (fname);
    269 		fileo.Read(abuffer, _ShapeBufferSize-1);
    270 		fileo.Close();
    271 		WWGetPrivateProfileString("Basic", "Name", "Nulls-Ville", namebuffer, 40, abuffer);
    272 		stats.Add_Field(FIELD_SCENARIO, namebuffer);
    273 		//stats.Add_Field(FIELD_SCENARIO, MPlayerScenarios[ScenarioIdx]);
    274 
    275 
    276 		/*
    277 		** Game completion status.
    278 		**
    279 		**  Connection lost.
    280 		**  Player 1 won
    281 		**  Player 2 won
    282 		**  Player 1 won by resignation
    283 		**  Player 2 won by resignation
    284 		**  Player 1 aborted
    285 		**  Player 2 aborted
    286 		**
    287 		*/
    288 		CCDebugString ("C&C95 - Adding stats field for completion status.\n");
    289 		HouseClass *player1 = HouseClass::As_Pointer(MPlayerHouses[0]);
    290 		HouseClass *player2 = HouseClass::As_Pointer(MPlayerHouses[1]);
    291 
    292 		int completion = -1;
    293 
    294 		if (ConnectionLost){
    295 			completion = COMPLETION_CONNECTION_LOST;
    296 			CCDebugString ("C&C95 - Completion status is connection lost.\n");
    297 		}else{
    298 
    299 			if (player1 && player2){
    300 				if (player1->IGaveUp){
    301 					completion = COMPLETION_PLAYER_2_WON_BY_DISCONNECTION;
    302 					CCDebugString ("C&C95 - Completion status is player 1 disconnected.\n");
    303 				}
    304 
    305 				if (player2->IGaveUp){
    306 					completion = COMPLETION_PLAYER_1_WON_BY_DISCONNECTION;
    307 					CCDebugString ("C&C95 - Completion status is player 2 disconnected.\n");
    308 				}
    309 
    310 
    311 				if (player2->IsDefeated){
    312 					/*
    313 					** Player 1 won. Find out how.
    314 					*/
    315 					completion = COMPLETION_PLAYER_1_WON;
    316 					if (player2->Resigned){
    317 						completion = COMPLETION_PLAYER_1_WON_BY_RESIGNATION;
    318 						CCDebugString ("C&C95 - Completion status is player 2 resigned.\n");
    319 					}else{
    320 						if (player2->IGaveUp){
    321 							completion = COMPLETION_PLAYER_1_WON_BY_DISCONNECTION;
    322 							CCDebugString ("C&C95 - Completion status is player 2 disconnected.\n");
    323 						}
    324 					}
    325 
    326 
    327 				}else{
    328 
    329 					if (player1->IsDefeated){
    330 						/*
    331 						** Player 2 won. Find out how.
    332 						*/
    333 						completion = COMPLETION_PLAYER_2_WON;
    334 						if (player1->Resigned){
    335 							completion = COMPLETION_PLAYER_2_WON_BY_RESIGNATION;
    336 							CCDebugString ("C&C95 - Completion status is player 1 resigned.\n");
    337 						}else{
    338 							if (player1->IGaveUp){
    339 								completion = COMPLETION_PLAYER_2_WON_BY_DISCONNECTION;
    340 								CCDebugString ("C&C95 - Completion status is player 1 disconnected.\n");
    341 							}
    342 						}
    343 					}
    344 				}
    345 			}
    346 		}
    347 
    348 		stats.Add_Field (FIELD_COMPLETION, (char) completion);
    349 
    350 
    351 
    352 
    353 
    354 
    355 		/*
    356 		** Game start time (GMT or Pacific?)
    357 		**
    358 		** Passed from WChat
    359 		*/
    360 		stats.Add_Field (FIELD_START_TIME, (long) PlanetWestwoodStartTime);
    361 
    362 		/*
    363 		** Game duration (seconds).
    364 		*/
    365 		stats.Add_Field (FIELD_GAME_DURATION, (long) GameEndTime/60);
    366 
    367 		/*
    368 		** Avg. frame rate.
    369 		*/
    370 		if (GameEndTime/60 == 0){
    371 			stats.Add_Field (FIELD_FRAME_RATE, 0L );
    372 		}else{
    373 			stats.Add_Field (FIELD_FRAME_RATE, (long) Frame / (GameEndTime/60) );
    374 		}
    375 
    376 
    377 		CCDebugString ("C&C95 - Adding hardware info stats.\n");
    378 		/*
    379 		** CPU type
    380 		*/
    381 		stats.Add_Field (FIELD_CPU_TYPE, (char)CPUType);
    382 
    383 		/*
    384 		** Memory
    385 		*/
    386 		MEMORYSTATUS	mem_info;
    387 		mem_info.dwLength=sizeof(mem_info);
    388 		GlobalMemoryStatus(&mem_info);
    389 		stats.Add_Field (FIELD_MEMORY, (long)mem_info.dwTotalPhys);
    390 
    391 		/*
    392 		** Video memory
    393 		*/
    394 		DDCAPS	video_capabilities;
    395 		long		video_memory;
    396 
    397 		if (DirectDrawObject){
    398 			video_capabilities.dwSize = sizeof (video_capabilities);
    399 			if (DD_OK == DirectDrawObject->GetCaps (&video_capabilities , NULL)){
    400 				video_memory = video_capabilities.dwVidMemTotal;
    401 				video_memory += 1024*1024 -1;
    402 				video_memory &= 0xfff00000;
    403 				stats.Add_Field (FIELD_VIDEO_MEMORY, (long) video_memory);
    404 			}
    405 		}
    406 
    407 		CCDebugString ("C&C95 - Adding game info stats.\n");
    408 		/*
    409 		** Game speed setting.
    410 		*/
    411 		stats.Add_Field (FIELD_SPEED_SETTING, (char)Options.GameSpeed);
    412 
    413 		/*
    414 		** C&C 95 version/build date
    415 		*/
    416 		char	version[128];
    417 		sprintf (version, "%d%s", Version_Number(), VersionText);
    418 		stats.Add_Field (FIELD_GAME_VERSION, version);
    419 
    420 		char path_to_exe[280];
    421 		FILETIME write_time;		//File time is 64 bits
    422 
    423 		GetModuleFileName (ProgramInstance, path_to_exe, 280);
    424 		RawFileClass file;
    425 		file.Set_Name(path_to_exe);
    426 		file.Open();
    427 		HANDLE handle = file.Get_File_Handle();
    428 
    429 		if (handle != INVALID_HANDLE_VALUE){
    430 			if (GetFileTime (handle, NULL, NULL, &write_time)){
    431 				write_time.dwLowDateTime = htonl (write_time.dwLowDateTime);
    432 				write_time.dwHighDateTime = htonl (write_time.dwHighDateTime);
    433 				stats.Add_Field (FIELD_GAME_BUILD_DATE, (void*)&write_time, sizeof (write_time));
    434 			}
    435 		}
    436 
    437 		/*
    438 		** Covert installed? (Yes/No)
    439 		*/
    440 		stats.Add_Field(FIELD_COVERT_PRESENT, (char) Expansion_Present());
    441 
    442 		CCDebugString ("C&C95 - Adding house specific stats.\n");
    443 		/*
    444 		** Build the player specific statistics
    445 		**
    446 		*/
    447 		for (int house = 0 ; house < 2 ; house++){
    448 
    449 			player = HouseClass::As_Pointer(MPlayerHouses[house]);
    450 
    451 			if (player){
    452 				/*
    453 				** Player handle.
    454 				*/
    455 				field_player_handle[3] = '1' + (char)house;
    456 				stats.Add_Field (field_player_handle, (char*) MPlayerNames[house]);
    457 
    458 				/*
    459 				** Player team. (NOD or GDI)
    460 				*/
    461 				field_player_team[3] = '1' + (char)house;
    462 				stats.Add_Field (field_player_team, houses[player->ActLike]);
    463 
    464 				/*
    465 				** Player color
    466 				*/
    467 				field_player_color[3] = '1' + (char)house;
    468 				stats.Add_Field (field_player_color, (unsigned char) (player->Class->House - HOUSE_MULTI1));
    469 
    470 				/*
    471 				** Player end credits.
    472 				*/
    473 				field_player_credits[3] = '1' + (char)house;
    474 				stats.Add_Field (field_player_credits, player->Credits + player->Tiberium);
    475 
    476 				/*
    477 				** Number of each unit/building type built
    478 				*/
    479 				field_player_infantry_bought[3] = '1' + (char)house;
    480 				field_player_units_bought[3] = '1' + (char)house;
    481 				field_player_planes_bought[3] = '1' + (char)house;
    482 				field_player_buildings_bought[3] = '1' + (char)house;
    483 
    484 				player->InfantryTotals->To_Network_Format();
    485 				player->UnitTotals->To_Network_Format();
    486 				player->AircraftTotals->To_Network_Format();
    487 				player->BuildingTotals->To_Network_Format();
    488 
    489 				stats.Add_Field (field_player_infantry_bought, (void*) player->InfantryTotals->Get_All_Totals(), player->InfantryTotals->Get_Unit_Count()*4);
    490 				stats.Add_Field (field_player_units_bought, (void*) player->UnitTotals->Get_All_Totals(), player->UnitTotals->Get_Unit_Count()*4);
    491 				stats.Add_Field (field_player_planes_bought, (void*) player->AircraftTotals->Get_All_Totals(), player->AircraftTotals->Get_Unit_Count()*4);
    492 				stats.Add_Field (field_player_buildings_bought, (void*) player->BuildingTotals->Get_All_Totals(), player->BuildingTotals->Get_Unit_Count()*4);
    493 
    494 				player->InfantryTotals->To_PC_Format();
    495 				player->UnitTotals->To_PC_Format();
    496 				player->AircraftTotals->To_PC_Format();
    497 				player->BuildingTotals->To_PC_Format();
    498 
    499 				/*
    500 				** Clear out the counts and use the space to count up the current number of units/buildings
    501 				*/
    502 				player->InfantryTotals->Clear_Unit_Total();
    503 				player->AircraftTotals->Clear_Unit_Total();
    504 				player->UnitTotals->Clear_Unit_Total();
    505 				player->BuildingTotals->Clear_Unit_Total();
    506 
    507 				/*
    508 				** Number of units remaining to player
    509 				*/
    510 				for (index = 0; index < Units.Count(); index++) {
    511 					UnitClass const * unit = Units.Ptr(index);
    512 					if (unit->House == player){
    513 						player->UnitTotals->Increment_Unit_Total (unit->Class->Type);
    514 					}
    515 				}
    516 
    517 				for (index = 0; index < Infantry.Count(); index++) {
    518 				InfantryClass const * infantry = Infantry.Ptr(index);
    519 					if (infantry->House == player && !infantry->Class->IsCivilian){
    520 						player->InfantryTotals->Increment_Unit_Total (infantry->Class->Type);
    521 					}
    522 				}
    523 
    524 				for (index = 0; index < Aircraft.Count(); index++) {
    525 				AircraftClass const * aircraft = Aircraft.Ptr(index);
    526 					if (aircraft->House == player &&	aircraft->Class->Type != AIRCRAFT_CARGO){
    527 						player->AircraftTotals->Increment_Unit_Total (aircraft->Class->Type);
    528 					}
    529 				}
    530 
    531 				for (index = 0; index < Buildings.Count(); index++) {
    532 				BuildingClass const * building = Buildings.Ptr(index);
    533 					if (building->House == player){
    534 						player->BuildingTotals->Increment_Unit_Total (building->Class->Type);
    535 					}
    536 				}
    537 
    538 				player->InfantryTotals->To_Network_Format();
    539 				player->UnitTotals->To_Network_Format();
    540 				player->AircraftTotals->To_Network_Format();
    541 				player->BuildingTotals->To_Network_Format();
    542 
    543 				field_player_infantry_left[3] = '1' + (char)house;
    544 				field_player_units_left[3] = '1' + (char)house;
    545 				field_player_planes_left[3] = '1' + (char)house;
    546 				field_player_buildings_left[3] = '1' + (char)house;
    547 				stats.Add_Field (field_player_infantry_left, (void*) player->InfantryTotals->Get_All_Totals(), player->InfantryTotals->Get_Unit_Count()*4);
    548 				stats.Add_Field (field_player_units_left, (void*) player->UnitTotals->Get_All_Totals(), player->UnitTotals->Get_Unit_Count()*4);
    549 				stats.Add_Field (field_player_planes_left, (void*) player->AircraftTotals->Get_All_Totals(), player->AircraftTotals->Get_Unit_Count()*4);
    550 				stats.Add_Field (field_player_buildings_left, (void*) player->BuildingTotals->Get_All_Totals(), player->BuildingTotals->Get_Unit_Count()*4);
    551 
    552 
    553 				/*
    554 				** Number of enemy units/buildings of each type destroyed.
    555 				*/
    556 
    557 				player->DestroyedInfantry->To_Network_Format();
    558 				player->DestroyedUnits->To_Network_Format();
    559 				player->DestroyedAircraft->To_Network_Format();
    560 				player->DestroyedBuildings->To_Network_Format();
    561 
    562 				field_player_infantry_killed[3] = '1' + (char)house;
    563 				field_player_units_killed[3] = '1' + (char)house;
    564 				field_player_planes_killed[3] = '1' + (char)house;
    565 				field_player_buildings_killed[3] = '1' + (char)house;
    566 				stats.Add_Field (field_player_infantry_killed, (void*) player->DestroyedInfantry->Get_All_Totals(), player->DestroyedInfantry->Get_Unit_Count()*4);
    567 				stats.Add_Field (field_player_units_killed, (void*) player->DestroyedUnits->Get_All_Totals(), player->DestroyedUnits->Get_Unit_Count()*4);
    568 				stats.Add_Field (field_player_planes_killed, (void*) player->DestroyedAircraft->Get_All_Totals(), player->DestroyedAircraft->Get_Unit_Count()*4);
    569 				stats.Add_Field (field_player_buildings_killed, (void*) player->DestroyedBuildings->Get_All_Totals(), player->DestroyedBuildings->Get_Unit_Count()*4);
    570 
    571 
    572 				/*
    573 				** Number and type of enemy buildings captured
    574 				*/
    575 				field_player_buildings_captured[3] = '1' + (char)house;
    576 				player->CapturedBuildings->To_Network_Format();
    577 				stats.Add_Field (field_player_buildings_captured, (void*) player->CapturedBuildings->Get_All_Totals(), player->CapturedBuildings->Get_Unit_Count()*4);
    578 
    579 				/*
    580 				** Number of crates discovered and their contents
    581 				*/
    582 				field_player_crates_found[3] = '1' + (char)house;
    583 				player->TotalCrates->To_Network_Format();
    584 				stats.Add_Field (field_player_crates_found, (void*) player->TotalCrates->Get_All_Totals(), player->TotalCrates->Get_Unit_Count()*4);
    585 
    586 				/*
    587 				** Amount of tiberium turned into credits
    588 				*/
    589 				field_player_harvested[3] = '1' + (char)house;
    590 				stats.Add_Field (field_player_harvested, (unsigned long) player->HarvestedCredits);
    591 			}
    592 		}
    593 
    594 		CCDebugString ("C&C95 - Calling Create_Comms_Packet.\n");
    595 		/*
    596 		** Create the comms packet to be sent
    597 		*/
    598 		packet = stats.Create_Comms_Packet(packet_size);
    599 		CCDebugString ("C&C95 - Returned from Create_Comms_Packet.\n");
    600 
    601 		/*
    602 		** If a player disconnected then dont send the packet at this time - save it for later
    603 		*/
    604 		if (completion == COMPLETION_PLAYER_1_WON_BY_DISCONNECTION
    605 			|| completion == COMPLETION_PLAYER_2_WON_BY_DISCONNECTION){
    606 			PacketLater = packet;
    607 			CCDebugString ("C&C95 - Flagging to send the packet later.\n");
    608 			return;
    609 		}
    610 
    611 	}else{		//else for if (!PacketLater)
    612 
    613 		CCDebugString ("C&C95 - PacketLater is true.\n");
    614 
    615 		/*
    616 		** Send the packet we calculated earlier when the disconnect occurred
    617 		*/
    618 		packet = PacketLater;
    619 		PacketLater = NULL;
    620 	}
    621 
    622 	/*
    623 	** Send it.....
    624 	*/
    625 	int times = 100;		//100 times max
    626 	CountDownTimerClass	send_timer;
    627 
    628 	CCDebugString ("C&C95 - About to send stats packet to DDE server.\n");
    629 	while ( ! Send_Data_To_DDE_Server ((char*)packet, packet_size, DDEServerClass::DDE_PACKET_GAME_RESULTS)){
    630 		CCDebugString ("C&C95 - Stats packet send failed.\n");
    631 		send_timer.Set (60, true);
    632 		while (send_timer.Time()){};
    633 	}
    634 
    635 
    636 	/*
    637 	** Save it to disk as well so I can see it
    638 	*/
    639 #if (0)
    640 	RawFileClass anotherfile ("packet.net");
    641 	anotherfile.Write(packet, packet_size);
    642 #endif	//(0)
    643 	/*
    644 	** Tidy up
    645 	*/
    646 	CCDebugString ("C&C95 - About to delete packet memory.\n");
    647 	delete [] packet;
    648 
    649 	GameStatisticsPacketSent = true;
    650 	CCDebugString ("C&C95 - Returning from Send_Statistics_Packet.\n");
    651 #endif	//DEMO
    652 #endif
    653 }
    654 
    655 
    656 
    657 
    658 
    659 
    660 
    661 
    662 
    663 void Register_Game_Start_Time(void)
    664 {
    665 
    666 	GameTimer.Set (0, true);
    667 	GameTimerInUse = true;
    668 }
    669 
    670 
    671 extern void Register_Game_End_Time(void)
    672 {
    673 	GameEndTime = GameTimer.Time();
    674 	GameTimerInUse = false;
    675 }
    676