This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Combat/playerdata.cpp

472 lines
14 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Combat/playerdata.cpp $*
* *
* $Author:: Byon_g $*
* *
* $Modtime:: 3/29/02 3:40p $*
* *
* $Revision:: 38 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "playerdata.h"
#include "debug.h"
#include "chunkio.h"
#include "wwpacket.h"
#include "persistfactory.h"
#include "combatchunkid.h"
#include "combat.h"
#include "hud.h"
#include "soldier.h"
#include "systeminfolog.h"
#include "stackdump.h"
/*
**
*/
PlayerDataClass::PlayerDataClass( void ) :
Score( 0 ),
Money( 0 ),
PunishTimer( 0 )
{
Stats_Reset();
}
PlayerDataClass::~PlayerDataClass( void )
{
PlayerInfoLog::Append_To_Log(this);
if ( Get_GameObj() ) {
Get_GameObj()->Set_Player_Data( NULL );
}
}
/*
**
*/
enum {
CHUNKID_VARIABLES = 201011247,
CHUNKID_STATS_WEAPON,
MICROCHUNKID_SCORE = 1,
MICROCHUNKID_MONEY,
MICROCHUNKID_STAT_TIME_IN_GAME,
MICROCHUNKID_STAT_ENEMIES_KILLED,
MICROCHUNKID_STAT_ALLIES_KILLED,
MICROCHUNKID_STAT_SHOTS_FIRED,
MICROCHUNKID_STAT_HEAD_SHOTS,
MICROCHUNKID_STAT_TORSO_SHOTS,
MICROCHUNKID_STAT_ARM_SHOTS,
MICROCHUNKID_STAT_LEG_SHOTS,
MICROCHUNKID_STAT_CROTCH_CHOTS,
MICROCHUNKID_STAT_FINAL_HEALTH,
MICROCHUNKID_STAT_POWERUPS,
MICROCHUNKID_STAT_VEHICLES_DESTROYED,
MICROCHUNKID_STAT_TIME_IN_VEHICLES,
MICROCHUNKID_STAT_KILLS_FROM_VEHICLES,
MICROCHUNKID_STAT_SQUISHES,
MICROCHUNKID_STAT_CREDITS_GRANTED,
MICROCHUNKID_STAT_BUILDINGS_DESTROYED,
MICROCHUNKID_STAT_HEAD_HITS,
MICROCHUNKID_STAT_TORSO_HITS,
MICROCHUNKID_STAT_ARM_HITS,
MICROCHUNKID_STAT_LEG_HITS,
MICROCHUNKID_STAT_CROTCH_HITS,
MICROCHUNKID_STAT_WEAPON_ID,
MICROCHUNKID_STAT_WEAPON_COUNT,
};
bool PlayerDataClass::Save( ChunkSaveClass & csave )
{
csave.Begin_Chunk( CHUNKID_VARIABLES );
WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_SCORE, Score, float );
WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_MONEY, Money, float );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TIME_IN_GAME, StatTimeInGame );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ENEMIES_KILLED, StatEnemiesKilled );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ALLIES_KILLED, StatAlliesKilled );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_SHOTS_FIRED, StatShotsFired );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_HEAD_SHOTS, StatHeadShots );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TORSO_SHOTS, StatTorsoShots );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ARM_SHOTS, StatArmShots );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_LEG_SHOTS, StatLegShots );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CROTCH_CHOTS, StatCrotchShots );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_FINAL_HEALTH, StatFinalHealth );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_POWERUPS, StatPowerups );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_VEHICLES_DESTROYED, StatVehiclesDestroyed );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TIME_IN_VEHICLES, StatTimeInVehicles );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_KILLS_FROM_VEHICLES, StatKillsFromVehicles );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_SQUISHES, StatSquishes );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CREDITS_GRANTED, StatCreditsGranted );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_BUILDINGS_DESTROYED, StatBuildingsDestroyed );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_HEAD_HITS, StatHeadHits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_TORSO_HITS, StatTorsoHits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_ARM_HITS, StatArmHits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_LEG_HITS, StatLegHits );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_CROTCH_HITS, StatCrotchHits );
csave.End_Chunk();
for (int i = 0; i < StatWeaponIDFired.Count(); i++) {
int id = StatWeaponIDFired[i];
int count = StatWeaponFireCount[i];
csave.Begin_Chunk( CHUNKID_STATS_WEAPON );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_WEAPON_ID, id );
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STAT_WEAPON_COUNT, count );
csave.End_Chunk();
}
return true;
}
bool PlayerDataClass::Load( ChunkLoadClass &cload )
{
StatTimeInSession=0.0f;
StatLastWeaponIndex = -1;
WWASSERT( StatWeaponIDFired.Count() == 0 );
WWASSERT( StatWeaponFireCount.Count() == 0 );
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID()) {
case CHUNKID_VARIABLES:
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_SCORE, Score, float );
READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_MONEY, Money, float );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TIME_IN_GAME, StatTimeInGame );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ENEMIES_KILLED, StatEnemiesKilled );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ALLIES_KILLED, StatAlliesKilled );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_SHOTS_FIRED, StatShotsFired );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_HEAD_SHOTS, StatHeadShots );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TORSO_SHOTS, StatTorsoShots );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ARM_SHOTS, StatArmShots );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_LEG_SHOTS, StatLegShots );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CROTCH_CHOTS, StatCrotchShots );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_FINAL_HEALTH, StatFinalHealth );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_POWERUPS, StatPowerups );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_VEHICLES_DESTROYED, StatVehiclesDestroyed );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TIME_IN_VEHICLES, StatTimeInVehicles );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_KILLS_FROM_VEHICLES, StatKillsFromVehicles );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_SQUISHES, StatSquishes );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CREDITS_GRANTED, StatCreditsGranted );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_BUILDINGS_DESTROYED, StatBuildingsDestroyed );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_HEAD_HITS, StatHeadHits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_TORSO_HITS, StatTorsoHits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_ARM_HITS, StatArmHits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_LEG_HITS, StatLegHits );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_CROTCH_HITS, StatCrotchHits );
default:
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Micro_Chunk();
}
break;
case CHUNKID_STATS_WEAPON:
{
int id = 0;
int count = 0;
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_WEAPON_ID, id );
READ_MICRO_CHUNK( cload, MICROCHUNKID_STAT_WEAPON_COUNT, count );
default:
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Micro_Chunk();
}
WWASSERT( id != 0 );
StatWeaponIDFired.Add(id);
StatWeaponFireCount.Add(count);
break;
}
default:
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Chunk();
}
return true;
}
void PlayerDataClass::Reset_Player(void)
{
Stats_Reset();
Set_Score( 0 );
Set_Money( 0 );
}
void PlayerDataClass::Increment_Score( float add )
{
if (!CombatManager::Is_Gameplay_Permitted()) {
return;
}
//
// Look out for very big increments
//
static int warning_num = 0;
if (add >= 10000 && ++warning_num < 10) {
WWDEBUG_SAY(("* PlayerDataClass::Increment_Score(%10.2f) - is this ok?\n", add));
LOG_CALL_STACK;
}
Score = (float)Score + add;
//
// TSS101001 - let's try giving 1 credit per point
//
if (add > 0) {
Increment_Money(add);
}
}
void PlayerDataClass::Increment_Money( float add )
{
if (add > 0 && !CombatManager::Is_Gameplay_Permitted()) {
return;
}
//
// Look out for very big increments
//
#pragma message ("(gth) this caused a crash and seems like debugging code so I'm disabling it...")
#if 0
static int warning_num = 0;
if (add >= 10000 && ++warning_num < 10) {
WWDEBUG_SAY(("* PlayerDataClass::Increment_Money(%f) - is this ok?\n", add));
LOG_CALL_STACK;
}
#endif
Money = (float)Money + add;
if ( add > 0 ) {
Stats_Add_Credit_Grant( (int) add );
}
//Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
}
/*
**
*/
void PlayerDataClass::Apply_Damage_Points( float points, DamageableGameObj * victim )
{
//Increment_Score( ::fabs(points) );
Increment_Score( points );
// If this is the star's PlayerData, display the points on the HUD
if ( COMBAT_STAR && COMBAT_STAR->Get_Player_Data() == this ) {
HUDClass::Display_Points( points );
}
}
void PlayerDataClass::Apply_Death_Points( float points, DamageableGameObj * victim )
{
Increment_Score( points );
if ( Get_GameObj() == COMBAT_STAR && COMBAT_STAR != NULL ) {
HUDClass::Display_Points( points );
}
}
bool PlayerDataClass::Purchase_Item( int cost )
{
bool retval = false;
if (cost >= 0) {
//
// Check to ensure the player has enough cash
//
float money = (float)Money;
if (money >= cost) {
/*
money -= cost;
Money = money;
*/
//
// Use Increment_Money so that dirty is set.
//
Increment_Money(-1 * cost);
retval = true;
}
}
return retval;
}
//
// Import_Rare
//
void PlayerDataClass::Import_Occasional( BitStreamClass & packet )
{
//
// Get the score and money from the server
//
float score = packet.Get(score);
Score = score;
float money = packet.Get(money);
Money = money;
}
//
// Export_Rare
//
void PlayerDataClass::Export_Occasional( BitStreamClass & packet )
{
//
// Transmit the score and money
//
packet.Add ((float)Score);
packet.Add ((float)Money);
}
/*
** Stats
*/
void PlayerDataClass::Stats_Reset( void )
{
StatTimeInGame = 0.0f;
StatTimeInSession = 0.0f;
StatEnemiesKilled = 0;
StatAlliesKilled = 0;
StatShotsFired = 0;
StatHeadShots = 0;
StatTorsoShots = 0;
StatArmShots = 0;
StatLegShots = 0;
StatCrotchShots = 0;
StatFinalHealth = 0;
StatPowerups = 0;
StatVehiclesDestroyed = 0;
StatTimeInVehicles = 0;
StatKillsFromVehicles = 0;
StatSquishes = 0;
StatCreditsGranted = 0;
StatBuildingsDestroyed = 0;
StatHeadHits = 0;
StatTorsoHits = 0;
StatArmHits = 0;
StatLegHits = 0;
StatCrotchHits = 0;
StatLastWeaponIndex = -1;
StatWeaponIDFired.Delete_All();
StatWeaponFireCount.Delete_All();
}
void PlayerDataClass::Stats_Add_Weapon_Fired( int weapon_id )
{
// Check for using same weapon as last time
if ((StatLastWeaponIndex >= 0) && (StatWeaponIDFired[StatLastWeaponIndex] == weapon_id)) {
StatWeaponFireCount[StatLastWeaponIndex]++;
return;
}
// See if we already have this weapon
for (int i = 0; i < StatWeaponIDFired.Count(); i++) {
if (StatWeaponIDFired[i] == weapon_id) {
StatLastWeaponIndex = i;
StatWeaponFireCount[StatLastWeaponIndex]++;
return;
}
}
// Add this new weapon
StatLastWeaponIndex = StatWeaponIDFired.Count();
StatWeaponIDFired.Add(weapon_id);
StatWeaponFireCount.Add(1);
}
//------------------------------------------------------------------------------------
int PlayerDataClass::Get_Weapon_Fired_Count(void) const
{
return StatWeaponIDFired.Count();
}
//------------------------------------------------------------------------------------
bool PlayerDataClass::Get_Weapon_Fired(int index, unsigned long& weaponID, unsigned long& firedCount) const
{
if ((index >= 0) && (index < StatWeaponIDFired.Count())) {
weaponID = (unsigned long)StatWeaponIDFired[index];
firedCount = (unsigned long)StatWeaponFireCount[index];
return true;
}
return false;
}
/*
bool PlayerDataClass::Purchase_Item( int cost )
{
bool retval = false;
//
// Check to ensure the player has enough cash
//
int score = (int)Score;
if (score >= cost) {
score -= cost;
Score = score;
retval = true;
}
return retval;
}
*/