playerdata.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. ** Command & Conquer Renegade(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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/playerdata.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 3/29/02 3:40p $*
  29. * *
  30. * $Revision:: 38 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "playerdata.h"
  36. #include "debug.h"
  37. #include "chunkio.h"
  38. #include "wwpacket.h"
  39. #include "persistfactory.h"
  40. #include "combatchunkid.h"
  41. #include "combat.h"
  42. #include "hud.h"
  43. #include "soldier.h"
  44. #include "systeminfolog.h"
  45. #include "stackdump.h"
  46. /*
  47. **
  48. */
  49. PlayerDataClass::PlayerDataClass( void ) :
  50. Score( 0 ),
  51. Money( 0 ),
  52. PunishTimer( 0 )
  53. {
  54. Stats_Reset();
  55. }
  56. PlayerDataClass::~PlayerDataClass( void )
  57. {
  58. PlayerInfoLog::Append_To_Log(this);
  59. if ( Get_GameObj() ) {
  60. Get_GameObj()->Set_Player_Data( NULL );
  61. }
  62. }
  63. /*
  64. **
  65. */
  66. enum {
  67. CHUNKID_VARIABLES = 201011247,
  68. CHUNKID_STATS_WEAPON,
  69. MICROCHUNKID_SCORE = 1,
  70. MICROCHUNKID_MONEY,
  71. MICROCHUNKID_STAT_TIME_IN_GAME,
  72. MICROCHUNKID_STAT_ENEMIES_KILLED,
  73. MICROCHUNKID_STAT_ALLIES_KILLED,
  74. MICROCHUNKID_STAT_SHOTS_FIRED,
  75. MICROCHUNKID_STAT_HEAD_SHOTS,
  76. MICROCHUNKID_STAT_TORSO_SHOTS,
  77. MICROCHUNKID_STAT_ARM_SHOTS,
  78. MICROCHUNKID_STAT_LEG_SHOTS,
  79. MICROCHUNKID_STAT_CROTCH_CHOTS,
  80. MICROCHUNKID_STAT_FINAL_HEALTH,
  81. MICROCHUNKID_STAT_POWERUPS,
  82. MICROCHUNKID_STAT_VEHICLES_DESTROYED,
  83. MICROCHUNKID_STAT_TIME_IN_VEHICLES,
  84. MICROCHUNKID_STAT_KILLS_FROM_VEHICLES,
  85. MICROCHUNKID_STAT_SQUISHES,
  86. MICROCHUNKID_STAT_CREDITS_GRANTED,
  87. MICROCHUNKID_STAT_BUILDINGS_DESTROYED,
  88. MICROCHUNKID_STAT_HEAD_HITS,
  89. MICROCHUNKID_STAT_TORSO_HITS,
  90. MICROCHUNKID_STAT_ARM_HITS,
  91. MICROCHUNKID_STAT_LEG_HITS,
  92. MICROCHUNKID_STAT_CROTCH_HITS,
  93. MICROCHUNKID_STAT_WEAPON_ID,
  94. MICROCHUNKID_STAT_WEAPON_COUNT,
  95. };
  96. bool PlayerDataClass::Save( ChunkSaveClass & csave )
  97. {
  98. csave.Begin_Chunk( CHUNKID_VARIABLES );
  99. WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_SCORE, Score, float );
  100. WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_MONEY, Money, float );
  101. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TIME_IN_GAME, StatTimeInGame );
  102. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ENEMIES_KILLED, StatEnemiesKilled );
  103. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ALLIES_KILLED, StatAlliesKilled );
  104. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_SHOTS_FIRED, StatShotsFired );
  105. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_HEAD_SHOTS, StatHeadShots );
  106. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TORSO_SHOTS, StatTorsoShots );
  107. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ARM_SHOTS, StatArmShots );
  108. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_LEG_SHOTS, StatLegShots );
  109. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CROTCH_CHOTS, StatCrotchShots );
  110. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_FINAL_HEALTH, StatFinalHealth );
  111. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_POWERUPS, StatPowerups );
  112. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_VEHICLES_DESTROYED, StatVehiclesDestroyed );
  113. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TIME_IN_VEHICLES, StatTimeInVehicles );
  114. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_KILLS_FROM_VEHICLES, StatKillsFromVehicles );
  115. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_SQUISHES, StatSquishes );
  116. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CREDITS_GRANTED, StatCreditsGranted );
  117. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_BUILDINGS_DESTROYED, StatBuildingsDestroyed );
  118. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_HEAD_HITS, StatHeadHits );
  119. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TORSO_HITS, StatTorsoHits );
  120. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ARM_HITS, StatArmHits );
  121. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_LEG_HITS, StatLegHits );
  122. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CROTCH_HITS, StatCrotchHits );
  123. csave.End_Chunk();
  124. for (int i = 0; i < StatWeaponIDFired.Count(); i++) {
  125. int id = StatWeaponIDFired[i];
  126. int count = StatWeaponFireCount[i];
  127. csave.Begin_Chunk( CHUNKID_STATS_WEAPON );
  128. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_WEAPON_ID, id );
  129. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_WEAPON_COUNT, count );
  130. csave.End_Chunk();
  131. }
  132. return true;
  133. }
  134. bool PlayerDataClass::Load( ChunkLoadClass &cload )
  135. {
  136. StatTimeInSession=0.0f;
  137. StatLastWeaponIndex = -1;
  138. WWASSERT( StatWeaponIDFired.Count() == 0 );
  139. WWASSERT( StatWeaponFireCount.Count() == 0 );
  140. while (cload.Open_Chunk()) {
  141. switch(cload.Cur_Chunk_ID()) {
  142. case CHUNKID_VARIABLES:
  143. while (cload.Open_Micro_Chunk()) {
  144. switch(cload.Cur_Micro_Chunk_ID()) {
  145. READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_SCORE, Score, float );
  146. READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_MONEY, Money, float );
  147. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TIME_IN_GAME, StatTimeInGame );
  148. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ENEMIES_KILLED, StatEnemiesKilled );
  149. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ALLIES_KILLED, StatAlliesKilled );
  150. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_SHOTS_FIRED, StatShotsFired );
  151. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_HEAD_SHOTS, StatHeadShots );
  152. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TORSO_SHOTS, StatTorsoShots );
  153. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ARM_SHOTS, StatArmShots );
  154. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_LEG_SHOTS, StatLegShots );
  155. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CROTCH_CHOTS, StatCrotchShots );
  156. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_FINAL_HEALTH, StatFinalHealth );
  157. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_POWERUPS, StatPowerups );
  158. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_VEHICLES_DESTROYED, StatVehiclesDestroyed );
  159. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TIME_IN_VEHICLES, StatTimeInVehicles );
  160. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_KILLS_FROM_VEHICLES, StatKillsFromVehicles );
  161. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_SQUISHES, StatSquishes );
  162. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CREDITS_GRANTED, StatCreditsGranted );
  163. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_BUILDINGS_DESTROYED, StatBuildingsDestroyed );
  164. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_HEAD_HITS, StatHeadHits );
  165. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TORSO_HITS, StatTorsoHits );
  166. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ARM_HITS, StatArmHits );
  167. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_LEG_HITS, StatLegHits );
  168. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CROTCH_HITS, StatCrotchHits );
  169. default:
  170. Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
  171. break;
  172. }
  173. cload.Close_Micro_Chunk();
  174. }
  175. break;
  176. case CHUNKID_STATS_WEAPON:
  177. {
  178. int id = 0;
  179. int count = 0;
  180. while (cload.Open_Micro_Chunk()) {
  181. switch(cload.Cur_Micro_Chunk_ID()) {
  182. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_WEAPON_ID, id );
  183. READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_WEAPON_COUNT, count );
  184. default:
  185. Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
  186. break;
  187. }
  188. cload.Close_Micro_Chunk();
  189. }
  190. WWASSERT( id != 0 );
  191. StatWeaponIDFired.Add(id);
  192. StatWeaponFireCount.Add(count);
  193. break;
  194. }
  195. default:
  196. Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  197. break;
  198. }
  199. cload.Close_Chunk();
  200. }
  201. return true;
  202. }
  203. void PlayerDataClass::Reset_Player(void)
  204. {
  205. Stats_Reset();
  206. Set_Score( 0 );
  207. Set_Money( 0 );
  208. }
  209. void PlayerDataClass::Increment_Score( float add )
  210. {
  211. if (!CombatManager::Is_Gameplay_Permitted()) {
  212. return;
  213. }
  214. //
  215. // Look out for very big increments
  216. //
  217. static int warning_num = 0;
  218. if (add >= 10000 && ++warning_num < 10) {
  219. WWDEBUG_SAY(("* PlayerDataClass::Increment_Score(%10.2f) - is this ok?\n", add));
  220. LOG_CALL_STACK;
  221. }
  222. Score = (float)Score + add;
  223. //
  224. // TSS101001 - let's try giving 1 credit per point
  225. //
  226. if (add > 0) {
  227. Increment_Money(add);
  228. }
  229. }
  230. void PlayerDataClass::Increment_Money( float add )
  231. {
  232. if (add > 0 && !CombatManager::Is_Gameplay_Permitted()) {
  233. return;
  234. }
  235. //
  236. // Look out for very big increments
  237. //
  238. #pragma message ("(gth) this caused a crash and seems like debugging code so I'm disabling it...")
  239. #if 0
  240. static int warning_num = 0;
  241. if (add >= 10000 && ++warning_num < 10) {
  242. WWDEBUG_SAY(("* PlayerDataClass::Increment_Money(%f) - is this ok?\n", add));
  243. LOG_CALL_STACK;
  244. }
  245. #endif
  246. Money = (float)Money + add;
  247. if ( add > 0 ) {
  248. Stats_Add_Credit_Grant( (int) add );
  249. }
  250. //Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
  251. }
  252. /*
  253. **
  254. */
  255. void PlayerDataClass::Apply_Damage_Points( float points, DamageableGameObj * victim )
  256. {
  257. //Increment_Score( ::fabs(points) );
  258. Increment_Score( points );
  259. // If this is the star's PlayerData, display the points on the HUD
  260. if ( COMBAT_STAR && COMBAT_STAR->Get_Player_Data() == this ) {
  261. HUDClass::Display_Points( points );
  262. }
  263. }
  264. void PlayerDataClass::Apply_Death_Points( float points, DamageableGameObj * victim )
  265. {
  266. Increment_Score( points );
  267. if ( Get_GameObj() == COMBAT_STAR && COMBAT_STAR != NULL ) {
  268. HUDClass::Display_Points( points );
  269. }
  270. }
  271. bool PlayerDataClass::Purchase_Item( int cost )
  272. {
  273. bool retval = false;
  274. if (cost >= 0) {
  275. //
  276. // Check to ensure the player has enough cash
  277. //
  278. float money = (float)Money;
  279. if (money >= cost) {
  280. /*
  281. money -= cost;
  282. Money = money;
  283. */
  284. //
  285. // Use Increment_Money so that dirty is set.
  286. //
  287. Increment_Money(-1 * cost);
  288. retval = true;
  289. }
  290. }
  291. return retval;
  292. }
  293. //
  294. // Import_Rare
  295. //
  296. void PlayerDataClass::Import_Occasional( BitStreamClass & packet )
  297. {
  298. //
  299. // Get the score and money from the server
  300. //
  301. float score = packet.Get(score);
  302. Score = score;
  303. float money = packet.Get(money);
  304. Money = money;
  305. }
  306. //
  307. // Export_Rare
  308. //
  309. void PlayerDataClass::Export_Occasional( BitStreamClass & packet )
  310. {
  311. //
  312. // Transmit the score and money
  313. //
  314. packet.Add ((float)Score);
  315. packet.Add ((float)Money);
  316. }
  317. /*
  318. ** Stats
  319. */
  320. void PlayerDataClass::Stats_Reset( void )
  321. {
  322. StatTimeInGame = 0.0f;
  323. StatTimeInSession = 0.0f;
  324. StatEnemiesKilled = 0;
  325. StatAlliesKilled = 0;
  326. StatShotsFired = 0;
  327. StatHeadShots = 0;
  328. StatTorsoShots = 0;
  329. StatArmShots = 0;
  330. StatLegShots = 0;
  331. StatCrotchShots = 0;
  332. StatFinalHealth = 0;
  333. StatPowerups = 0;
  334. StatVehiclesDestroyed = 0;
  335. StatTimeInVehicles = 0;
  336. StatKillsFromVehicles = 0;
  337. StatSquishes = 0;
  338. StatCreditsGranted = 0;
  339. StatBuildingsDestroyed = 0;
  340. StatHeadHits = 0;
  341. StatTorsoHits = 0;
  342. StatArmHits = 0;
  343. StatLegHits = 0;
  344. StatCrotchHits = 0;
  345. StatLastWeaponIndex = -1;
  346. StatWeaponIDFired.Delete_All();
  347. StatWeaponFireCount.Delete_All();
  348. }
  349. void PlayerDataClass::Stats_Add_Weapon_Fired( int weapon_id )
  350. {
  351. // Check for using same weapon as last time
  352. if ((StatLastWeaponIndex >= 0) && (StatWeaponIDFired[StatLastWeaponIndex] == weapon_id)) {
  353. StatWeaponFireCount[StatLastWeaponIndex]++;
  354. return;
  355. }
  356. // See if we already have this weapon
  357. for (int i = 0; i < StatWeaponIDFired.Count(); i++) {
  358. if (StatWeaponIDFired[i] == weapon_id) {
  359. StatLastWeaponIndex = i;
  360. StatWeaponFireCount[StatLastWeaponIndex]++;
  361. return;
  362. }
  363. }
  364. // Add this new weapon
  365. StatLastWeaponIndex = StatWeaponIDFired.Count();
  366. StatWeaponIDFired.Add(weapon_id);
  367. StatWeaponFireCount.Add(1);
  368. }
  369. //------------------------------------------------------------------------------------
  370. int PlayerDataClass::Get_Weapon_Fired_Count(void) const
  371. {
  372. return StatWeaponIDFired.Count();
  373. }
  374. //------------------------------------------------------------------------------------
  375. bool PlayerDataClass::Get_Weapon_Fired(int index, unsigned long& weaponID, unsigned long& firedCount) const
  376. {
  377. if ((index >= 0) && (index < StatWeaponIDFired.Count())) {
  378. weaponID = (unsigned long)StatWeaponIDFired[index];
  379. firedCount = (unsigned long)StatWeaponFireCount[index];
  380. return true;
  381. }
  382. return false;
  383. }
  384. /*
  385. bool PlayerDataClass::Purchase_Item( int cost )
  386. {
  387. bool retval = false;
  388. //
  389. // Check to ensure the player has enough cash
  390. //
  391. int score = (int)Score;
  392. if (score >= cost) {
  393. score -= cost;
  394. Score = score;
  395. retval = true;
  396. }
  397. return retval;
  398. }
  399. */