/*
**	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/gdcnc.cpp                           $*
 *                                                                                             *
 *                      $Author:: Bhayes                                                      $*
 *                                                                                             *
 *                     $Modtime:: 4/15/02 4:12p                                               $*
 *                                                                                             *
 *                    $Revision:: 47                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "gdcnc.h"

#include "specialbuilds.h"
#include "cnetwork.h"
#include "translatedb.h"
#include "string_ids.h"
#include "assets.h"
#include "multihud.h"
#include "playerdata.h"
#include "player.h"
#include "playertype.h"
#include "consolemode.h"


//-----------------------------------------------------------------------------
cGameDataCnc::cGameDataCnc(void)	:
	IsPlaying (false),
	cGameData()
{
   //WWDEBUG_SAY(("cGameDataCnc::cGameDataCnc\n"));

	Set_Time_Limit_Minutes(25);
	Set_Ini_Filename("svrcfg_cnc.ini");
	Set_Ip_And_Port();
	BaseDestructionEndsGame.Set(true);
	BeaconPlacementEndsGame.Set(true);
	StartingCredits = 0;
	IsTeamChangingAllowed.Set(false);
	RemixTeams.Set(true);
	Set_Radar_Mode(RADAR_TEAMMATES);
}

//-----------------------------------------------------------------------------
cGameDataCnc::~cGameDataCnc(void)
{
   //WWDEBUG_SAY(("cGameDataCnc::~cGameDataCnc\n"));
}

//-----------------------------------------------------------------------------
cGameDataCnc& cGameDataCnc::operator=(const cGameDataCnc& rhs)
{
	//
	// Call the base class
	//
	cGameData::operator=(rhs);

	BaseDestructionEndsGame				= rhs.BaseDestructionEndsGame;
	BeaconPlacementEndsGame				= rhs.BeaconPlacementEndsGame;
	StartingCredits						= rhs.StartingCredits;

	return (*this);
}

//-----------------------------------------------------------------------------
const WCHAR* cGameDataCnc::Get_Static_Game_Name(void)
{
	return TRANSLATION(IDS_MP_GAME_TYPE_CNC);
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Reset_Game(bool is_reloaded)
{
   WWDEBUG_SAY(("cGameDataCnc::Reset_Game\n"));

	cGameData::Reset_Game(is_reloaded);

	//
	// TSS091201 - hack - On_Game_End not called in correct places
	//
	if (IsPlaying) {
		BaseGDI.Shutdown ();
		BaseNOD.Shutdown ();
		IsPlaying = false;
	}

	//
	//	Initialize the base controllers
	//
	BaseGDI.Initialize ( PLAYERTYPE_GDI );
	BaseNOD.Initialize ( PLAYERTYPE_NOD );
	return ;
}

//-----------------------------------------------------------------------------
void
cGameDataCnc::On_Game_Begin (void)
{
   WWDEBUG_SAY(("cGameDataCnc::On_Game_Begin\n"));

	cGameData::On_Game_Begin();

	CombatManager::Set_Beacon_Placement_Ends_Game(BeaconPlacementEndsGame.Get());

	//
	//	Initialize the bases
	//
	IsPlaying = true;
	return ;
}

//-----------------------------------------------------------------------------
void
cGameDataCnc::On_Game_End (void)
{
   WWDEBUG_SAY(("cGameDataCnc::On_Game_End\n"));

	//
	//	Close the bases
	//
	BaseGDI.Shutdown ();
	BaseNOD.Shutdown ();
	IsPlaying = false;

	cGameData::On_Game_End();
	return ;
}

//-----------------------------------------------------------------------------
void
cGameDataCnc::Soldier_Added (SoldierGameObj *soldier)
{
	cGameData::Soldier_Added (soldier);

	//
	//	Give the soldier some starting credits
	//
	if (	soldier != NULL &&
			soldier->Get_Player_Data() != NULL &&
			soldier->Get_Player_Data()->Get_Game_Time () == 0)
	{
		soldier->Get_Player_Data ()->Set_Money (StartingCredits);
	}

	return ;
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Think(void)
{
	cGameData::Think();

	if (!cNetwork::I_Am_Server()) {
		return;
	}

	//
	//	Let the bases think
	//
	if (IsPlaying) {
		BaseGDI.Think ();
		BaseNOD.Think ();
	}

	return ;
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Set_Starting_Credits(int credits)
{
   Set_Generic_Num(credits, 0, MAX_CREDITS, StartingCredits);
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Export_Tier_2_Data(cPacket & packet)
{
	cGameData::Export_Tier_2_Data(packet);

	packet.Add(BaseDestructionEndsGame.Get());
	packet.Add(BeaconPlacementEndsGame.Get());
	packet.Add(StartingCredits);
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Import_Tier_2_Data(cPacket & packet)
{
	cGameData::Import_Tier_2_Data(packet);

   bool	b_placeholder;
   int	i_placeholder;

	BaseDestructionEndsGame.Set(	packet.Get(b_placeholder));
	BeaconPlacementEndsGame.Set(	packet.Get(b_placeholder));
	Set_Starting_Credits(			packet.Get(i_placeholder));
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Base_Destruction_Score_Tweaking(void)
{
	WWASSERT(cNetwork::I_Am_Server());

	cTeam * p_nod = cTeamManager::Find_Team(PLAYERTYPE_NOD);
	WWASSERT(p_nod != NULL);

	cTeam * p_gdi = cTeamManager::Find_Team(PLAYERTYPE_GDI);
	WWASSERT(p_gdi != NULL);

	float nod_score = p_nod->Get_Score();
	float gdi_score = p_gdi->Get_Score();

	const int BASE_DESTRUCTION_POINTS_REWARD = 5000;

	//
	// Base destroyer gets a points reward.
	// If this isn't enough to beat other team, nudge score ahead by 1 point.
	//

	if (BaseGDI.Is_Base_Destroyed()) {

		nod_score += BASE_DESTRUCTION_POINTS_REWARD;
		if (nod_score <= gdi_score) {
			nod_score = gdi_score + 1;
		}

		p_nod->Set_Score(nod_score);

	} else {

		WWASSERT(BaseNOD.Is_Base_Destroyed());

		gdi_score += BASE_DESTRUCTION_POINTS_REWARD;
		if (gdi_score <= nod_score) {
			gdi_score = nod_score + 1;
		}

		p_gdi->Set_Score(gdi_score);
	}
}

//-----------------------------------------------------------------------------
bool cGameDataCnc::Is_Game_Over(void)
{
	WWASSERT(cNetwork::I_Am_Server());

 	bool is_game_over = cGameData::Is_Game_Over();

	if (!is_game_over && BaseDestructionEndsGame.Is_True())
	{
		//
		// If a base is destroyed then the game is over and the other team wins.
		// To ensure this we may need to tweak the base-destroyer's score.
		//

		if (BaseGDI.Is_Base_Destroyed() || BaseNOD.Is_Base_Destroyed()) {
			is_game_over = true;
			Base_Destruction_Score_Tweaking();

			if (BaseGDI.Did_Beacon_Destroy_Base() || BaseNOD.Did_Beacon_Destroy_Base()) {
				Set_Win_Type(WIN_TYPE_BEACON);
			} else {
				Set_Win_Type(WIN_TYPE_BASE_DESTRUCTION);
			}
		}
	}

	//
	// Beacon placement end game works via above base destruction method.
	//

	return is_game_over;
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Load_From_Server_Config(void)
{
	cGameData::Load_From_Server_Config(Get_Ini_Filename());

   INIClass * p_ini = Get_INI(Get_Ini_Filename());
   WWASSERT(p_ini != NULL);

   bool				b;
   int				i;
   //float				f;


   i = p_ini->Get_Int(	INI_SECTION_NAME, "MaxPlayers",					Get_Max_Players());
	Set_Max_Players(i);

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "IsFriendlyFirePermitted",	IsFriendlyFirePermitted.Get());
	IsFriendlyFirePermitted.Set(b);

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "DoMapsLoop",	DoMapsLoop);
	DoMapsLoop = b;

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "IsTeamChangingAllowed",	IsTeamChangingAllowed.Get());
	IsTeamChangingAllowed.Set(b);

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "IsClanGame",					IsClanGame.Get());
	IsClanGame.Set(b);

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "BaseDestructionEndsGame",			BaseDestructionEndsGame.Get());
	BaseDestructionEndsGame.Set(b);

	b = p_ini->Get_Bool(	INI_SECTION_NAME, "BeaconPlacementEndsGame",	BeaconPlacementEndsGame.Get());
	BeaconPlacementEndsGame.Set(b);

   i = p_ini->Get_Int(	INI_SECTION_NAME, "StartingCredits",				Get_Starting_Credits());
	Set_Starting_Credits(i);



	Release_INI(p_ini);
	return ;
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Save_To_Server_Config(void)
{
	cGameData::Save_To_Server_Config(Get_Ini_Filename());

   INIClass * p_ini = Get_INI(Get_Ini_Filename());
   WWASSERT(p_ini != NULL);


	p_ini->Put_Bool(	INI_SECTION_NAME, "IsFriendlyFirePermitted",	IsFriendlyFirePermitted.Get());
	p_ini->Put_Bool(	INI_SECTION_NAME, "DoMapsLoop",					DoMapsLoop);
	p_ini->Put_Bool(	INI_SECTION_NAME, "IsTeamChangingAllowed",	IsTeamChangingAllowed.Get());
	p_ini->Put_Bool(	INI_SECTION_NAME, "IsClanGame",					IsClanGame.Get());
   p_ini->Put_Int(	INI_SECTION_NAME, "MaxPlayers",					Get_Max_Players());
	p_ini->Put_Bool(	INI_SECTION_NAME, "BaseDestructionEndsGame",	BaseDestructionEndsGame.Get());
	p_ini->Put_Bool(	INI_SECTION_NAME, "BeaconPlacementEndsGame",	BeaconPlacementEndsGame.Get());
	p_ini->Put_Int(   INI_SECTION_NAME, "StartingCredits",			Get_Starting_Credits());


	Save_INI(p_ini, Get_Ini_Filename());
   Release_INI(p_ini);
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Show_My_Money(void)
{
	if (cNetwork::I_Am_Client()) {
		cPlayer * p_player = cNetwork::Get_My_Player_Object();
		if (p_player != NULL) {
			WideStringClass text(0,true);
			text.Format(L"%s: %d",
				TRANSLATION(IDS_MP_MONEY), (int) p_player->Get_Money());
			Add_Bottom_Text(text);
		}
	}
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Show_Game_Settings_Limits(void)
{
	/*
	if (IsIntermission.Is_True()) {
		return;
	}
	*/

	Show_My_Money();

	cGameData::Show_Game_Settings_Limits();
}

