/* ** Command & Conquer Generals(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 . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: CampaignManager.cpp ///////////////////////////////////////////////// //----------------------------------------------------------------------------- // // Electronic Arts Pacific. // // Confidential Information // Copyright (C) 2002 - All Rights Reserved // //----------------------------------------------------------------------------- // // created: Jul 2002 // // Filename: CampaignManager.cpp // // author: Chris Huybregts // // purpose: The flow of the campaigns are stored up in here! // //----------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- // SYSTEM INCLUDES //////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // USER INCLUDES ////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "Common/INI.h" #include "Common/Xfer.h" #include "GameClient/CampaignManager.h" #include "GameClient/GameClient.h" //----------------------------------------------------------------------------- // DEFINES //////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- CampaignManager *TheCampaignManager = NULL; const FieldParse CampaignManager::m_campaignFieldParseTable[] = { { "Mission", CampaignManager::parseMissionPart, NULL, NULL }, { "FirstMission", INI::parseAsciiString, NULL, offsetof( Campaign, m_firstMission ) }, { "CampaignNameLabel", INI::parseAsciiString, NULL, offsetof( Campaign, m_campaignNameLabel ) }, { "FinalVictoryMovie", INI::parseAsciiString, NULL, offsetof( Campaign, m_finalMovieName ) }, { NULL, NULL, NULL, 0 } // keep this last }; //----------------------------------------------------------------------------- // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void INI::parseCampaignDefinition( INI *ini ) { AsciiString name; Campaign *campaign; // read the name const char* c = ini->getNextToken(); name.set( c ); // find existing item if present DEBUG_ASSERTCRASH( TheCampaignManager, ("parseCampaignDefinition: Unable to Get TheCampaignManager\n") ); if( !TheCampaignManager ) return; // If we have a previously allocated Campaign campaign = TheCampaignManager->newCampaign( name ); // sanity DEBUG_ASSERTCRASH( campaign, ("parseCampaignDefinition: Unable to allocate campaign '%s'\n", name.str()) ); // parse the ini definition ini->initFromINI( campaign, TheCampaignManager->getFieldParse() ); } // end parseCampaignDefinition //----------------------------------------------------------------------------- Campaign::Campaign( void ) { m_missions.clear(); m_firstMission.clear(); m_name.clear(); m_finalMovieName.clear(); } //----------------------------------------------------------------------------- Campaign::~Campaign( void ) { MissionListIt it = m_missions.begin(); while(it != m_missions.end()) { Mission *mission = *it; it = m_missions.erase( it ); if(mission) mission->deleteInstance(); } } AsciiString Campaign::getFinalVictoryMovie( void ) { return m_finalMovieName; } //----------------------------------------------------------------------------- Mission *Campaign::newMission( AsciiString name ) { MissionListIt it; it = m_missions.begin(); name.toLower(); while(it != m_missions.end()) { Mission *mission = *it; if(mission->m_name.compare(name) == 0) { m_missions.erase( it ); mission->deleteInstance(); break; } else ++it; } Mission *newMission = newInstance(Mission); newMission->m_name.set(name); m_missions.push_back(newMission); return newMission; } //----------------------------------------------------------------------------- Mission *Campaign::getMission( AsciiString missionName ) { if(missionName.isEmpty()) return NULL; MissionListIt it; it = m_missions.begin(); // we've reached the end of the campaign while(it != m_missions.end()) { Mission *mission = *it; if(mission->m_name.compare(missionName) == 0) return mission; ++it; } DEBUG_ASSERTCRASH(FALSE, ("getMission couldn't find %s", missionName.str())); return NULL; } //----------------------------------------------------------------------------- Mission *Campaign::getNextMission( Mission *current) { AsciiString name; //if passed a Null pointer, load the first mission if(!current) { name = m_firstMission; } else name = current->m_nextMission; name.toLower(); MissionListIt it; it = m_missions.begin(); // we've reached the end of the campaign if(name.isEmpty()) return NULL; while(it != m_missions.end()) { Mission *mission = *it; if(mission->m_name.compare(name) == 0) return mission; ++it; } // DEBUG_ASSERTCRASH(FALSE, ("GetNextMission couldn't find %s", current->m_nextMission.str())); return NULL; } //----------------------------------------------------------------------------- CampaignManager::CampaignManager( void ) { m_campaignList.clear(); m_currentCampaign = NULL; m_currentMission = NULL; m_victorious = FALSE; m_currentRankPoints = 0; m_difficulty = DIFFICULTY_NORMAL; } //----------------------------------------------------------------------------- CampaignManager::~CampaignManager( void ) { m_currentCampaign = NULL; m_currentMission = NULL; CampaignListIt it = m_campaignList.begin(); while(it != m_campaignList.end()) { Campaign *campaign = *it; it = m_campaignList.erase( it ); if(campaign) campaign->deleteInstance(); } } //----------------------------------------------------------------------------- void CampaignManager::init( void ) { INI ini; // Read from INI all the CampaignManager ini.load( AsciiString( "Data\\INI\\Campaign.ini" ), INI_LOAD_OVERWRITE, NULL ); } //----------------------------------------------------------------------------- Campaign *CampaignManager::getCurrentCampaign( void ) { return m_currentCampaign; } //----------------------------------------------------------------------------- Mission *CampaignManager::getCurrentMission( void ) { return m_currentMission; } //----------------------------------------------------------------------------- Mission *CampaignManager::gotoNextMission( void ) { if (!m_currentCampaign || !m_currentMission) return NULL; m_currentMission = m_currentCampaign->getNextMission(m_currentMission); return m_currentMission; } //----------------------------------------------------------------------------- void CampaignManager::setCampaignAndMission( AsciiString campaign, AsciiString mission ) { if(mission.isEmpty()) { setCampaign(campaign); return; } CampaignListIt it; it = m_campaignList.begin(); campaign.toLower(); while ( it != m_campaignList.end()) { Campaign *camp = *it; if(camp->m_name.compare(campaign) == 0) { m_currentCampaign = camp; m_currentMission = camp->getMission( mission ); return; } ++it; } } //----------------------------------------------------------------------------- void CampaignManager::setCampaign( AsciiString campaign ) { CampaignListIt it; it = m_campaignList.begin(); campaign.toLower(); while ( it != m_campaignList.end()) { Campaign *camp = *it; if(camp->m_name.compare(campaign) == 0) { m_currentCampaign = camp; m_currentMission = camp->getNextMission( NULL ); return; } ++it; } // could not find the mission. we are resetting the missions to nothing. m_currentCampaign = NULL; m_currentMission = NULL; m_currentRankPoints = 0; m_difficulty = DIFFICULTY_NORMAL; } //----------------------------------------------------------------------------- AsciiString CampaignManager::getCurrentMap( void ) { if(!m_currentMission) return AsciiString::TheEmptyString; return m_currentMission->m_mapName; } // ------------------------------------------------------------------------------------------------ /** Return the 0 based mission number */ // ------------------------------------------------------------------------------------------------ Int CampaignManager::getCurrentMissionNumber( void ) { Int number = INVALID_MISSION_NUMBER; if( m_currentCampaign ) { Campaign::MissionListIt it; for( it = m_currentCampaign->m_missions.begin(); it != m_currentCampaign->m_missions.end(); ++it ) { number++; if( *it == m_currentMission ) return number; } } return number; } //----------------------------------------------------------------------------- void CampaignManager::parseMissionPart( INI* ini, void *instance, void *store, const void *userData ) { static const FieldParse myFieldParse[] = { { "Map", INI::parseAsciiString, NULL, offsetof( Mission, m_mapName ) }, { "NextMission", INI::parseAsciiString, NULL, offsetof( Mission, m_nextMission ) }, { "IntroMovie", INI::parseAsciiString, NULL, offsetof( Mission, m_movieLabel ) }, { "ObjectiveLine0", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[0] ) }, { "ObjectiveLine1", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[1] ) }, { "ObjectiveLine2", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[2] ) }, { "ObjectiveLine3", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[3] ) }, { "ObjectiveLine4", INI::parseAsciiString, NULL, offsetof( Mission, m_missionObjectivesLabel[4] ) }, { "BriefingVoice", INI::parseAudioEventRTS, NULL, offsetof( Mission, m_briefingVoice ) }, { "UnitNames0", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[0] ) }, { "UnitNames1", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[1] ) }, { "UnitNames2", INI::parseAsciiString, NULL, offsetof( Mission, m_unitNames[2] ) }, { "LocationNameLabel",INI::parseAsciiString, NULL, offsetof( Mission, m_locationNameLabel ) }, { "VoiceLength", INI::parseInt , NULL, offsetof( Mission, m_voiceLength ) }, { NULL, NULL, NULL, 0 } // keep this last }; AsciiString name; const char* c = ini->getNextToken(); name.set( c ); Mission *mission = ((Campaign*)instance)->newMission(name ); ini->initFromINI(mission, myFieldParse); } //----------------------------------------------------------------------------- Campaign *CampaignManager::newCampaign(AsciiString name) { CampaignListIt it; it = m_campaignList.begin(); name.toLower(); while(it != m_campaignList.end()) { Campaign *campaign = *it; if(campaign->m_name.compare(name) == 0) { m_campaignList.erase( it ); campaign->deleteInstance(); break; } else ++it; } Campaign *newCampaign = newInstance(Campaign); newCampaign->m_name.set(name); m_campaignList.push_back(newCampaign); return newCampaign; } // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info * 1: Initial version * 2: Added RankPoints Saving*/ // ------------------------------------------------------------------------------------------------ void CampaignManager::xfer( Xfer *xfer ) { // version const XferVersion currentVersion = 3; XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // current campaign AsciiString currentCampaign; if( m_currentCampaign ) currentCampaign = m_currentCampaign->m_name; xfer->xferAsciiString( ¤tCampaign ); // current mission AsciiString currentMission; if( m_currentMission ) currentMission = m_currentMission->m_name; xfer->xferAsciiString( ¤tMission ); // version 2 and above has rank points! if(version >= 2) xfer->xferInt( &m_currentRankPoints ); if(version >= 3) xfer->xferUser( &m_difficulty, sizeof(m_difficulty) ); // when loading, need to set the current campaign and mission if( xfer->getXferMode() == XFER_LOAD ) setCampaignAndMission( currentCampaign, currentMission ); } // end xfer //----------------------------------------------------------------------------- // PRIVATE FUNCTIONS ////////////////////////////////////////////////////////// //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- Mission::Mission( void ) { m_voiceLength = 0; } //----------------------------------------------------------------------------- Mission::~Mission( void ) { }