/*
**	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/campaign.cpp          $* 
 *                                                                                             * 
 *                      $Author:: Ian_l                                                       $* 
 *                                                                                             * 
 *                     $Modtime:: 1/19/02 12:30p                                              $* 
 *                                                                                             * 
 *                    $Revision:: 33                                                          $* 
 *                                                                                             * 
 *---------------------------------------------------------------------------------------------* 
 * Functions:                                                                                  * 
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "campaign.h"
#include "debug.h"
#include "gamemode.h"
#include "gamedata.h"
#include "singlepl.h"
#include "gdsingleplayer.h"
#include "cnetwork.h"
#include "playertype.h"
#include "gameinitmgr.h"
#include "scorescreen.h"
#include "assets.h"
#include "movie.h"
#include "consolefunction.h"
#include "renegadedialogmgr.h"
#include "registry.h"
#include "_globals.h"
#include "crandom.h"
#include "god.h"
#include "dlgloadspgame.h"
#include "ccamera.h"

/*
**
*/
int	CampaignManager::State = 0;
int	CampaignManager::BackdropIndex = 0;

#define	CAMPAIGN_INI_FILENAME	"campaign.ini"
#define	SECTION_CAMPAIGN			"Campaign"
#define	NOT_IN_CAMPAIGN_STATE	-10
#define	REPLAY_LEVEL			-11
#define	REPLAY_SCORE			-12

DynamicVectorClass<StringClass>	CampaignFlowDescriptions;

struct BackdropDescriptionStruct {
	int State;
	DynamicVectorClass<StringClass>	Lines;

	bool operator == (BackdropDescriptionStruct const & rec) const	{ return false; }
	bool operator != (BackdropDescriptionStruct const & rec) const	{ return true; }
};

DynamicVectorClass<BackdropDescriptionStruct>	BackdropDescriptions;

/*
**
*/
void	CampaignManager::Init( void )
{
	State = NOT_IN_CAMPAIGN_STATE;
	BackdropIndex = 0;

	// Load CAMPAIGN.INI to get campain flow
	INIClass	* campaignINI = Get_INI( CAMPAIGN_INI_FILENAME );
	if (campaignINI != NULL) {
		WWASSERT( campaignINI && campaignINI->Section_Count() > 0 );
		int count =  campaignINI->Entry_Count( SECTION_CAMPAIGN );
		for ( int entry = 0; entry < count; entry++ )	{
			StringClass	description(0,true);
			campaignINI->Get_String(description, SECTION_CAMPAIGN, campaignINI->Get_Entry( SECTION_CAMPAIGN, entry) );
			CampaignFlowDescriptions.Add( description );
		}

		// Load Backdrop Descriptions
		// Load the first 100, because 90-95 are multiplay.. :)
		for ( int state = 0; state < 100; state++ ) {
			StringClass section_name;
			section_name.Format( "Backdrop%d", state );
			int count =  campaignINI->Entry_Count( section_name );
			if ( count != 0 ) {
				int index = BackdropDescriptions.Count();
				BackdropDescriptions.Uninitialized_Add();
				BackdropDescriptions[index].State = state;
				for ( int entry = 0; entry < count; entry++ )	{
					StringClass	description(0,true);
					campaignINI->Get_String(description, section_name, campaignINI->Get_Entry( section_name, entry) );
					BackdropDescriptions[index].Lines.Add( description );
				}
			}

		}

		Release_INI( campaignINI );
	} else {
		Debug_Say(("CampaignManager::Init - Unable to load %s\n", CAMPAIGN_INI_FILENAME));
	}

}


/*
**
*/
void	CampaignManager::Shutdown( void )
{
	CampaignFlowDescriptions.Clear();
}



/*
**
*/
//-----------------------------------------------------------------------------
enum	{
	CHUNKID_VARIABLES = 906011356,

	MICROCHUNK_STATE = 1,
	MICROCHUNK_BACKDROP_INDEX,
};

//-----------------------------------------------------------------------------
bool CampaignManager::Save(ChunkSaveClass & csave)
{
	csave.Begin_Chunk(CHUNKID_VARIABLES);
		WRITE_MICRO_CHUNK(csave, MICROCHUNK_STATE, State);
		WRITE_MICRO_CHUNK(csave, MICROCHUNK_BACKDROP_INDEX, BackdropIndex);
	csave.End_Chunk();
	return true;
}

