Преглед изворни кода

* restoring campaign features
* minor improvements

mateuszb пре 13 година
родитељ
комит
8e3de98059

+ 15 - 2
VCMI_VS10.sln

@@ -1,6 +1,6 @@
 
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual C++ Express 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCMI_client", "client\VCMI_client.vcxproj", "{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCMI_lib", "lib\VCMI_lib.vcxproj", "{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}"
@@ -24,6 +24,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCAI", "AI\VCAI\VCAI.vcxpro
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FuzzyLite", "AI\FuzzyLite\FuzzyLite.vcxproj", "{D15B34EC-A32C-4968-9B0B-66998B579364}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BattleAI", "AI\BattleAI\BattleAI.vcxproj", "{C0300513-E845-43B4-9A4F-E8817EAEF57C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -84,6 +89,14 @@ Global
 		{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|Win32.ActiveCfg = RD|Win32
 		{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|Win32.Build.0 = RD|Win32
 		{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|x64.ActiveCfg = RD|Win32
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.Build.0 = Debug|Win32
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|x64.ActiveCfg = Debug|x64
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|x64.Build.0 = Debug|x64
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|Win32.ActiveCfg = RD|Win32
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|Win32.Build.0 = RD|Win32
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|x64.ActiveCfg = RD|x64
+		{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|x64.Build.0 = RD|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 4 - 4
client/CMT.cpp

@@ -774,10 +774,10 @@ static void listenForEvents()
 			}*/
 			case RETURN_TO_MAIN_MENU:
 				{
-					StartInfo si = *client->getStartInfo();
-					if(si.mode == StartInfo::CAMPAIGN)
-						GH.pushInt( new CBonusSelection(si.campSt) );
-					else
+// 					StartInfo si = *client->getStartInfo();
+// 					if(si.mode == StartInfo::CAMPAIGN)
+// 						GH.pushInt( new CBonusSelection(si.campState) );
+// 					else
 					{
 						endGame();
 						CGPreGame::create();

+ 5 - 3
client/CPlayerInterface.cpp

@@ -2024,7 +2024,8 @@ void CPlayerInterface::gameOver(ui8 player, bool victory )
 		makingTurn = false;
 
 		howManyPeople--;
-		if(!howManyPeople) //all human players eliminated
+		if(!howManyPeople //all human players eliminated
+			&& cb->getStartInfo()->mode != StartInfo::CAMPAIGN) //campaigns are handled in proposeNextMission
 		{
 			requestReturningToMainMenu();
 		}
@@ -2133,6 +2134,9 @@ void CPlayerInterface::acceptTurn()
 
 	//select first hero if available.
 	//TODO: check if hero is slept
+	adventureInt->heroList.update();
+	adventureInt->townList.update();
+
 	if(wanderingHeroes.size())
 		adventureInt->select(wanderingHeroes.front());
 	else
@@ -2141,8 +2145,6 @@ void CPlayerInterface::acceptTurn()
 	//show new day animation and sound on infobar
 	adventureInt->infoBar.showDate();
 
-	adventureInt->heroList.update();
-	adventureInt->townList.update();
 	adventureInt->updateNextHero(NULL);
 	adventureInt->showAll(screen);
 

+ 38 - 23
client/CPreGame.cpp

@@ -793,11 +793,7 @@ void CSelectionScreen::startCampaign()
 {
 	if (SEL->current)
 	{
-		CCampaign * ourCampaign = CCampaignHandler::getCampaign(SEL->current->fileURI);
-		CCampaignState * campState = new CCampaignState();
-		campState->camp = ourCampaign;
-		sInfo.campSt = campState;
-		GH.pushInt( new CBonusSelection(campState) );
+		GH.pushInt(new CBonusSelection(SEL->current->fileURI));
 	}
 }
 
@@ -2756,10 +2752,14 @@ void CHotSeatPlayers::enterSelectionScreen()
 	GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_HOT_SEAT, &names));
 }
 
-CBonusSelection::CBonusSelection( CCampaignState * _ourCampaign )
-: highlightedRegion(NULL), ourCampaign(_ourCampaign), ourHeader(NULL),
-	 diffLb(NULL), diffRb(NULL), bonuses(NULL)
+void CBonusSelection::init()
 {
+	highlightedRegion = nullptr;
+	ourHeader = nullptr;
+	diffLb = nullptr;
+	diffRb = nullptr;
+	bonuses = nullptr;
+
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	static const std::string bgNames [] = {"E1_BG.BMP", "G2_BG.BMP", "E2_BG.BMP", "G1_BG.BMP", "G3_BG.BMP", "N1_BG.BMP",
 		"S1_BG.BMP", "BR_BG.BMP", "IS_BG.BMP", "KR_BG.BMP", "NI_BG.BMP", "TA_BG.BMP", "AR_BG.BMP", "HS_BG.BMP",
@@ -2823,11 +2823,11 @@ CBonusSelection::CBonusSelection( CCampaignState * _ourCampaign )
 		}
 	}
 
-	//init campaign state if necessary
-	if (ourCampaign->campaignName.size() == 0)
-	{
-		ourCampaign->initNewCampaign(sInfo);
-	}
+// 	//init campaign state if necessary
+// 	if (ourCampaign->campaignName.size() == 0)
+// 	{
+// 		ourCampaign->initNewCampaign(sInfo);
+// 	}
 
 	//allies / enemies
 	CSDL_Ext::printAt(CGI->generaltexth->allTexts[390] + ":", 486, 407, FONT_SMALL, Colors::Cornsilk, background); //Allies
@@ -2860,7 +2860,26 @@ CBonusSelection::CBonusSelection( CCampaignState * _ourCampaign )
 
 	//load miniflags
 	sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
+}
 
+
+CBonusSelection::CBonusSelection(shared_ptr<CCampaignState> _ourCampaign)
+	: ourCampaign(std::move(_ourCampaign))
+{
+	init();
+}
+
+CBonusSelection::CBonusSelection( std::string campaignFName )
+{
+	ourCampaign = make_shared<CCampaignState>();
+	ourCampaign->camp = CCampaignHandler::getCampaign(campaignFName);
+	for(int i = 0; i < ourCampaign->camp->scenarios.size(); i++)
+	{
+		ourCampaign->mapsRemaining.push_back(i);
+	}
+
+	sInfo.campState = ourCampaign;
+	init();
 }
 
 CBonusSelection::~CBonusSelection()
@@ -2925,7 +2944,7 @@ void CBonusSelection::selectMap( int whichOne )
 	sInfo.difficulty = ourCampaign->camp->scenarios[whichOne].difficulty;
 	sInfo.mapname = ourCampaign->camp->header.filename;
 	sInfo.mode = StartInfo::CAMPAIGN;
-	sInfo.campSt = ourCampaign;
+	sInfo.campState = ourCampaign;
 	ourCampaign->currentMap = whichOne;
 
 	//get header
@@ -3016,7 +3035,7 @@ void CBonusSelection::updateBonusSelection()
 	//resource - BORES.DEF
 	//player - CREST58.DEF
 	//hero - PORTRAITSLARGE (HPL###.BMPs)
-	const CCampaignScenario &scenario = ourCampaign->camp->scenarios[sInfo.campSt->currentMap];
+	const CCampaignScenario &scenario = ourCampaign->camp->scenarios[sInfo.campState->currentMap];
 	const std::vector<CScenarioTravel::STravelBonus> & bonDescs = scenario.travelOptions.bonusesToChoose;
 
 	for (size_t i=0; i<bonuses->buttons.size(); i++)
@@ -3206,9 +3225,9 @@ void CBonusSelection::selectBonus( int id )
 {
 	// Total redraw is needed because the border around the bonus images
 	// have to be undrawn/drawn.
-	if (id != sInfo.choosenCampaignBonus)
+	if (id != sInfo.campState->currentBonusID())
 	{
-		sInfo.choosenCampaignBonus = id;
+		sInfo.campState->chosenCampaignBonuses[sInfo.campState->currentMap] = id;
 		GH.totalRedraw();
 
 		if (startB->getState() == CButtonBase::BLOCKED)
@@ -3216,7 +3235,7 @@ void CBonusSelection::selectBonus( int id )
 	}
 
 
-	const CCampaignScenario &scenario = ourCampaign->camp->scenarios[sInfo.campSt->currentMap];
+	const CCampaignScenario &scenario = ourCampaign->camp->scenarios[sInfo.campState->currentMap];
 	const std::vector<CScenarioTravel::STravelBonus> & bonDescs = scenario.travelOptions.bonusesToChoose;
 	if (bonDescs[id].type == 8) //hero crossover
 	{
@@ -3566,11 +3585,7 @@ void CCampaignScreen::CCampaignButton::clickLeft(tribool down, bool previousStat
 	{
 		// Close running video and open the selected campaign
 		CCS->videoh->close();
-
-		CCampaign * ourCampaign = CCampaignHandler::getCampaign(campFile);
-		CCampaignState * campState = new CCampaignState();
-		campState->camp = ourCampaign;
-		GH.pushInt( new CBonusSelection(campState) );
+		GH.pushInt( new CBonusSelection(campFile) );
 	}
 }
 

+ 4 - 2
client/CPreGame.h

@@ -415,7 +415,7 @@ class CBonusSelection : public CIntObject
 	CRegion * highlightedRegion;
 
 	void loadPositionsOfGraphics();
-	CCampaignState * ourCampaign;
+	shared_ptr<CCampaignState> ourCampaign;
 	CMapHeader *ourHeader;
 	CDefHandler *sizes; //icons of map sizes
 	SDL_Surface* diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this)
@@ -434,8 +434,10 @@ public:
 
 	void selectMap(int whichOne);
 	void selectBonus(int id);
+	void init();
 
-	CBonusSelection(CCampaignState * _ourCampaign);
+	CBonusSelection(std::string campaignFName);
+	CBonusSelection(shared_ptr<CCampaignState> _ourCampaign);
 	~CBonusSelection();
 
 	void showAll(SDL_Surface * to);

+ 4 - 2
client/Client.cpp

@@ -515,12 +515,14 @@ void CClient::updatePaths()
 		calculatePaths(h);
 }
 
-void CClient::finishCampaign( CCampaignState * camp )
+void CClient::finishCampaign( shared_ptr<CCampaignState> camp )
 {
 }
 
-void CClient::proposeNextMission( CCampaignState * camp )
+void CClient::proposeNextMission(shared_ptr<CCampaignState> camp)
 {
+	endGame(false);
+	LOCPLINT = nullptr; //TODO free res
 	GH.pushInt(new CBonusSelection(camp));
 	GH.curInt = CGP;
 }

+ 2 - 2
client/Client.h

@@ -148,8 +148,8 @@ public:
 	void save(const std::string & fname);
 	void loadGame(const std::string & fname);
 	void run();
-	void finishCampaign( CCampaignState * camp );
-	void proposeNextMission( CCampaignState * camp );
+	void finishCampaign( shared_ptr<CCampaignState> camp );
+	void proposeNextMission(shared_ptr<CCampaignState> camp);
 	void invalidatePaths(const CGHeroInstance *h = NULL); //invalidates paths for hero h or for any hero if h is NULL => they'll got recalculated when the next query comes
 	void calculatePaths(const CGHeroInstance *h);
 	void updatePaths(); //calls calculatePaths for same hero for which we previously calculated paths

+ 35 - 13
lib/CCampaignHandler.cpp

@@ -35,9 +35,9 @@ CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
 	return ret;
 }
 
-CCampaign * CCampaignHandler::getCampaign( const std::string & name)
+unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
 {
-	CCampaign * ret = new CCampaign();
+	auto ret = make_unique<CCampaign>();
 
 	std::vector<std::vector<ui8>> file = getFile(name, false);
 
@@ -63,7 +63,13 @@ CCampaign * CCampaignHandler::getCampaign( const std::string & name)
 			scenarioID++;
 		}
 		//set map piece appropriately
-		ret->mapPieces[scenarioID++] = file[g];
+
+
+		ret->mapPieces[scenarioID].resize(file[g].size());
+		for(int i = 0; i < file[g].size(); i++)
+			ret->mapPieces[scenarioID][i] = file[g][i];
+		
+		scenarioID++;
 	}
 
 	return ret;
@@ -406,16 +412,16 @@ bool CScenarioTravel::STravelBonus::isBonusForHero() const
 	return type == 0 || type == 1 || type == 3 || type == 4 || type == 5 || type == 6;
 }
 