//-----------------------------------------------------------------------------
bool cGameDataCnc::Is_Limited(void) const
{
	return Is_Time_Limit() || BaseDestructionEndsGame.Is_True();
}

//-----------------------------------------------------------------------------
void cGameDataCnc::Get_Description(WideStringClass & description)
{
	//
	// Call base class
	//
	cGameData::Get_Description(description);

	const WideStringClass delimiter	= L"\t";
	const WideStringClass newline		= L"\n";
	const WideStringClass yes			= TRANSLATE(IDS_YES);
	const WideStringClass no			= TRANSLATE(IDS_NO);

	WideStringClass attribute(0, true);
	WideStringClass value(0, true);

	//
	// Starting Credits
	//
	attribute = TRANSLATE(IDS_MENU_TEXT349);
	value.Format(L"%d", StartingCredits);
	description += (attribute + delimiter + value + newline);

	//
	// Base Destruction Ends Game
	//
	attribute = TRANSLATE(IDS_MENU_TEXT314);
	value = (BaseDestructionEndsGame.Get() ? yes : no);
	description += (attribute + delimiter + value + newline);

	//
	// Beacon Placement Ends Game
	//
	attribute = TRANSLATE(IDS_MENU_TEXT315);
	value = (BeaconPlacementEndsGame.Get() ? yes : no);
	description += (attribute + delimiter + value + newline);
}



