STATS.CPP 23 KB

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