-void CCampaignState::initNewCampaign( const StartInfo &si )
-{
-	assert(si.mode == StartInfo::CAMPAIGN);
-	campaignName = si.mapname;
-	currentMap = si.campSt->currentMap;
-
-	camp = CCampaignHandler::getCampaign(campaignName);
-	for (ui8 i = 0; i < camp->mapPieces.size(); i++)
-		mapsRemaining.push_back(i);
-}
+// void CCampaignState::initNewCampaign( const StartInfo &si )
+// {
+// 	assert(si.mode == StartInfo::CAMPAIGN);
+// 	campaignName = si.mapname;
+// 	currentMap = si.campState->currentMap;
+// 
+// 	camp = CCampaignHandler::getCampaign(campaignName);
+// 	for (ui8 i = 0; i < camp->mapPieces.size(); i++)
+// 		mapsRemaining.push_back(i);
+// }
 
 void CCampaignState::mapConquered( const std::vector<CGHeroInstance*> & heroes )
 {
@@ -424,3 +430,19 @@ void CCampaignState::mapConquered( const std::vector<CGHeroInstance*> & heroes )
 	mapsRemaining -= currentMap;
 	camp->scenarios[currentMap].conquered = true;
 }
+
+CScenarioTravel::STravelBonus CCampaignState::getBonusForCurrentMap() const
+{
+	assert(chosenCampaignBonuses.count(currentMap));
+	return getCurrentScenario().travelOptions.bonusesToChoose[currentBonusID()];
+}
+
+const CCampaignScenario & CCampaignState::getCurrentScenario() const
+{
+	return camp->scenarios[currentMap];
+}
+
+ui8 CCampaignState::currentBonusID() const
+{
+	return chosenCampaignBonuses[currentMap];
+}