//-----------------------------------------------------------------------------
bool CampaignManager::Load(ChunkLoadClass &cload)
{
	while (cload.Open_Chunk()) {
		switch(cload.Cur_Chunk_ID()) {

			case CHUNKID_VARIABLES:
				while (cload.Open_Micro_Chunk()) {
					switch(cload.Cur_Micro_Chunk_ID()) {
						READ_MICRO_CHUNK(cload, MICROCHUNK_STATE, State);
						READ_MICRO_CHUNK(cload, MICROCHUNK_BACKDROP_INDEX, BackdropIndex);
						default:
							Debug_Say(( "Unrecognized Campaign Variable chunkID\n" ));
							break;
					}
					cload.Close_Micro_Chunk();
				}
				break;

			default:
				Debug_Say(( "Unrecognized campaign chunkID\n" ));
				break;
		}
		cload.Close_Chunk();
	}

	return true;
}




/*
**
*/
void	CampaignManager::Start_Campaign( int difficulty )
{
	Debug_Say(( "CampaignManager::Start_Campaign( %d )\n", difficulty ));

	State = -1;
	BackdropIndex = 0;

	// Why was this commented out???
	CombatManager::Set_Difficulty_Level( difficulty );

	StringClass diff_string;
	diff_string.Format( "difficulty %d", difficulty );
	ConsoleFunctionManager::Parse_Input( diff_string );

	cGod::Reset_Inventory();

	Continue();
}

/*
**
*/
void	CampaignManager::Continue( bool success )
{
	BackdropIndex = 0;

	if ( State == REPLAY_LEVEL ) {
		State = REPLAY_SCORE;

		// Activeate the Score screen before the combat deactivates, so we can get the stats
		ScoreScreenGameModeClass * ss = (ScoreScreenGameModeClass *)GameModeManager::Find ("ScoreScreen");
		if ( ss != NULL ) {
		 	ss->Save_Stats();
		}

		GameModeManager::Find ("Movie")->Deactivate();
		GameModeManager::Find ("Combat")->Suspend();
		GameInitMgrClass::End_Game();
		GameModeManager::Find ("Menu")->Deactivate();

		if ( ss != NULL ) {
			ss->Activate();
		}
		return;
	}

	if ( State == NOT_IN_CAMPAIGN_STATE || State == REPLAY_SCORE || ( State >= CampaignFlowDescriptions.Count() - 1 ) ) {
		State = NOT_IN_CAMPAIGN_STATE;
		GameModeManager::Find ("Movie")->Deactivate();
		GameModeManager::Find ("ScoreScreen")->Deactivate();		// BMG???
		GameModeManager::Find ("Combat")->Suspend();
		GameInitMgrClass::End_Game();
		GameInitMgrClass::Display_End_Game_Menu();
		return;
	}

	State = State+1;

	Debug_Say(( "CampaignManager::Continue %d\n", State ));

	const char * state_description = CampaignFlowDescriptions[State];

#define	StringMatch(a,b)	(!::strncmp( a,b,strlen(b) ))

	if ( StringMatch( state_description, "Message " ) ) {

		state_description += ::strlen( "Message " );

		GameModeManager::Find ("Movie")->Deactivate();
		GameModeManager::Find ("Combat")->Suspend();
		GameInitMgrClass::End_Game();

		GameModeManager::Find ("Menu")->Deactivate();
		GameModeManager::Find ("ScoreScreen")->Activate();

	} else if ( StringMatch( state_description, "Score" ) ) {

		state_description += ::strlen( "Score" );

		// Activeate the Score screen before the combat deactivates, so we can get the stats
		ScoreScreenGameModeClass * ss = (ScoreScreenGameModeClass *)GameModeManager::Find ("ScoreScreen");
		if ( ss != NULL ) {
		 	ss->Save_Stats();
		}

		GameModeManager::Find ("Movie")->Deactivate();
		GameModeManager::Find ("Combat")->Suspend();
		GameInitMgrClass::End_Game();
		GameModeManager::Find ("Menu")->Deactivate();

		if ( ss != NULL ) {
			ss->Activate();
		}

	} else if ( StringMatch( state_description, "Level " ) ) {


		GameModeManager::Find ("Combat")->Suspend();
		GameModeManager::Find ("Movie")->Deactivate();
	    GameModeManager::Find ("ScoreScreen")->Deactivate ();

		GameInitMgrClass::End_Game();

		state_description += ::strlen( "Level " );

		int mission = cGameData::Get_Mission_Number_From_Map_Name( state_description );
		Select_Backdrop_Number( mission );
		GameInitMgrClass::Start_Game ( state_description, PLAYERTYPE_RENEGADE, 0 );

		// Hack to not autosave for Mission 0 (M13)
		if ( ::strnicmp( state_description, "M13", 3 ) != 0 ) {
			CombatManager::Request_Autosave();
		}

	} else if ( StringMatch( state_description, "Movie " ) ) {

		if (COMBAT_CAMERA != NULL) {
			COMBAT_CAMERA->Set_Host_Model (NULL);
		}

		GameModeManager::Find ("Combat")->Suspend();
		GameInitMgrClass::End_Game();
		GameModeManager::Find ("Menu")->Deactivate();
		GameModeManager::Find ("ScoreScreen")->Deactivate ();

		//
		//	Parse the parameters
		//
		int len = ::strlen( state_description );
		StringClass foo( len + 1, true );
		StringClass filename( len + 1, true );
		StringClass description( len + 1, true );
		::sscanf (state_description, "%s %s %s", foo.Peek_Buffer (), filename.Peek_Buffer (), description.Peek_Buffer ());

		MovieGameModeClass * mode = (MovieGameModeClass *)GameModeManager::Find ("Movie");
		if ( mode ) {
			mode->Activate();
			mode->Start_Movie( filename );

			//
			//	Add this movie name to the registry (that way the user
			// can watch it later)
			//	
			RegistryClass registry( APPLICATION_SUB_KEY_NAME_MOVIES );
			if ( registry.Is_Valid() ) {
				registry.Set_String( filename, description );
			}
		}

	} else {

		Debug_Say(( "Failed to Parse Campaign Description %s\n", state_description ));

		State = NOT_IN_CAMPAIGN_STATE;		
		RenegadeDialogMgrClass::Goto_Location (RenegadeDialogMgrClass::LOC_MAIN_MENU);
	}

}

