STATS.CPP 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  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. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /***********************************************************************************************
  15. *** 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 ***
  16. ***********************************************************************************************
  17. * *
  18. * Project Name : Command & Conquer *
  19. * *
  20. * File Name : WINSTUB.CPP *
  21. * *
  22. * Programmer : Steve Tall *
  23. * *
  24. * Start Date : 05/29/1996 *
  25. * *
  26. * Last Update : May 29th 1996 [ST] *
  27. * *
  28. *---------------------------------------------------------------------------------------------*
  29. * Overview: *
  30. * Internet game statistics to collect and upload to the server *
  31. * *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #ifdef WIN32
  38. #include "function.h"
  39. #include "tcpip.h"
  40. #include "packet.h"
  41. #include "ccdde.h"
  42. #define FIELD_PACKET_TYPE "TYPE"
  43. #define FIELD_GAME_ID "IDNO"
  44. #define FIELD_START_CREDITS "CRED"
  45. #define FIELD_BASES "BASE"
  46. #define FIELD_TIBERIUM "TIBR"
  47. #define FIELD_CRATES "CRAT"
  48. #define FIELD_AI_PLAYERS "AIPL"
  49. #define FIELD_CAPTURE_THE_FLAG "FLAG"
  50. #define FIELD_START_UNIT_COUNT "UNIT"
  51. #define FIELD_TECH_LEVEL "TECH"
  52. #define FIELD_SCENARIO "SCEN"
  53. #define FIELD_COMPLETION "CMPL"
  54. #define FIELD_START_TIME "TIME"
  55. #define FIELD_GAME_DURATION "DURA"
  56. #define FIELD_FRAME_RATE "AFPS"
  57. #define FIELD_SPEED_SETTING "SPED"
  58. #define FIELD_GAME_VERSION "VERS"
  59. #define FIELD_GAME_BUILD_DATE "DATE"
  60. #define FIELD_COVERT_PRESENT "COVT"
  61. #define FIELD_CPU_TYPE "PROC"
  62. #define FIELD_MEMORY "MEMO"
  63. #define FIELD_VIDEO_MEMORY "VIDM"
  64. #define FIELD_SHADOW_REGROWS "SHAD"
  65. #ifdef WOLAPI_INTEGRATION
  66. #define FIELD_HOSTORNOT "SDFX"
  67. #define FIELD_TOURNAMENT "TRNY"
  68. #define FIELD_NUM_INITIAL_PLAYERS "NUMP"
  69. #define FIELD_NUM_REMAINING_PLAYERS "REMN"
  70. #define FIELD_DISCONNECT_PINGS "PING"
  71. #define FIELD_COMPUTERTOOKOVER "QUIT"
  72. //#define FIELD_HARDWARE_GUID "GUID"
  73. #define FIELD_PLAYER1_IP "ADR1"
  74. #define FIELD_PLAYER2_IP "ADR2"
  75. #endif
  76. // ajw The following were never used (thank god).
  77. #define FIELD_PLAYER1_HANDLE "NAM1"
  78. #define FIELD_PLAYER2_HANDLE "NAM2"
  79. #define FIELD_PLAYER1_TEAM "SID1"
  80. #define FIELD_PLAYER2_TEAM "SID2"
  81. #define FIELD_PLAYER1_COLOR "COL1"
  82. #define FIELD_PLAYER2_COLOR "COL2"
  83. #define FIELD_PLAYER1_CREDITS "CRD1"
  84. #define FIELD_PLAYER2_CREDITS "CRD2"
  85. #define FIELD_PLAYER1_UNITS_LEFT "UNL1"
  86. #define FIELD_PLAYER2_UNITS_LEFT "UNL2"
  87. #define FIELD_PLAYER1_INFANTRY_LEFT "INL1"
  88. #define FIELD_PLAYER2_INFANTRY_LEFT "INL2"
  89. #define FIELD_PLAYER1_PLANES_LEFT "PLL1"
  90. #define FIELD_PLAYER2_PLANES_LEFT "PLL2"
  91. #define FIELD_PLAYER1_BUILDINGS_LEFT "BLL1"
  92. #define FIELD_PLAYER2_BUILDINGS_LEFT "BLL2"
  93. #define FIELD_PLAYER1_VESSELS_LEFT "VSL1"
  94. #define FIELD_PLAYER2_VESSELS_LEFT "VSL2"
  95. #define FIELD_PLAYER1_UNITS_BOUGHT "UNB1"
  96. #define FIELD_PLAYER2_UNITS_BOUGHT "UNB2"
  97. #define FIELD_PLAYER1_INFANTRY_BOUGHT "INB1"
  98. #define FIELD_PLAYER2_INFANTRY_BOUGHT "INB2"
  99. #define FIELD_PLAYER1_PLANES_BOUGHT "PLB1"
  100. #define FIELD_PLAYER2_PLANES_BOUGHT "PLB2"
  101. #define FIELD_PLAYER1_BUILDINGS_BOUGHT "BLB1"
  102. #define FIELD_PLAYER2_BUILDINGS_BOUGHT "BLB2"
  103. #define FIELD_PLAYER1_VESSELS_BOUGHT "VSB1"
  104. #define FIELD_PLAYER2_VESSELS_BOUGHT "VSB2"
  105. #define FIELD_PLAYER1_UNITS_KILLED "UNK1"
  106. #define FIELD_PLAYER2_UNITS_KILLED "UNK2"
  107. #define FIELD_PLAYER1_INFANTRY_KILLED "INK1"
  108. #define FIELD_PLAYER2_INFANTRY_KILLED "INK2"
  109. #define FIELD_PLAYER1_PLANES_KILLED "PLK1"
  110. #define FIELD_PLAYER2_PLANES_KILLED "PLK2"
  111. #define FIELD_PLAYER1_BUILDINGS_KILLED "BLK1"
  112. #define FIELD_PLAYER2_BUILDINGS_KILLED "BLK2"
  113. #define FIELD_PLAYER1_VESSELS_KILLED "VSK1"
  114. #define FIELD_PLAYER2_VESSELS_KILLED "VSK2"
  115. #define FIELD_PLAYER1_BUILDINGS_CAPTURED "BLC1"
  116. #define FIELD_PLAYER2_BUILDINGS_CAPTURED "BLC2"
  117. #define FIELD_PLAYER1_CRATES_FOUND "CRA1"
  118. #define FIELD_PLAYER2_CRATES_FOUND "CRA2"
  119. #define FIELD_PLAYER1_HARVESTED "HRV1"
  120. #define FIELD_PLAYER2_HARVESTED "HRV2"
  121. #define PACKET_TYPE_HOST_GAME_INFO (unsigned char) 50
  122. #define PACKET_TYPE_GUEST_GAME_INFO (unsigned char) 51
  123. // Note: These enums match those in the game results server code.
  124. enum {
  125. COMPLETION_CONNECTION_LOST,
  126. COMPLETION_PLAYER_1_WON,
  127. COMPLETION_PLAYER_1_WON_BY_RESIGNATION,
  128. COMPLETION_PLAYER_1_WON_BY_DISCONNECTION,
  129. COMPLETION_PLAYER_2_WON,
  130. COMPLETION_PLAYER_2_WON_BY_RESIGNATION,
  131. COMPLETION_PLAYER_2_WON_BY_DISCONNECTION,
  132. #ifdef FIXIT_VERSION_3 // Stalemate games.
  133. COMPLETION_WASH = 64,
  134. #endif
  135. };
  136. extern unsigned long PlanetWestwoodGameID;
  137. extern HINSTANCE ProgramInstance;
  138. extern unsigned long PlanetWestwoodStartTime;
  139. extern "C" char CPUType;
  140. bool GameTimerInUse = false;
  141. TimerClass GameTimer;
  142. long GameEndTime;
  143. void *PacketLater = NULL;
  144. //#include "WolDebug.h"
  145. #ifdef WOLAPI_INTEGRATION
  146. #include "WolapiOb.h"
  147. extern WolapiObject* pWolapi;
  148. extern bool bReconnectDialogCancelled;
  149. #endif
  150. /***********************************************************************************************
  151. * Send_Statistics_To_Server -- sends internet game statistics to the Westeood server *
  152. * *
  153. * *
  154. * *
  155. * INPUT: Nothing *
  156. * *
  157. * OUTPUT: Nothing *
  158. * *
  159. * WARNINGS: None *
  160. * *
  161. * HISTORY: *
  162. * 5/29/96 12:38PM ST : Created *
  163. *=============================================================================================*/
  164. void Send_Statistics_Packet(void)
  165. {
  166. #if (0)//PG
  167. // debugprint( "Stats: Send_Statistics_Packet() called.\n" );
  168. #ifndef INTERNET_OFF // Denzil 5/4/98
  169. #ifdef WOLAPI_INTEGRATION
  170. if( !pWolapi ) // Should no longer ever happen.
  171. return;
  172. #endif
  173. PacketClass stats;
  174. HouseClass *player;
  175. static int packet_size;
  176. int index;
  177. bool packet_later = false; // Should the packet be sent later
  178. void *packet;
  179. static char field_player_handle[5] = { "NAM?" };
  180. static char field_player_team[5] = { "SID?" };
  181. static char field_player_color[5] = { "COL?" };
  182. static char field_player_credits[5] = { "CRD?" };
  183. static char field_player_units_left[5] = { "UNL?" };
  184. static char field_player_infantry_left[5] = { "INL?" };
  185. static char field_player_planes_left[5] = { "PLL?" };
  186. static char field_player_buildings_left[5] = { "BLL?" };
  187. static char field_player_vessels_left[5] = { "VSL?" };
  188. static char field_player_units_bought[5] = { "UNB?" };
  189. static char field_player_infantry_bought[5] = { "INB?" };
  190. static char field_player_planes_bought[5] = { "PLB?" };
  191. static char field_player_buildings_bought[5] = { "BLB?" };
  192. static char field_player_vessels_bought[5] = { "VSB?" };
  193. static char field_player_units_killed[5] = { "UNK?" };
  194. static char field_player_infantry_killed[5] = { "INK?" };
  195. static char field_player_planes_killed[5] = { "PLK?" };
  196. static char field_player_buildings_killed[5] = { "BLK?" };
  197. static char field_player_vessels_killed[5] = { "VSK?" };
  198. static char field_player_buildings_captured[5] = { "BLC?" };
  199. static char field_player_crates_found[5] = { "CRA?" };
  200. static char field_player_harvested[5] = { "HRV?" };
  201. static char *houses[] = {
  202. "SPA",
  203. "GRE",
  204. "USS",
  205. "ENG",
  206. "ITA",
  207. "GER",
  208. "FRA",
  209. "TKY",
  210. "GUD",
  211. "BAD",
  212. "CIV",
  213. "JP ",
  214. "M01",
  215. "M02",
  216. "M03",
  217. "M04",
  218. "M05",
  219. "M06",
  220. "M07",
  221. "M08"
  222. };
  223. if (!PacketLater){
  224. /*
  225. ** Field to identify this as C&C 95 internet game statistics packet
  226. */
  227. #ifdef WOLAPI_INTEGRATION
  228. if( pWolapi->bGameServer )
  229. {
  230. stats.Add_Field( FIELD_HOSTORNOT, (unsigned char)0 ); // Reversed meaning of this for Neal.
  231. }else{
  232. stats.Add_Field( FIELD_HOSTORNOT, (unsigned char)1 );
  233. }
  234. #else
  235. if (Server){
  236. stats.Add_Field(FIELD_PACKET_TYPE, PACKET_TYPE_HOST_GAME_INFO);
  237. }else{
  238. stats.Add_Field(FIELD_PACKET_TYPE, PACKET_TYPE_GUEST_GAME_INFO);
  239. }
  240. #endif
  241. /*
  242. ** Game ID. A unique game identifier assigned by WChat.
  243. */
  244. stats.Add_Field(FIELD_GAME_ID, PlanetWestwoodGameID);
  245. #ifdef WOLAPI_INTEGRATION
  246. // Number of players initially in game.
  247. stats.Add_Field( FIELD_NUM_INITIAL_PLAYERS, (unsigned long)pWolapi->GameInfoCurrent.iPlayerCount );
  248. //debugprint( "Stats: number of initial players is %i\n", pWolapi->GameInfoCurrent.iPlayerCount );
  249. // Number of players remaining in game. Not sure of what use this will be statistically...
  250. stats.Add_Field( FIELD_NUM_REMAINING_PLAYERS, (unsigned long)Session.Players.Count() );
  251. //debugprint( "Stats: number of remaining players is %i\n", Session.Players.Count() );
  252. // Whether or not this was a tournament game.
  253. stats.Add_Field( FIELD_TOURNAMENT, (unsigned char)( pWolapi->GameInfoCurrent.bTournament ? 1 : 0 ) );
  254. // ajw This is now in WOLAPI...
  255. // // A unique value that identifies the machine that the game was played on.
  256. // HW_PROFILE_INFO hwinfo;
  257. // ::GetCurrentHwProfile( &hwinfo );
  258. // stats.Add_Field( FIELD_HARDWARE_GUID, hwinfo.szHwProfileGuid );
  259. #endif
  260. /*
  261. ** Start credits.
  262. */
  263. stats.Add_Field(FIELD_START_CREDITS, (unsigned long)Session.Options.Credits);
  264. /*
  265. ** Bases (On/Off)
  266. */
  267. stats.Add_Field(FIELD_BASES, Session.Options.Bases ? "ON" : "OFF");
  268. /*
  269. ** Tiberium (On/Off)
  270. */
  271. stats.Add_Field(FIELD_TIBERIUM, Session.Options.Tiberium ? "ON" : "OFF");
  272. /*
  273. ** Crates (On/Off)
  274. */
  275. stats.Add_Field(FIELD_CRATES, Session.Options.Goodies ? "ON" : "OFF");
  276. /*
  277. ** AI Players (On/Off)
  278. */
  279. stats.Add_Field(FIELD_AI_PLAYERS, (unsigned long) Session.Options.AIPlayers);
  280. /*
  281. ** Shadow regrowth enabled
  282. */
  283. stats.Add_Field(FIELD_SHADOW_REGROWS, Special.IsShadowGrow ? "ON" : "OFF" );
  284. /*
  285. ** Capture the flag mode (On/Off)
  286. */
  287. stats.Add_Field(FIELD_CAPTURE_THE_FLAG, Special.IsCaptureTheFlag ? "ON" : "OFF");
  288. /*
  289. ** Start unit count
  290. */
  291. stats.Add_Field(FIELD_START_UNIT_COUNT, (unsigned long)Session.Options.UnitCount);
  292. /*
  293. ** Tech level.
  294. */
  295. stats.Add_Field(FIELD_TECH_LEVEL, (unsigned long)BuildLevel);
  296. /*
  297. ** Scenario
  298. */
  299. #if (1)
  300. stats.Add_Field(FIELD_SCENARIO, Session.Options.ScenarioDescription);
  301. #else //(1)
  302. char fname[128];
  303. char namebuffer[40];
  304. char *abuffer = (char *)_ShapeBuffer;
  305. memset(abuffer, '\0', _ShapeBufferSize);
  306. sprintf(fname,"%s.INI",Scen.ScenarioName);
  307. CCFileClass fileo;
  308. fileo.Set_Name (fname);
  309. fileo.Read(abuffer, _ShapeBufferSize-1);
  310. fileo.Close();
  311. WWGetPrivateProfileString("Basic", "Name", "Nulls-Ville", namebuffer, 40, abuffer);
  312. stats.Add_Field(FIELD_SCENARIO, namebuffer);
  313. //stats.Add_Field(FIELD_SCENARIO, MPlayerScenarios[ScenarioIdx]);
  314. #endif //(1)
  315. #ifdef WOLAPI_INTEGRATION
  316. // Completion status is set for Tournament games only - ajw.
  317. if( pWolapi->GameInfoCurrent.bTournament )
  318. {
  319. #endif
  320. /*
  321. ** Game completion status.
  322. **
  323. ** Connection lost.
  324. ** Player 1 won
  325. ** Player 2 won
  326. ** Player 1 won by resignation
  327. ** Player 2 won by resignation
  328. ** Player 1 aborted
  329. ** Player 2 aborted
  330. **
  331. ** Game was a draw
  332. */
  333. HouseClass *player1 = NULL;
  334. HouseClass *player2 = NULL;
  335. for (int h=0 ; h<Session.Players.Count(); h++){
  336. HouseClass *ptr = HouseClass::As_Pointer ((HousesType)(h + HOUSE_MULTI1));
  337. if (ptr->IsHuman){
  338. if (player1){
  339. player2 = ptr;
  340. break;
  341. }else{
  342. player1 = ptr;
  343. }
  344. }
  345. }
  346. int completion = -1;
  347. if (player1 && player2){ // Can this ever fail? ajw
  348. #ifdef FIXIT_VERSION_3
  349. // Send IP addresses of both players.
  350. NetNumType net;
  351. NetNodeType node;
  352. char szIPAddress[ 30 ];
  353. Session.Players[ 0 ]->Address.Get_Address( net, node );
  354. sprintf( szIPAddress, "%i.%i.%i.%i", node[0], node[1], node[2], node[3] );
  355. if( strcmp( szIPAddress, "255.255.255.255" ) == 0 )
  356. {
  357. // Ok. It's not set. Let's try to get it ourselves...
  358. char szHostName[ 512 ];
  359. int iRes = gethostname( szHostName, 512 );
  360. if( iRes != SOCKET_ERROR ) // else forget about trying
  361. {
  362. // debugprint( "gethostname got me %s\n", szHostName );
  363. struct hostent* pHostent = gethostbyname( szHostName );
  364. if( pHostent ) // else forget about trying
  365. {
  366. int i = 0;
  367. int* piAddress = (int*)pHostent->h_addr_list[ i ];
  368. while( piAddress )
  369. {
  370. // There is a non-null value for this h_addr_list entry.
  371. char szAsciiIP[ 30 ];
  372. strcpy( szAsciiIP, inet_ntoa( *( (struct in_addr*)piAddress ) ) );
  373. // We have an address in the right form.
  374. // Now, is it an address in a private network? If so we should ignore it.
  375. unsigned char q1 = ( (char*)piAddress )[ 0 ]; // First digit.
  376. unsigned char q2 = ( (char*)piAddress )[ 1 ]; // Second digit.
  377. // debugprint( "ip: %s\n", szAsciiIP );
  378. if( q1 == 10 || ( q1 == 172 && ( q2 >= 16 && q2 <= 31 ) ) || ( q1 == 192 && q2 == 168 ) )
  379. {
  380. // This is a private network address - ignore it and go on to next.
  381. }
  382. else
  383. {
  384. strcpy( szIPAddress, szAsciiIP );
  385. break;
  386. }
  387. piAddress = (int*)pHostent->h_addr_list[ ++i ];
  388. }
  389. }
  390. // else
  391. // debugprint( "gethostbyname failed. Error %i\n", WSAGetLastError() );
  392. }
  393. // else
  394. // debugprint( "gethostname failed with %i, error %i\n", iRes, WSAGetLastError() );
  395. }
  396. stats.Add_Field( FIELD_PLAYER1_IP, (char*)szIPAddress );
  397. Session.Players[ 1 ]->Address.Get_Address( net, node );
  398. sprintf( szIPAddress, "%i.%i.%i.%i", node[0], node[1], node[2], node[3] );
  399. stats.Add_Field( FIELD_PLAYER2_IP, (char*)szIPAddress );
  400. #endif
  401. #ifdef FIXIT_VERSION_3 // Stalemate games.
  402. if( Scen.bLocalProposesDraw && Scen.bOtherProposesDraw )
  403. {
  404. completion = COMPLETION_WASH;
  405. }
  406. else
  407. {
  408. #endif
  409. if (ConnectionLost){
  410. #ifdef WOLAPI_INTEGRATION
  411. if( bReconnectDialogCancelled )
  412. {
  413. if( Session.Players[ 0 ]->Player.ID == HOUSE_MULTI1 )
  414. // I am player1.
  415. completion = COMPLETION_PLAYER_2_WON_BY_DISCONNECTION;
  416. else
  417. completion = COMPLETION_PLAYER_1_WON_BY_DISCONNECTION;
  418. }
  419. else
  420. {
  421. completion = COMPLETION_CONNECTION_LOST;
  422. if( pWolapi->bDisconnectPingingCompleted )
  423. {
  424. char szPingResult[ 8 ]; // Format is "x/y a/b", e.g., "3/5 4/5"
  425. pWolapi->DisconnectPingResultsString( szPingResult );
  426. stats.Add_Field( FIELD_DISCONNECT_PINGS, (char*)szPingResult );
  427. }
  428. // else
  429. // debugprint( "Stats: bDisconnectPingingCompleted is false! Should be finished!!!!!!!!!!!!!!!\n" );
  430. }
  431. #else
  432. completion = COMPLETION_CONNECTION_LOST;
  433. #endif
  434. }else{
  435. if (player1->IsGiverUpper){
  436. completion = COMPLETION_PLAYER_2_WON_BY_DISCONNECTION;
  437. }
  438. if (player2->IsGiverUpper){
  439. completion = COMPLETION_PLAYER_1_WON_BY_DISCONNECTION;
  440. }
  441. if (player2->IsDefeated){
  442. /*
  443. ** Player 1 won. Find out how.
  444. */
  445. completion = COMPLETION_PLAYER_1_WON;
  446. if (player2->IsResigner){
  447. completion = COMPLETION_PLAYER_1_WON_BY_RESIGNATION;
  448. }else{
  449. if (player2->IsGiverUpper){
  450. completion = COMPLETION_PLAYER_1_WON_BY_DISCONNECTION;
  451. }
  452. }
  453. }else{
  454. if (player1->IsDefeated){
  455. /*
  456. ** Player 2 won. Find out how.
  457. */
  458. completion = COMPLETION_PLAYER_2_WON;
  459. if (player1->IsResigner){
  460. completion = COMPLETION_PLAYER_2_WON_BY_RESIGNATION;
  461. }else{
  462. if (player1->IsGiverUpper){
  463. completion = COMPLETION_PLAYER_2_WON_BY_DISCONNECTION;
  464. }
  465. }
  466. }
  467. }
  468. }
  469. #ifdef FIXIT_VERSION_3 // Stalemate games.
  470. }
  471. #endif
  472. }
  473. stats.Add_Field (FIELD_COMPLETION, (char) completion);
  474. //debugprint( "Stats: Tournament game completion value: %i\n", completion );
  475. #ifdef WOLAPI_INTEGRATION
  476. }
  477. #endif
  478. /*
  479. ** Game start time (GMT or Pacific?)
  480. **
  481. ** Passed from WChat
  482. */
  483. stats.Add_Field (FIELD_START_TIME, (long) PlanetWestwoodStartTime);
  484. /*
  485. ** Game duration (seconds).
  486. */
  487. stats.Add_Field (FIELD_GAME_DURATION, (long) GameEndTime/60);
  488. /*
  489. ** Avg. frame rate.
  490. */
  491. #ifdef FIXIT_IP_CRASH
  492. long divisor = GameEndTime / 60;
  493. if (divisor != 0) {
  494. stats.Add_Field (FIELD_FRAME_RATE, (long) Frame / (GameEndTime/60) );
  495. } else {
  496. stats.Add_Field (FIELD_FRAME_RATE, 0l);
  497. }
  498. #else
  499. stats.Add_Field (FIELD_FRAME_RATE, (long) Frame / (GameEndTime/60) );
  500. #endif
  501. /*
  502. ** CPU type
  503. */
  504. stats.Add_Field (FIELD_CPU_TYPE, (char)CPUType);
  505. /*
  506. ** Memory
  507. */
  508. MEMORYSTATUS mem_info;
  509. mem_info.dwLength=sizeof(mem_info);
  510. GlobalMemoryStatus(&mem_info);
  511. stats.Add_Field (FIELD_MEMORY, (long)mem_info.dwTotalPhys);
  512. /*
  513. ** Video memory
  514. */
  515. DDCAPS video_capabilities;
  516. long video_memory;
  517. if (DirectDrawObject){
  518. video_capabilities.dwSize = sizeof (video_capabilities);
  519. if (DD_OK == DirectDrawObject->GetCaps (&video_capabilities , NULL)){
  520. video_memory = video_capabilities.dwVidMemTotal;
  521. video_memory += 1024*1024 -1;
  522. video_memory &= 0xfff00000;
  523. stats.Add_Field (FIELD_VIDEO_MEMORY, (long) video_memory);
  524. }
  525. }
  526. /*
  527. ** Game speed setting.
  528. */
  529. stats.Add_Field (FIELD_SPEED_SETTING, (char)Options.GameSpeed);
  530. /*
  531. ** Red Alert version/build date
  532. */
  533. char version[128];
  534. sprintf (version, "V%s", VerNum.Version_Name() );
  535. stats.Add_Field (FIELD_GAME_VERSION, (char*)version);
  536. char path_to_exe[280];
  537. FILETIME write_time; //File time is 64 bits
  538. GetModuleFileName (ProgramInstance, path_to_exe, 280);
  539. RawFileClass file;
  540. file.Set_Name(path_to_exe);
  541. file.Open();
  542. HANDLE handle = file.Get_File_Handle();
  543. if (handle != INVALID_HANDLE_VALUE){
  544. if (GetFileTime (handle, NULL, NULL, &write_time)){
  545. write_time.dwLowDateTime = htonl (write_time.dwLowDateTime);
  546. write_time.dwHighDateTime = htonl (write_time.dwHighDateTime);
  547. stats.Add_Field (FIELD_GAME_BUILD_DATE, (void*)&write_time, sizeof (write_time));
  548. }
  549. }
  550. /*
  551. ** Covert installed? (Yes/No)
  552. */
  553. //stats.Add_Field(FIELD_COVERT_PRESENT, (char) Expansion_Present());
  554. /*
  555. ** Build the player specific statistics
  556. **
  557. */
  558. #ifdef WOLAPI_INTEGRATION
  559. for (int house = 0 ; house < 8 ; house++){
  560. #else
  561. for (int house = 0 ; house < 2 ; house++){
  562. #endif
  563. player = HouseClass::As_Pointer((HousesType) (house + HOUSE_MULTI1));
  564. #ifdef WOLAPI_INTEGRATION
  565. if( !player )
  566. continue;
  567. #endif
  568. /*
  569. ** Player handle.
  570. */
  571. field_player_handle[3] = '1' + (char)house;
  572. #ifdef WOLAPI_INTEGRATION
  573. stats.Add_Field (field_player_handle, (char*) player->InitialName);
  574. //debugprint( "Stats: Player %i name %s\n", house, (char*) player->InitialName );
  575. //debugprint( "Stats: Player %i ending name %s\n", house, (char*) player->IniName );
  576. #else
  577. stats.Add_Field (field_player_handle, (char*) player->IniName);
  578. #endif
  579. #ifdef WOLAPI_INTEGRATION
  580. // Whether or not this player was taken over by the computer, due to his quitting the game.
  581. if( strcmp( player->IniName, player->InitialName ) )
  582. stats.Add_Field( FIELD_COMPUTERTOOKOVER, (unsigned char)1 );
  583. else
  584. stats.Add_Field( FIELD_COMPUTERTOOKOVER, (unsigned char)0 );
  585. #endif
  586. /*
  587. ** Player team. (NOD or GDI)
  588. */
  589. field_player_team[3] = '1' + (char)house;
  590. stats.Add_Field (field_player_team, houses[player->ActLike]);
  591. /*
  592. ** Player color
  593. */
  594. field_player_color[3] = '1' + (char)house;
  595. stats.Add_Field (field_player_color, (unsigned char) (player->Class->House - HOUSE_MULTI1));
  596. /*
  597. ** Player end credits.
  598. */
  599. field_player_credits[3] = '1' + (char)house;
  600. stats.Add_Field (field_player_credits, player->Credits + player->Tiberium);
  601. /*
  602. ** Number of each unit/building type built
  603. */
  604. field_player_infantry_bought[3] = '1' + (char)house;
  605. field_player_units_bought[3] = '1' + (char)house;
  606. field_player_planes_bought[3] = '1' + (char)house;
  607. field_player_buildings_bought[3] = '1' + (char)house;
  608. field_player_vessels_bought[3] = '1' + (char)house;
  609. player->InfantryTotals->To_Network_Format();
  610. player->UnitTotals->To_Network_Format();
  611. player->AircraftTotals->To_Network_Format();
  612. player->BuildingTotals->To_Network_Format();
  613. player->VesselTotals->To_Network_Format();
  614. stats.Add_Field (field_player_infantry_bought, (void*) player->InfantryTotals->Get_All_Totals(), player->InfantryTotals->Get_Unit_Count()*4);
  615. stats.Add_Field (field_player_units_bought, (void*) player->UnitTotals->Get_All_Totals(), player->UnitTotals->Get_Unit_Count()*4);
  616. stats.Add_Field (field_player_planes_bought, (void*) player->AircraftTotals->Get_All_Totals(), player->AircraftTotals->Get_Unit_Count()*4);
  617. stats.Add_Field (field_player_buildings_bought, (void*) player->BuildingTotals->Get_All_Totals(), player->BuildingTotals->Get_Unit_Count()*4);
  618. stats.Add_Field (field_player_vessels_bought, (void*) player->VesselTotals->Get_All_Totals(), player->VesselTotals->Get_Unit_Count()*4);
  619. player->InfantryTotals->To_PC_Format();
  620. player->UnitTotals->To_PC_Format();
  621. player->AircraftTotals->To_PC_Format();
  622. player->BuildingTotals->To_PC_Format();
  623. /*
  624. ** Clear out the counts and use the space to count up the current number of units/buildings
  625. */
  626. player->InfantryTotals->Clear_Unit_Total();
  627. player->AircraftTotals->Clear_Unit_Total();
  628. player->UnitTotals->Clear_Unit_Total();
  629. player->BuildingTotals->Clear_Unit_Total();
  630. player->VesselTotals->Clear_Unit_Total();
  631. /*
  632. ** Number of units remaining to player
  633. */
  634. for (index = 0; index < Units.Count(); index++) {
  635. UnitClass const * unit = Units.Ptr(index);
  636. if (player == unit->House){
  637. player->UnitTotals->Increment_Unit_Total (unit->Class->Type);
  638. }
  639. }
  640. for (index = 0; index < Infantry.Count(); index++) {
  641. InfantryClass const * infantry = Infantry.Ptr(index);
  642. if (player == infantry->House && !infantry->Class->IsCivilian){
  643. player->InfantryTotals->Increment_Unit_Total (infantry->Class->Type);
  644. }
  645. }
  646. for (index = 0; index < Aircraft.Count(); index++) {
  647. AircraftClass const * aircraft = Aircraft.Ptr(index);
  648. if (player == aircraft->House){ // && aircraft->Class->Type != AIRCRAFT_CARGO){
  649. player->AircraftTotals->Increment_Unit_Total (aircraft->Class->Type);
  650. }
  651. }
  652. for (index = 0; index < Buildings.Count(); index++) {
  653. BuildingClass const * building = Buildings.Ptr(index);
  654. if (player == building->House){
  655. player->BuildingTotals->Increment_Unit_Total (building->Class->Type);
  656. }
  657. }
  658. for (index = 0; index < Vessels.Count(); index++) {
  659. VesselClass const * vessel = Vessels.Ptr(index);
  660. if (player == vessel->House){
  661. player->VesselTotals->Increment_Unit_Total (vessel->Class->Type);
  662. }
  663. }
  664. player->InfantryTotals->To_Network_Format();
  665. player->UnitTotals->To_Network_Format();
  666. player->AircraftTotals->To_Network_Format();
  667. player->BuildingTotals->To_Network_Format();
  668. player->VesselTotals->To_Network_Format();
  669. field_player_infantry_left[3] = '1' + (char)house;
  670. field_player_units_left[3] = '1' + (char)house;
  671. field_player_planes_left[3] = '1' + (char)house;
  672. field_player_buildings_left[3] = '1' + (char)house;
  673. #ifdef FIXIT_IP_STATS
  674. field_player_vessels_left[3] = '1' + (char)house;
  675. #endif
  676. stats.Add_Field (field_player_infantry_left, (void*) player->InfantryTotals->Get_All_Totals(), player->InfantryTotals->Get_Unit_Count()*4);
  677. stats.Add_Field (field_player_units_left, (void*) player->UnitTotals->Get_All_Totals(), player->UnitTotals->Get_Unit_Count()*4);
  678. stats.Add_Field (field_player_planes_left, (void*) player->AircraftTotals->Get_All_Totals(), player->AircraftTotals->Get_Unit_Count()*4);
  679. stats.Add_Field (field_player_buildings_left, (void*) player->BuildingTotals->Get_All_Totals(), player->BuildingTotals->Get_Unit_Count()*4);
  680. stats.Add_Field (field_player_vessels_left, (void*) player->VesselTotals->Get_All_Totals(), player->VesselTotals->Get_Unit_Count()*4);
  681. /*
  682. ** Number of enemy units/buildings of each type destroyed.
  683. */
  684. player->DestroyedInfantry->To_Network_Format();
  685. player->DestroyedUnits->To_Network_Format();
  686. player->DestroyedAircraft->To_Network_Format();
  687. player->DestroyedBuildings->To_Network_Format();
  688. player->DestroyedVessels->To_Network_Format();
  689. field_player_infantry_killed[3] = '1' + (char)house;
  690. field_player_units_killed[3] = '1' + (char)house;
  691. field_player_planes_killed[3] = '1' + (char)house;
  692. field_player_buildings_killed[3] = '1' + (char)house;
  693. field_player_vessels_killed[3] = '1' + (char)house;
  694. stats.Add_Field (field_player_infantry_killed, (void*) player->DestroyedInfantry->Get_All_Totals(), player->DestroyedInfantry->Get_Unit_Count()*4);
  695. stats.Add_Field (field_player_units_killed, (void*) player->DestroyedUnits->Get_All_Totals(), player->DestroyedUnits->Get_Unit_Count()*4);
  696. stats.Add_Field (field_player_planes_killed, (void*) player->DestroyedAircraft->Get_All_Totals(), player->DestroyedAircraft->Get_Unit_Count()*4);
  697. stats.Add_Field (field_player_buildings_killed, (void*) player->DestroyedBuildings->Get_All_Totals(), player->DestroyedBuildings->Get_Unit_Count()*4);
  698. #ifdef FIXIT_VERSION_3
  699. stats.Add_Field (field_player_vessels_killed, (void*) player->DestroyedVessels->Get_All_Totals(), player->DestroyedVessels->Get_Unit_Count()*4);
  700. #else
  701. stats.Add_Field (field_player_vessels_killed, (void*) player->DestroyedVessels->Get_All_Totals(), player->DestroyedBuildings->Get_Unit_Count()*4);
  702. #endif
  703. /*
  704. ** Number and type of enemy buildings captured
  705. */
  706. field_player_buildings_captured[3] = '1' + (char)house;
  707. player->CapturedBuildings->To_Network_Format();
  708. stats.Add_Field (field_player_buildings_captured, (void*) player->CapturedBuildings->Get_All_Totals(), player->CapturedBuildings->Get_Unit_Count()*4);
  709. /*
  710. ** Number of crates discovered and their contents
  711. */
  712. field_player_crates_found[3] = '1' + (char)house;
  713. player->TotalCrates->To_Network_Format();
  714. stats.Add_Field (field_player_crates_found, (void*) player->TotalCrates->Get_All_Totals(), player->TotalCrates->Get_Unit_Count()*4);
  715. /*
  716. ** Amount of tiberium turned into credits
  717. */
  718. field_player_harvested[3] = '1' + (char)house;
  719. stats.Add_Field (field_player_harvested, (unsigned long) player->HarvestedCredits);
  720. }
  721. /*
  722. ** Create the comms packet to be sent
  723. */
  724. packet = stats.Create_Comms_Packet(packet_size);
  725. #ifndef WOLAPI_INTEGRATION // ajw - 'PacketLater' is no longer ever used.
  726. /*
  727. ** If a player disconnected then dont send the packet at this time - save it for later
  728. */
  729. if (completion == COMPLETION_PLAYER_1_WON_BY_DISCONNECTION
  730. || completion == COMPLETION_PLAYER_2_WON_BY_DISCONNECTION){
  731. PacketLater = packet;
  732. return;
  733. }
  734. #endif
  735. }else{ //else for if (!PacketLater)
  736. /*
  737. ** Send the packet we calculated earlier when the disconnect occurred
  738. */
  739. packet = PacketLater;
  740. PacketLater = NULL;
  741. }
  742. /*
  743. ** Send it.....
  744. */
  745. const char* szGameResServer;
  746. int iPort;
  747. if( pWolapi->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME )
  748. {
  749. szGameResServer = pWolapi->szGameResServerHost2;
  750. iPort = pWolapi->iGameResServerPort2;
  751. }
  752. else
  753. {
  754. szGameResServer = pWolapi->szGameResServerHost1;
  755. iPort = pWolapi->iGameResServerPort1;
  756. }
  757. if( *szGameResServer )
  758. {
  759. if( pWolapi->pNetUtil->RequestGameresSend( szGameResServer, iPort, (unsigned char*)packet, packet_size ) != S_OK )
  760. //debugprint( "RequestGameresSend( %s, %i ) failed!!!\n", szGameResServer, iPort );
  761. ;
  762. }
  763. /*
  764. ** Save it to disk as well so I can see it
  765. */
  766. // RawFileClass anotherfile ("packet.net");
  767. // anotherfile.Write(packet, packet_size);
  768. //debugprint( "Wrote out packet.net\n" );
  769. /*
  770. ** Tidy up
  771. */
  772. delete [] packet;
  773. GameStatisticsPacketSent = true;
  774. #endif // INTERNET_OFF
  775. #endif
  776. }
  777. void Register_Game_Start_Time(void)
  778. {
  779. GameTimer.Set (0, true);
  780. GameTimerInUse = true;
  781. }
  782. extern void Register_Game_End_Time(void)
  783. {
  784. GameEndTime = GameTimer.Time();
  785. GameTimerInUse = false;
  786. }
  787. #endif //WIN32