+ 12 - 5
lib/CCampaignHandler.h

@@ -124,7 +124,7 @@ class DLL_LINKAGE CCampaign
 public:
 	CCampaignHeader header;
 	std::vector<CCampaignScenario> scenarios;
-	std::map<int, std::vector<ui8> > mapPieces; //binary h3ms, scenario number -> map data
+	std::map<int, std::string > mapPieces; //binary h3ms, scenario number -> map data
 
 	template <typename Handler> void serialize(Handler &h, const int formatVersion)
 	{
@@ -139,17 +139,24 @@ public:
 class DLL_LINKAGE CCampaignState
 {
 public:
-	CCampaign *camp;
+	unique_ptr<CCampaign> camp;
 	std::string campaignName; 
 	std::vector<ui8> mapsConquered, mapsRemaining;
 	ui8 currentMap; 
 
-	void initNewCampaign(const StartInfo &si);
+	bmap<ui8, ui8> chosenCampaignBonuses; //used only for mode CAMPAIGN
+
+	//void initNewCampaign(const StartInfo &si);
 	void mapConquered(const std::vector<CGHeroInstance*> & heroes);
+	CScenarioTravel::STravelBonus getBonusForCurrentMap() const;
+	const CCampaignScenario &getCurrentScenario() const;
+	ui8 currentBonusID() const;
+
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & camp & campaignName & mapsRemaining & mapsConquered & currentMap;
+		h & chosenCampaignBonuses;
 	}
 };
 