void	CampaignManager::Reset()
{
	State = NOT_IN_CAMPAIGN_STATE;		
}

/*
**
*/
void	CampaignManager::Replay_Level( const char * mission_name, int difficulty )
{
	State = REPLAY_LEVEL;

	cGod::Reset_Inventory();
	CombatManager::Set_Difficulty_Level( difficulty );

	GameInitMgrClass::Start_Game( mission_name, PLAYERTYPE_RENEGADE, 0 );
}

/*
**
*/
int	CampaignManager::Get_Backdrop_Description_Count( void )
{
	if (BackdropDescriptions.Count() > 0) {
		return BackdropDescriptions[BackdropIndex].Lines.Count();
	}
	return 0;
}

const char * CampaignManager::Get_Backdrop_Description( int index )
{
	return BackdropDescriptions[BackdropIndex].Lines[index];
}

void	CampaignManager::Select_Backdrop_Number( int state_number )
{
	// Find Backdrop Index
	BackdropIndex = 0;
	for ( int i = 0; i < BackdropDescriptions.Count(); i++ ) {
		if ( BackdropDescriptions[i].State == state_number ) {
			BackdropIndex = i;
		}
	}

	if ( BackdropIndex == 0 ) {
		Debug_Say(( "Failed to find load menu for state %d\n", state_number ));
	}
}

void	CampaignManager::Select_Backdrop_Number_By_MP_Type( int type )
{
	//
	//	Setup Load Menu
	//
	/*
	#define	MULTIPLAY_LOAD_MENU_NUMBER_DEATHMATCH			91
	#define	MULTIPLAY_LOAD_MENU_NUMBER_TEAM_DEATHMATCH	92
	#define	MULTIPLAY_LOAD_MENU_NUMBER_CTF					93
	#define	MULTIPLAY_LOAD_MENU_NUMBER_CNC1					94
	#define	MULTIPLAY_LOAD_MENU_NUMBER_CNC2					95
	int load_menu_number = 0;
	if ( type == cGameData::GAME_TYPE_DEATHMATCH ) {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_DEATHMATCH;	
	}
	if ( type == cGameData::GAME_TYPE_TEAM_DEATHMATCH ) {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_TEAM_DEATHMATCH;	
	}
	if ( type == cGameData::GAME_TYPE_CNC ) {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC1;	
		if ( FreeRandom.Get_Int() & 1 ) {
			load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC2;	
		}
	}
	Select_Backdrop_Number( load_menu_number );
	*/

	WWASSERT(type == cGameData::GAME_TYPE_CNC);

	#define	MULTIPLAY_LOAD_MENU_NUMBER_CNC1					94
	#define	MULTIPLAY_LOAD_MENU_NUMBER_CNC2					95

	int load_menu_number = 0;
	if (FreeRandom.Get_Int() & 1) {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC1;
	} else {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CNC2;
	}

//	Select_Backdrop_Number(load_menu_number);
	//forget the random screen, alwayds do 94 (BMG 11/24/01)
	Select_Backdrop_Number( MULTIPLAY_LOAD_MENU_NUMBER_CNC1 );

}





















	/*
	if ( type == cGameData::GAME_TYPE_CTF ) {
		load_menu_number = MULTIPLAY_LOAD_MENU_NUMBER_CTF;	
	}
	*/
