1105 lines
28 KiB
C++
1105 lines
28 KiB
C++
|
/*
|
||
|
** 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/Commando/player.cpp $*
|
||
|
* *
|
||
|
* $Author:: Steve_t $*
|
||
|
* *
|
||
|
* $Modtime:: 10/17/02 11:04a $*
|
||
|
* *
|
||
|
* $Revision:: 146 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "player.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "playermanager.h"
|
||
|
#include "teammanager.h"
|
||
|
#include "wwdebug.h"
|
||
|
#include "miscutil.h"
|
||
|
#include "cnetwork.h"
|
||
|
#include "textdisplay.h"
|
||
|
#include "WWAudio.H"
|
||
|
#include "gamedata.h"
|
||
|
#include "wwdebug.h"
|
||
|
#include "chunkio.h"
|
||
|
#include "useroptions.h"
|
||
|
#include "smartgameobj.h"
|
||
|
#include "playertype.h"
|
||
|
#include "translatedb.h"
|
||
|
#include "string_ids.h"
|
||
|
#include "devoptions.h"
|
||
|
#include "colors.h"
|
||
|
#include "persistfactory.h"
|
||
|
#include "combatchunkid.h"
|
||
|
#include "networkobjectfactory.h"
|
||
|
#include "gameobjmanager.h"
|
||
|
#include "gametype.h"
|
||
|
#include "multihud.h"
|
||
|
#include "apppackettypes.h"
|
||
|
#include "messagewindow.h"
|
||
|
#include "playerkill.h"
|
||
|
#include "consolemode.h"
|
||
|
#include "gamespyadmin.h"
|
||
|
|
||
|
|
||
|
DECLARE_NETWORKOBJECT_FACTORY(cPlayer, NETCLASSID_PLAYER);
|
||
|
|
||
|
//
|
||
|
// Class statics
|
||
|
//
|
||
|
const int cPlayer::INVALID_ID = -1000;
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
cPlayer::cPlayer(void) :
|
||
|
ClanID(0),
|
||
|
WOLPoints(0)
|
||
|
{
|
||
|
//WWDEBUG_SAY(("cPlayer::cPlayer\n"));
|
||
|
|
||
|
Id = INVALID_ID;
|
||
|
LadderPoints = 0;
|
||
|
Kills = 0;
|
||
|
Deaths = 0;
|
||
|
Rung = 0;
|
||
|
WolRank = -1;
|
||
|
IpAddress = 0;
|
||
|
Fps = 0;
|
||
|
LastUpdateTimeMs = 0;
|
||
|
DamageScaleFactor = 100;
|
||
|
Ping = -1;
|
||
|
FastSortKey = 0;
|
||
|
NumWolGames = 0;
|
||
|
|
||
|
Reset_Join_Time();
|
||
|
Reset_Total_Time();
|
||
|
Set_Is_In_Game(true);
|
||
|
Set_Is_Waiting_For_Intermission(false);
|
||
|
Set_App_Packet_Type(APPPACKETTYPE_PLAYER);
|
||
|
|
||
|
Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_INITIAL);
|
||
|
Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_INITIAL);
|
||
|
|
||
|
cPlayerManager::Add(this);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
cPlayer::~cPlayer(void)
|
||
|
{
|
||
|
//WWDEBUG_SAY(("* Destroying player object for client %d (%s)\n", Id, Name));
|
||
|
//WWDEBUG_SAY(("cPlayer::~cPlayer\n"));
|
||
|
|
||
|
cPlayerManager::Remove(this);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Delete(void)
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Init(void)
|
||
|
{
|
||
|
WWASSERT(cNetwork::I_Am_Server());
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_CREATION, true);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
enum {
|
||
|
CHUNKID_VARIABLES = 12374,
|
||
|
CHUNKID_PARENT,
|
||
|
|
||
|
MICROCHUNK_ID = 1,
|
||
|
MICROCHUNK_NAME,
|
||
|
MICROCHUNK_PLAYERTYPE,
|
||
|
MICROCHUNK_KILLS,
|
||
|
MICROCHUNK_DEATHS,
|
||
|
XXXMICROCHUNK_SCORE,
|
||
|
MICROCHUNK_NUMLIVES,
|
||
|
MICROCHUNK_TEAMNUMBER,
|
||
|
MICROCHUNK_REMAP_POINTER,
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool cPlayer::Save(ChunkSaveClass & csave)
|
||
|
{
|
||
|
csave.Begin_Chunk(CHUNKID_PARENT);
|
||
|
PlayerDataClass::Save( csave );
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
csave.Begin_Chunk(CHUNKID_VARIABLES);
|
||
|
|
||
|
WRITE_MICRO_CHUNK(csave, MICROCHUNK_ID, Id);
|
||
|
WRITE_MICRO_CHUNK_WIDESTRING(csave, MICROCHUNK_NAME, Name);
|
||
|
WRITE_MICRO_CHUNK(csave, MICROCHUNK_KILLS, Kills());
|
||
|
WRITE_MICRO_CHUNK(csave, MICROCHUNK_DEATHS, Deaths());
|
||
|
WRITE_MICRO_CHUNK(csave, MICROCHUNK_TEAMNUMBER, PlayerType());
|
||
|
void * old_ptr = this;
|
||
|
WRITE_MICRO_CHUNK(csave, MICROCHUNK_REMAP_POINTER, old_ptr);
|
||
|
|
||
|
csave.End_Chunk();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool cPlayer::Load(ChunkLoadClass &cload)
|
||
|
{
|
||
|
void * old_ptr = NULL;
|
||
|
|
||
|
while (cload.Open_Chunk()) {
|
||
|
switch(cload.Cur_Chunk_ID()) {
|
||
|
|
||
|
case CHUNKID_PARENT:
|
||
|
PlayerDataClass::Load( cload );
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
while (cload.Open_Micro_Chunk()) {
|
||
|
|
||
|
switch(cload.Cur_Micro_Chunk_ID()) {
|
||
|
READ_MICRO_CHUNK(cload, MICROCHUNK_ID, Id);
|
||
|
READ_MICRO_CHUNK_WIDESTRING(cload, MICROCHUNK_NAME, Name);
|
||
|
READ_SAFE_MICRO_CHUNK(cload, MICROCHUNK_KILLS, Kills,int);
|
||
|
READ_SAFE_MICRO_CHUNK(cload, MICROCHUNK_DEATHS, Deaths, int);
|
||
|
READ_SAFE_MICRO_CHUNK(cload, MICROCHUNK_TEAMNUMBER, PlayerType, int);
|
||
|
READ_MICRO_CHUNK(cload, MICROCHUNK_REMAP_POINTER, old_ptr);
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized cPlayer Variable chunkID\n" ));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cload.Close_Micro_Chunk();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say(( "Unrecognized cPlayer chunkID\n" ));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
cload.Close_Chunk();
|
||
|
}
|
||
|
|
||
|
if ( old_ptr != NULL ) {
|
||
|
SaveLoadSystemClass::Register_Pointer(old_ptr, this);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::On_Create(void)
|
||
|
{
|
||
|
WWASSERT(cNetwork::I_Am_Client());
|
||
|
|
||
|
//
|
||
|
// Don't show a join message unless:
|
||
|
// - It's MP
|
||
|
// - I am rendering
|
||
|
// - It's not about me
|
||
|
// - His join came after my join (the server will send you existing
|
||
|
// players before your own).
|
||
|
//
|
||
|
|
||
|
if (!IS_MISSION && cPlayerManager::Is_Player_Present(cNetwork::Get_My_Id())) {
|
||
|
|
||
|
WWASSERT(CombatManager::Get_Message_Window() != NULL);
|
||
|
|
||
|
if (cNetwork::Show_Welcome_Message(Name)) {
|
||
|
switch (PlayerType()) {
|
||
|
case PLAYERTYPE_RENEGADE:
|
||
|
{
|
||
|
WideStringClass widestring;
|
||
|
widestring.Format(
|
||
|
L"%s, %s.\n",
|
||
|
TRANSLATION(IDS_MP_WELCOME_RENEGADE),
|
||
|
Name);
|
||
|
//
|
||
|
// Display the message...
|
||
|
//
|
||
|
CombatManager::Get_Message_Window ()->Add_Message (widestring, Vector3 (0.7F, 0.7F, 0.7F));
|
||
|
break;
|
||
|
}
|
||
|
case PLAYERTYPE_NOD:
|
||
|
case PLAYERTYPE_GDI:
|
||
|
{
|
||
|
WideStringClass widestring;
|
||
|
WWASSERT(PTheGameData != NULL);
|
||
|
if (The_Game()->IsTeamChangingAllowed.Is_True()) {
|
||
|
widestring.Format(
|
||
|
L"%s, %s.\n",
|
||
|
TRANSLATION(IDS_MP_WELCOME_RENEGADE),
|
||
|
Name);
|
||
|
} else {
|
||
|
widestring.Format(
|
||
|
L"%s, %s, %s %s %s.\n",
|
||
|
TRANSLATION(IDS_MP_WELCOME_RENEGADE),
|
||
|
Name,
|
||
|
TRANSLATION(IDS_MP_TO),
|
||
|
The_Game()->Get_Team_Word(),
|
||
|
cTeamManager::Get_Team_Name(PlayerType));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Display the message...
|
||
|
//
|
||
|
CombatManager::Get_Message_Window ()->Add_Message (widestring, Vector3 (0.7F, 0.7F, 0.7F));
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
DIE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
switch (PlayerType()) {
|
||
|
case PLAYERTYPE_MUTANT:
|
||
|
case PLAYERTYPE_NEUTRAL:
|
||
|
break;
|
||
|
case PLAYERTYPE_RENEGADE:
|
||
|
{
|
||
|
WideStringClass widestring;
|
||
|
widestring.Format(
|
||
|
L"%s %s\n",
|
||
|
Name,
|
||
|
TRANSLATION(IDS_MP_RENEGADE_JOINS));
|
||
|
|
||
|
//
|
||
|
// Display the message...
|
||
|
//
|
||
|
CombatManager::Get_Message_Window ()->Add_Message (widestring, Vector3 (0.7F, 0.7F, 0.7F));
|
||
|
break;
|
||
|
}
|
||
|
case PLAYERTYPE_NOD:
|
||
|
case PLAYERTYPE_GDI:
|
||
|
{
|
||
|
WideStringClass widestring;
|
||
|
WWASSERT(PTheGameData != NULL);
|
||
|
if (The_Game()->IsTeamChangingAllowed.Is_True()) {
|
||
|
widestring.Format(
|
||
|
L"%s %s\n",
|
||
|
Name,
|
||
|
TRANSLATION(IDS_MP_RENEGADE_JOINS));
|
||
|
} else {
|
||
|
widestring.Format(
|
||
|
L"%s %s %s %s\n",
|
||
|
Name,
|
||
|
TRANSLATION(IDS_MP_TEAMPLAYER_JOINS),
|
||
|
The_Game()->Get_Team_Word(),
|
||
|
cTeamManager::Get_Team_Name(PlayerType));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Display the message...
|
||
|
//
|
||
|
Vector3 color(0.7F, 0.7F, 0.7F);
|
||
|
CombatManager::Get_Message_Window ()->Add_Message (widestring, color);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
DIE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::On_Destroy(void)
|
||
|
{
|
||
|
if (cNetwork::I_Am_Client() &&
|
||
|
GameModeManager::Find("Combat")->Is_Active() &&
|
||
|
The_Game() != NULL &&
|
||
|
The_Game()->Is_Cnc()) {
|
||
|
|
||
|
WideStringClass message;
|
||
|
message.Format(
|
||
|
L"%s %s\n",
|
||
|
Name, TRANSLATION(IDS_MP_PLAYER_LEFT_GAME));
|
||
|
|
||
|
//
|
||
|
// Display the message...
|
||
|
//
|
||
|
CombatManager::Get_Message_Window ()->Add_Message (message, Vector3 (0.7F, 0.7F, 0.7F));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Mark_As_Modified(void)
|
||
|
{
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Id(int id)
|
||
|
{
|
||
|
Id = id;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Name(const WideStringClass & name)
|
||
|
{
|
||
|
Name = name;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Player_Type(int type)
|
||
|
{
|
||
|
WWASSERT(type >= PLAYERTYPE_FIRST && type <= PLAYERTYPE_LAST);
|
||
|
|
||
|
PlayerType = type;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool cPlayer::Is_Team_Player(void)
|
||
|
{
|
||
|
return PlayerType == PLAYERTYPE_NOD || PlayerType == PLAYERTYPE_GDI;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Reset_Player(void)
|
||
|
{
|
||
|
//
|
||
|
// Call base class
|
||
|
//
|
||
|
PlayerDataClass::Reset_Player();
|
||
|
|
||
|
Set_Ladder_Points(0);
|
||
|
Set_Kills(0);
|
||
|
Set_Deaths(0);
|
||
|
|
||
|
Reset_Join_Time();
|
||
|
Reset_Total_Time();
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
Vector3 cPlayer::Get_Color(void) const
|
||
|
{
|
||
|
switch (PlayerType()) {
|
||
|
|
||
|
case PLAYERTYPE_NEUTRAL:
|
||
|
return COLOR_NEUTRAL;
|
||
|
break;
|
||
|
|
||
|
case PLAYERTYPE_RENEGADE:
|
||
|
return COLOR_RENEGADE;
|
||
|
break;
|
||
|
|
||
|
case PLAYERTYPE_NOD:
|
||
|
return Get_Color_For_Team(PLAYERTYPE_NOD);
|
||
|
break;
|
||
|
|
||
|
case PLAYERTYPE_GDI:
|
||
|
return Get_Color_For_Team(PLAYERTYPE_GDI);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
//TSS110101
|
||
|
//This crashed the server in the beta test.
|
||
|
//I don't know how we got here.
|
||
|
//Try making it non-fatal.
|
||
|
//
|
||
|
//DIE;
|
||
|
return COLOR_NEUTRAL; // avoid compiler warning
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Get_Player_String(int rank, WideStringClass & string, bool force_verbose)
|
||
|
{
|
||
|
//
|
||
|
// Compose a string description of a player's stats for display
|
||
|
//
|
||
|
#pragma message("TODO: (TSS) Examine all wide string %s formatting for errors...")
|
||
|
|
||
|
string.Format(L"");
|
||
|
|
||
|
WWASSERT(The_Game() != NULL);
|
||
|
bool is_verbose = force_verbose ||
|
||
|
The_Game()->IsIntermission.Is_True() ||
|
||
|
//MultiHUDClass::Get_Verbose_Lists();
|
||
|
(MultiHUDClass::Get_Playerlist_Format() == PLAYERLIST_FORMAT_FULL);
|
||
|
|
||
|
WideStringClass substring(0, true);
|
||
|
|
||
|
//
|
||
|
// Standing
|
||
|
//
|
||
|
//XXX substring.Format(L" %2d. ", rank);
|
||
|
substring.Format(L" %2d. ", (int) Get_Rung());
|
||
|
string += substring;
|
||
|
|
||
|
//
|
||
|
// Name
|
||
|
//
|
||
|
// GAMESPY
|
||
|
/*
|
||
|
if (IsActive.Is_True()) {
|
||
|
substring.Format(L"%-11s", Name);
|
||
|
} else {
|
||
|
substring.Format(L"%-9s##", Name);
|
||
|
}
|
||
|
*/
|
||
|
if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
substring.Format(L"%-34s", Name);
|
||
|
} else {
|
||
|
substring.Format(L"%-9s", Name);
|
||
|
}
|
||
|
if (IsActive.Is_True()) {
|
||
|
substring += L" ";
|
||
|
} else {
|
||
|
substring += L"##";
|
||
|
}
|
||
|
string += substring;
|
||
|
|
||
|
if (IsInGame.Is_False()) {
|
||
|
//
|
||
|
// Don't show all the other details, just show "RELOADING"
|
||
|
//
|
||
|
substring.Format(L"%s", TRANSLATION(IDS_MP_LOADING));
|
||
|
string += substring;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Kills
|
||
|
//
|
||
|
if (is_verbose) {
|
||
|
substring.Format(L"%-8d", Get_Kills());
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Deaths
|
||
|
//
|
||
|
if (is_verbose) {
|
||
|
substring.Format(L"%-8d", Get_Deaths());
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Kill to Death ratio
|
||
|
//
|
||
|
if (is_verbose) {
|
||
|
float ktd = Get_Kill_To_Death_Ratio();
|
||
|
if (ktd >= 0) {
|
||
|
substring.Format(L"%-8.1f", ktd);
|
||
|
} else {
|
||
|
substring.Format(L"%-8s", "-");
|
||
|
}
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Money.
|
||
|
// Do not show other team's money.
|
||
|
//
|
||
|
WWASSERT(PTheGameData != NULL);
|
||
|
if ((The_Game()->Is_Cnc() || The_Game()->Is_Skirmish()) && is_verbose) {
|
||
|
#ifdef WWDEBUG
|
||
|
bool show = cDevOptions::ShowMoney.Is_True() ||
|
||
|
#else
|
||
|
bool show =
|
||
|
#endif // WWDEBUG
|
||
|
cNetwork::I_Am_Only_Server() ||
|
||
|
(cNetwork::I_Am_Client() &&
|
||
|
cNetwork::Get_My_Player_Object() != NULL &&
|
||
|
(cNetwork::Get_My_Team_Number() == (int) PlayerType));
|
||
|
|
||
|
if (show) {
|
||
|
substring.Format(L"%-8d", (int) Get_Money());
|
||
|
} else {
|
||
|
substring.Format(L"%-8s", "-");
|
||
|
}
|
||
|
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Score
|
||
|
//
|
||
|
substring.Format(L"%-8d", (int) Get_Score());
|
||
|
string += substring;
|
||
|
|
||
|
//
|
||
|
// Ladder Points
|
||
|
//
|
||
|
if (force_verbose && The_Game()->IsLaddered.Is_True()) {
|
||
|
substring.Format(L"%-8d", Get_Ladder_Points());
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// WOL rank
|
||
|
//
|
||
|
if (GameModeManager::Find("WOL")->Is_Active() && is_verbose) {
|
||
|
if ((int)WolRank == -1) {
|
||
|
substring.Format(L"%-8s", L" -");
|
||
|
} else {
|
||
|
substring.Format(L"%-8d", (int)WolRank);
|
||
|
}
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
#ifdef WWDEBUG
|
||
|
//
|
||
|
// Ping
|
||
|
//
|
||
|
if (cDevOptions::ShowPing.Is_True()) {
|
||
|
/*
|
||
|
int ping = Get_Avg_Ping();
|
||
|
if (ping >= 0) {
|
||
|
substring.Format(L"%-8d", ping);
|
||
|
} else {
|
||
|
substring.Format(L"%-8s", L"");
|
||
|
}
|
||
|
*/
|
||
|
int ping = Get_Ping();
|
||
|
if (ping >= 0) {
|
||
|
substring.Format(L"%-8d", ping);
|
||
|
} else {
|
||
|
substring.Format(L"%-8s", L"");
|
||
|
}
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Player Id
|
||
|
//
|
||
|
if (cDevOptions::ShowId.Is_True()) {
|
||
|
substring.Format(L"%-8d", Id);
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fps
|
||
|
//
|
||
|
if (cNetwork::I_Am_Server() && cDevOptions::ShowClientFps.Is_True()) {
|
||
|
substring.Format(L"%-8d", Fps);
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// GameSpy auth. state
|
||
|
//
|
||
|
if (cNetwork::I_Am_Server() && cGameSpyAdmin::Is_Gamespy_Game() &&
|
||
|
cDevOptions::ShowGameSpyAuthState.Is_True()) {
|
||
|
WideStringClass wide_string;
|
||
|
wide_string.Convert_From(cGameSpyAuthMgr::Describe_Auth_State(GameSpyAuthState));
|
||
|
substring.Format(L"%-12s", wide_string);
|
||
|
string += substring;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// IP Address
|
||
|
//
|
||
|
if (cNetwork::I_Am_Server() && cDevOptions::ShowIpAddresses.Is_True()) {
|
||
|
WideStringClass wide_ip;
|
||
|
wide_ip.Convert_From(cNetUtil::Address_To_String(IpAddress));
|
||
|
substring.Format(L"%-30s", wide_ip);
|
||
|
string += substring;
|
||
|
}
|
||
|
#endif // WWDEBUG
|
||
|
|
||
|
if (force_verbose) {
|
||
|
//
|
||
|
// Logged player list has no color so we need to show Nod/GDI
|
||
|
//
|
||
|
//substring.Format(L" T%d", (int) PlayerType);
|
||
|
if (PlayerType == PLAYERTYPE_NOD) {
|
||
|
substring.Format(L" %s", TRANSLATION(IDS_MP_TEAMNAME_MISSIONS_TEAM_0));
|
||
|
} else {
|
||
|
substring.Format(L" %s", TRANSLATION(IDS_MP_TEAMNAME_MISSIONS_TEAM_1));
|
||
|
}
|
||
|
string += substring;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Score(float score)
|
||
|
{
|
||
|
//
|
||
|
// Call base class
|
||
|
//
|
||
|
PlayerDataClass::Set_Score(score);
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Increment_Score(float add)
|
||
|
{
|
||
|
if (!CombatManager::Is_Gameplay_Permitted()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call base class
|
||
|
//
|
||
|
PlayerDataClass::Increment_Score(add);
|
||
|
|
||
|
//
|
||
|
// If this player is on a team, increment the team score
|
||
|
//
|
||
|
if (Is_Team_Player()) {
|
||
|
cTeam * p_team = cTeamManager::Find_Team(Get_Player_Type());
|
||
|
WWASSERT(p_team != NULL);
|
||
|
p_team->Increment_Score(add);
|
||
|
}
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Money(float money)
|
||
|
{
|
||
|
//
|
||
|
// Call base class
|
||
|
//
|
||
|
PlayerDataClass::Set_Money(money);
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Increment_Money(float add)
|
||
|
{
|
||
|
if (!CombatManager::Is_Gameplay_Permitted()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Call base class
|
||
|
//
|
||
|
PlayerDataClass::Increment_Money(add);
|
||
|
|
||
|
/*
|
||
|
//
|
||
|
// If this player is on a team, increment the team money
|
||
|
//
|
||
|
if (Is_Team_Player()) {
|
||
|
cTeam * p_team = cTeamManager::Find_Team(Get_Player_Type());
|
||
|
WWASSERT(p_team != NULL);
|
||
|
p_team->Increment_Money(add);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Ladder_Points(int points)
|
||
|
{
|
||
|
LadderPoints = points;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Kills(int new_kills)
|
||
|
{
|
||
|
WWASSERT(new_kills >= 0);
|
||
|
|
||
|
Kills = new_kills;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Deaths(int new_deaths)
|
||
|
{
|
||
|
WWASSERT(new_deaths >= 0);
|
||
|
|
||
|
Deaths = new_deaths;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_OCCASIONAL, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Wol_Rank(int wol_rank)
|
||
|
{
|
||
|
WWASSERT(wol_rank >= -1);
|
||
|
WolRank = wol_rank;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Rung(int rung)
|
||
|
{
|
||
|
WWASSERT(rung >= 0);
|
||
|
Rung = rung;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Damage_Scale_Factor(int factor)
|
||
|
{
|
||
|
WWASSERT(factor >= 0 && factor <= 100);
|
||
|
DamageScaleFactor = factor;
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Reset_Join_Time(void)
|
||
|
{
|
||
|
JoinTimeMs = TIMEGETTIME();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Increment_Total_Time(void)
|
||
|
{
|
||
|
TotalTimeMs += (TIMEGETTIME() - JoinTimeMs);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Reset_Total_Time(void)
|
||
|
{
|
||
|
TotalTimeMs = 0;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Ip_Address(ULONG ip_address)
|
||
|
{
|
||
|
WWASSERT(ip_address != 0);
|
||
|
|
||
|
WWDEBUG_SAY(("cPlayer::Set_Ip_Address to %s\n",
|
||
|
cNetUtil::Address_To_String(ip_address)));
|
||
|
|
||
|
IpAddress = ip_address;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Fps(int fps)
|
||
|
{
|
||
|
WWASSERT(fps >= 0);
|
||
|
|
||
|
Fps = fps;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Last_Update_Time_Ms(DWORD time_ms)
|
||
|
{
|
||
|
LastUpdateTimeMs = time_ms;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
float cPlayer::Get_Kill_To_Death_Ratio(void) const
|
||
|
{
|
||
|
//
|
||
|
// If Deaths = 0, return -1;
|
||
|
//
|
||
|
float ktd = -1;
|
||
|
if ((int) Deaths > 0) {
|
||
|
ktd = ((int) Kills) / (float) ((int)Deaths);
|
||
|
}
|
||
|
|
||
|
return ktd;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Increment_Kills(void)
|
||
|
{
|
||
|
if (!CombatManager::Is_Gameplay_Permitted()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WWASSERT(cNetwork::I_Am_Server());
|
||
|
|
||
|
Set_Kills((int)Kills + 1);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Increment_Deaths(void)
|
||
|
{
|
||
|
if (!CombatManager::Is_Gameplay_Permitted()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WWASSERT(cNetwork::I_Am_Server());
|
||
|
|
||
|
Set_Deaths((int)Deaths + 1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
//------------------------------------------------------------------------------------
|
||
|
int cPlayer::Get_Avg_Ping(void) const
|
||
|
{
|
||
|
//
|
||
|
// If you are a server this method will return the player's S->C ping.
|
||
|
// If you are a client this method will return your own C->S ping, and
|
||
|
// -1 for anyone else.
|
||
|
//
|
||
|
|
||
|
int ping = -1;
|
||
|
|
||
|
if (cNetwork::I_Am_Server()) {
|
||
|
if (Id > 0) {
|
||
|
cRemoteHost * p_rhost = cNetwork::Get_Server_Rhost(Id);
|
||
|
WWASSERT(p_rhost != NULL);
|
||
|
ping = p_rhost->Get_Average_Internal_Pingtime_Ms();
|
||
|
}
|
||
|
} else if (Id == cNetwork::Get_My_Id()) {
|
||
|
WWASSERT(cNetwork::I_Am_Only_Client());
|
||
|
cRemoteHost * p_rhost = cNetwork::Get_Client_Rhost();
|
||
|
if (p_rhost != NULL) {
|
||
|
//
|
||
|
// It can be NULL as you are quitting
|
||
|
//
|
||
|
ping = p_rhost->Get_Average_Internal_Pingtime_Ms();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ping;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
int cPlayer::Get_Ping(void)
|
||
|
{
|
||
|
//
|
||
|
// Update the ping if we are the server.
|
||
|
//
|
||
|
if (cNetwork::I_Am_Server() && Id > 0) {
|
||
|
cRemoteHost * p_rhost = cNetwork::Get_Server_Rhost(Id);
|
||
|
if (p_rhost != NULL) {
|
||
|
Ping = p_rhost->Get_Average_Internal_Pingtime_Ms();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Ping;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Export_Creation(BitStreamClass &packet)
|
||
|
{
|
||
|
NetworkObjectClass::Export_Creation(packet);
|
||
|
|
||
|
packet.Add_Wide_Terminated_String(Name);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Import_Creation(BitStreamClass &packet)
|
||
|
{
|
||
|
NetworkObjectClass::Import_Creation(packet);
|
||
|
|
||
|
WWASSERT(cNetwork::I_Am_Only_Client());
|
||
|
|
||
|
packet.Get_Wide_Terminated_String(Name.Get_Buffer(256), 256);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Export_Rare(BitStreamClass &packet)
|
||
|
{
|
||
|
packet.Add(Id);
|
||
|
packet.Add((int)LadderPoints);
|
||
|
packet.Add((int)PlayerType);
|
||
|
packet.Add(DamageScaleFactor);
|
||
|
packet.Add(Get_Ping());
|
||
|
|
||
|
packet.Add(IsInGame.Get());
|
||
|
packet.Add(Invulnerable.Get());
|
||
|
packet.Add(IsActive.Get());
|
||
|
|
||
|
packet.Add((int)WolRank);
|
||
|
packet.Add(NumWolGames);
|
||
|
//WWDEBUG_SAY(("cPlayer::Export_Rare NumWolGames = %d\n", NumWolGames));
|
||
|
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Import_Rare(BitStreamClass &packet)
|
||
|
{
|
||
|
int int_placeholder = 0;
|
||
|
|
||
|
Set_Id( packet.Get(int_placeholder));
|
||
|
Set_Ladder_Points( packet.Get(int_placeholder));
|
||
|
Set_Player_Type( packet.Get(int_placeholder));
|
||
|
Set_Damage_Scale_Factor( packet.Get(int_placeholder));
|
||
|
Set_Ping( packet.Get(int_placeholder));
|
||
|
|
||
|
bool bool_placeholder = false;
|
||
|
|
||
|
Set_Is_In_Game( packet.Get(bool_placeholder));
|
||
|
Invulnerable.Set( packet.Get(bool_placeholder));
|
||
|
Set_Is_Active( packet.Get(bool_placeholder));
|
||
|
|
||
|
WolRank = packet.Get(int_placeholder);
|
||
|
NumWolGames = packet.Get(int_placeholder);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Export_Occasional(BitStreamClass &packet)
|
||
|
{
|
||
|
//
|
||
|
// Call the base class
|
||
|
//
|
||
|
PlayerDataClass::Export_Occasional(packet);
|
||
|
|
||
|
packet.Add((int)Kills);
|
||
|
packet.Add((int)Deaths);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Import_Occasional(BitStreamClass &packet)
|
||
|
{
|
||
|
//
|
||
|
// Call the base class
|
||
|
//
|
||
|
PlayerDataClass::Import_Occasional(packet);
|
||
|
|
||
|
int int_placeholder = 0;
|
||
|
|
||
|
Set_Kills( packet.Get(int_placeholder));
|
||
|
Set_Deaths( packet.Get(int_placeholder));
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Is_In_Game(bool state)
|
||
|
{
|
||
|
IsInGame.Set(state);
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Is_Waiting_For_Intermission(bool state)
|
||
|
{
|
||
|
IsWaitingForIntermission.Set(state);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Is_Active(bool flag)
|
||
|
{
|
||
|
if (flag != IsActive.Get()) {
|
||
|
|
||
|
if (cNetwork::I_Am_Client()) {
|
||
|
if (flag == true) {
|
||
|
On_Create();
|
||
|
cPlayerManager::Activated(this);
|
||
|
} else {
|
||
|
On_Destroy();
|
||
|
cPlayerManager::Deactivated(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsActive.Is_False()) {
|
||
|
//
|
||
|
// Anyone who leaves will need to be reauthenticated next tim ethey attempt
|
||
|
// to join.
|
||
|
//
|
||
|
Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_INITIAL);
|
||
|
Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_INITIAL);
|
||
|
}
|
||
|
|
||
|
IsActive.Set(flag);
|
||
|
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
bool cPlayer::Is_Alive_And_Kicking(void) const
|
||
|
{
|
||
|
//
|
||
|
// Abbreviates those players who are human, loaded, and active.
|
||
|
//
|
||
|
|
||
|
return Is_Human() && IsInGame.Is_True() && IsActive.Is_True();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_Num_Wol_Games(int num_games)
|
||
|
{
|
||
|
NumWolGames = num_games;
|
||
|
//WWDEBUG_SAY(("Set_Num_Wol_Games NumWolGames = %d\n", NumWolGames));
|
||
|
Set_Object_Dirty_Bit(NetworkObjectClass::BIT_RARE, true);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_ENUM state)
|
||
|
{
|
||
|
if (state != GameSpyAuthState)
|
||
|
{
|
||
|
GameSpyAuthState = state;
|
||
|
GameSpyAuthStateEntryTimeMs = TIMEGETTIME();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Auth_State_Entry_Time_Ms(DWORD time_ms)
|
||
|
{
|
||
|
GameSpyAuthStateEntryTimeMs = time_ms;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Challenge_String(StringClass & challenge_string)
|
||
|
{
|
||
|
WWASSERT(!challenge_string.Is_Empty());
|
||
|
|
||
|
GameSpyChallengeString = challenge_string;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Hash_Id(StringClass & hash_id)
|
||
|
{
|
||
|
WWASSERT(!hash_id.Is_Empty());
|
||
|
|
||
|
GameSpyHashId = hash_id;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Kick_State(GAMESPY_KICK_STATE_ENUM state)
|
||
|
{
|
||
|
if (state != GameSpyKickState)
|
||
|
{
|
||
|
GameSpyKickState = state;
|
||
|
GameSpyKickStateEntryTimeMs = TIMEGETTIME();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------------
|
||
|
void cPlayer::Set_GameSpy_Kick_State_Entry_Time_Ms(DWORD time_ms)
|
||
|
{
|
||
|
GameSpyKickStateEntryTimeMs = time_ms;
|
||
|
}
|