@@ -158,12 +165,12 @@ class DLL_LINKAGE CCampaignHandler
 	static CCampaignHeader readHeaderFromMemory( const ui8 *buffer, int & outIt );
 	static CCampaignScenario readScenarioFromMemory( const ui8 *buffer, int & outIt, int version, int mapVersion );
 	static CScenarioTravel readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version);
-	/// returns h3c splitted in parts. 0 = h3c header, 1-end - maps (binary h3m)
+	/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
 	/// headerOnly - only header will be decompressed, returned vector wont have any maps
 	static std::vector< std::vector<ui8> > getFile(const std::string & name, bool headerOnly);
 public:
 
 	static CCampaignHeader getHeader( const std::string & name); //name - name of appropriate file
 
-	static CCampaign * getCampaign(const std::string & name); //name - name of appropriate file
+	static unique_ptr<CCampaign> getCampaign(const std::string & name); //name - name of appropriate file
 };

+ 19 - 21
lib/CGameState.cpp

@@ -753,7 +753,7 @@ void CGameState::init(StartInfo * si)
 		//it's assumed that given hero should receive the bonus
 		static void giveCampaignBonusToHero(CGHeroInstance * hero, const StartInfo * si, const CScenarioTravel & st, CGameState *gs )
 		{
-			const CScenarioTravel::STravelBonus & curBonus = st.bonusesToChoose[si->choosenCampaignBonus];
+			const CScenarioTravel::STravelBonus & curBonus = si->campState->getBonusForCurrentMap();
 			if(curBonus.isBonusForHero())
 			{
 				//apply bonus
@@ -793,7 +793,7 @@ void CGameState::init(StartInfo * si)
 							{
 								continue;
 							}
-							Bonus *bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, si->campSt->currentMap, g);
+							Bonus *bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, si->campState->currentMap, g);
 							hero->addNewBonus(bb);
 						}
 					}