#define PRINT_CONFIG_ERROR	ConsoleBox.Print("File %s - Error:\r\n\t ", Get_Ini_Filename());

//-----------------------------------------------------------------------------
bool cGameDataCnc::Is_Valid_Settings(WideStringClass& outMsg, bool check_as_server)
{
	/*
	** Check the base settings first.
	*/
	if (!cGameData::Is_Valid_Settings(outMsg, check_as_server)) {
		return(false);
	}

#ifdef FREEDEDICATEDSERVER
	if (BaseDestructionEndsGame.Is_False() && BeaconPlacementEndsGame.Is_True()) {
		//cHelpText::Set(TRANSLATION(IDS_MP_GAMEMODE_NEEDS_LIMIT));
		PRINT_CONFIG_ERROR;
		ConsoleBox.Print("Cannot allow beacons to end game without base destruction ending game.\n\n");
		outMsg = TRANSLATE(IDS_HOPTERR_NO_GAMEEND);
		return false;
	}
#endif

	return(true);
}

//-----------------------------------------------------------------------------
bool cGameDataCnc::Is_Gameplay_Permitted(void)
{
	bool permitted = cGameData::Is_Gameplay_Permitted();

	if (permitted && Get_Max_Players() > 1)
	{
		//
		// If your maxplayers is set to more than 1 then you must have an opponent.
		//
		permitted = 
			cPlayerManager::Tally_Team_Size(PLAYERTYPE_NOD) > 0 &&
			cPlayerManager::Tally_Team_Size(PLAYERTYPE_GDI) > 0;
	}

	return permitted;
}









/*
void cGameDataCnc::Get_Description(WideStringClass & description)
{
	//
	// Call base class
	//
	cGameData::Get_Description(description);

	const WideStringClass newline	= L"\n";
	const WideStringClass yes		= L"yes";
	const WideStringClass no		= L"no";

	WideStringClass line(0, true);

   line.Format(L"Starting Credits\t%d", StartingCredits);
	IDS_MENU_TEXT349
	description += line;
	description += newline;

   line.Format(L"Base Destruction Ends Game\t%s",		BaseDestructionEndsGame.Get() ? yes : no);
	IDS_MENU_TEXT314
	description += line;
	description += newline;

   line.Format(L"Beacon Placement Ends Game\t%s",		BeaconPlacementEndsGame.Get() ? yes : no);
	IDS_MENU_TEXT315
	description += line;
	description += newline;
}
*/

//-----------------------------------------------------------------------------