@@ -845,13 +845,12 @@ void CGameState::init(StartInfo * si)
 		break;
 	case StartInfo::CAMPAIGN:
 		{
-			campaign = new CCampaignState();
-			campaign->initNewCampaign(*scenarioOps);
-			assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campSt->currentMap));
+			auto campaign = scenarioOps->campState;
+			assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap));
 
-			std::vector<ui8> &mapContent = campaign->camp->mapPieces[scenarioOps->campSt->currentMap];
+			std::string &mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
 			map = new Mapa();
-			map->initFromBytes((const ui8*)mapContent.data(), mapContent.size());
+			map->initFromBytes((const ui8*)mapContent.c_str(), mapContent.size());
 		}
 		break;
 	case StartInfo::DUEL:
@@ -991,11 +990,10 @@ void CGameState::init(StartInfo * si)
 
 	/*************************replace hero placeholders*****************************/
 
-	if (campaign)
+	if (scenarioOps->campState)
 	{
-
-		CScenarioTravel::STravelBonus bonus =
-			campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions.bonusesToChoose[scenarioOps->choosenCampaignBonus];
+		auto campaign = scenarioOps->campState;
+		CScenarioTravel::STravelBonus bonus = campaign->getBonusForCurrentMap();
 
 
 		std::vector<CGHeroInstance *> Xheroes;
@@ -1078,8 +1076,7 @@ void CGameState::init(StartInfo * si)
 	//give start resource bonus in case of campaign
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
-		CScenarioTravel::STravelBonus chosenBonus =
-			campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions.bonusesToChoose[scenarioOps->choosenCampaignBonus];
+		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
 		if(chosenBonus.type == 7) //resource
 		{
 			std::vector<const PlayerSettings *> people = HLP::getHumanPlayerInfo(scenarioOps); //players we will give resource bonus
@@ -1163,8 +1160,7 @@ void CGameState::init(StartInfo * si)
 	if (scenarioOps->mode == StartInfo::CAMPAIGN) //give campaign bonuses for specific / best hero
 	{
 
-		CScenarioTravel::STravelBonus chosenBonus =
-			campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions.bonusesToChoose[scenarioOps->choosenCampaignBonus];
+		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
 		if (chosenBonus.isBonusForHero() && chosenBonus.info1 != 0xFFFE) //exclude generated heroes
 		{
 			//find human player
@@ -1194,7 +1190,7 @@ void CGameState::init(StartInfo * si)
 				if(maxB < 0)
 					tlog2 << "Warning - cannot give bonus to hero cause there are no heroes!\n";
 				else
-					HLP::giveCampaignBonusToHero(heroes[maxB], scenarioOps, campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions, this);
+					HLP::giveCampaignBonusToHero(heroes[maxB], scenarioOps, scenarioOps->campState->getCurrentScenario().travelOptions, this);
 			}
 			else //specific hero
 			{
@@ -1202,7 +1198,7 @@ void CGameState::init(StartInfo * si)
 				{
 					if (heroes[b]->subID == chosenBonus.info1)
 					{
-						HLP::giveCampaignBonusToHero(heroes[b], scenarioOps, campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions, this);
+						HLP::giveCampaignBonusToHero(heroes[b], scenarioOps, scenarioOps->campState->getCurrentScenario().travelOptions, this);
 						break;
 					}
 				}
@@ -1377,8 +1373,7 @@ void CGameState::init(StartInfo * si)
 	//campaign bonuses for towns
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
-		CScenarioTravel::STravelBonus chosenBonus =
-			campaign->camp->scenarios[scenarioOps->campSt->currentMap].travelOptions.bonusesToChoose[scenarioOps->choosenCampaignBonus];
+		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
 
 		if (chosenBonus.type == 2)
 		{
@@ -2008,7 +2003,10 @@ int CGameState::victoryCheck( ui8 player ) const
 
 	if (p->enteredWinningCheatCode)
 	{ //cheater or tester, but has entered the code...
-		return 1;
+		if(map->victoryCondition.condition == EVictoryConditionType::WINSTANDARD)
+			return -1;
+		else
+			return 1;
 	}
 
 	if(p->human || map->victoryCondition.appliesToAI)
@@ -2213,7 +2211,7 @@ struct statsHLP
 		}
 		return h[best];
 	}
-
+	
 	//calculates total number of artifacts that belong to given player
 	static int getNumberOfArts(const PlayerState * ps)
 	{

+ 1 - 2
lib/CGameState.h

@@ -383,7 +383,6 @@ class DLL_LINKAGE CGameState : public CNonConstInfoCallback
 {
 public:
 	ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
-	ConstTransitivePtr<CCampaignState> campaign;
 	ui8 currentPlayer; //ID of player currently having turn
 	ConstTransitivePtr<BattleInfo> curB; //current battle
 	ui32 day; //total number of days in game
@@ -450,7 +449,7 @@ public:
 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects & campaign;
+		h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
 		h & villages & forts & capitols;
 		if(!h.saving)
 		{

+ 13 - 0
lib/Connection.h

@@ -590,6 +590,12 @@ public:
 		*this << internalPtr;
 	}
 	template <typename T>
+	void saveSerializable(const unique_ptr<T> &data)
+	{
+		T *internalPtr = data.get();
+		*this << internalPtr;
+	}
+	template <typename T>
 	void saveSerializable(const std::vector<T> &data)
 	{
 		ui32 length = data.size();
@@ -894,6 +900,13 @@ public:
 		data.reset(internalPtr);
 	}
 	template <typename T>
+	void loadSerializable(unique_ptr<T> &data)
+	{
+		T *internalPtr;
+		*this >> internalPtr;
+		data.reset(internalPtr);
+	}
+	template <typename T>
 	void loadSerializable(std::vector<T> &data)
 	{
 		READ_CHECK_U32(length);

+ 1 - 1
lib/NetPacks.h

@@ -526,7 +526,7 @@ struct UpdateCampaignState : public CPackForClient //119
 		type = 119;
 	}
 
-	CCampaignState *camp;
+	shared_ptr<CCampaignState> camp;
 	void applyCl(CClient *cl);
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 5 - 6
lib/StartInfo.h

@@ -65,8 +65,9 @@ struct StartInfo
 	ui32 mapfileChecksum; //0 if not relevant
 	ui8 turnTime; //in minutes, 0=unlimited
 	std::string mapname;
-	ui8 choosenCampaignBonus; //used only for mode CAMPAIGN
-	CCampaignState * campSt;
+
+	shared_ptr<CCampaignState> campState;
+
 	PlayerSettings & getIthPlayersSettings(int no)
 	{
 		if(playerInfos.find(no) != playerInfos.end())
@@ -93,15 +94,13 @@ struct StartInfo
 		h & mapfileChecksum;
 		h & turnTime;
 		h & mapname;
-		h & choosenCampaignBonus;
-		h & campSt;
+		h & campState;
 	}
 
 	StartInfo()
 	{
 		mapfileChecksum = seedPostInit = seedToBeUsed = 0;
 		mode = INVALID;
-		choosenCampaignBonus = -1;
-		campSt = nullptr;
+		campState = nullptr;
 	}
 };

+ 3 - 3
server/CGameHandler.cpp

@@ -5037,7 +5037,7 @@ void CGameHandler::checkLossVictory( ui8 player )
 	{
 		end2 = true;
 
-		if(gs->campaign)
+		if(gs->scenarioOps->campState)
 		{
 			std::vector<CGHeroInstance *> hes;
 			BOOST_FOREACH(CGHeroInstance * ghi, gs->map->heroes)
@@ -5047,10 +5047,10 @@ void CGameHandler::checkLossVictory( ui8 player )
 					hes.push_back(ghi);
 				}
 			}
-			gs->campaign->mapConquered(hes);
+			gs->scenarioOps->campState->mapConquered(hes);
 
 			UpdateCampaignState ucs;
-			ucs.camp = gs->campaign;
+			ucs.camp = gs->scenarioOps->campState;
 			sendAndApply(&ucs);
 		}
 	}