浏览代码

* support for campaign scenarios with no bonuses

mateuszb 13 年之前
父节点
当前提交
7fe2692bf8
共有 4 个文件被更改,包括 110 次插入92 次删除
  1. 3 1
      client/CPreGame.cpp
  2. 7 3
      lib/CCampaignHandler.cpp
  3. 1 1
      lib/CCampaignHandler.h
  4. 99 87
      lib/CGameState.cpp

+ 3 - 1
client/CPreGame.cpp

@@ -2765,7 +2765,6 @@ void CBonusSelection::init()
 
 	startB = new CAdventureMapButton("", "", bind(&CBonusSelection::startMap, this), 475, 536, "CBBEGIB.DEF", SDLK_RETURN);
 	backB = new CAdventureMapButton("", "", bind(&CBonusSelection::goBack, this), 624, 536, "CBCANCB.DEF", SDLK_ESCAPE);
-	startB->setState(CButtonBase::BLOCKED);
 
 	//campaign name
 	if (ourCampaign->camp->header.name.length())
@@ -2810,6 +2809,9 @@ void CBonusSelection::init()
 		}
 	}
 
+	//unlock if no bonuses -- it's acceptable
+	startB->setState( ourCampaign->getCurrentScenario().travelOptions.bonusesToChoose.size() ? CButtonBase::BLOCKED : CButtonBase::NORMAL);
+
 // 	//init campaign state if necessary
 // 	if (ourCampaign->campaignName.size() == 0)
 // 	{

+ 7 - 3
lib/CCampaignHandler.cpp

@@ -426,10 +426,14 @@ void CCampaignState::mapConquered( const std::vector<CGHeroInstance*> & heroes )
 	camp->scenarios[currentMap].conquered = true;
 }
 
-CScenarioTravel::STravelBonus CCampaignState::getBonusForCurrentMap() const
+boost::optional<CScenarioTravel::STravelBonus> CCampaignState::getBonusForCurrentMap() const
 {
-	assert(chosenCampaignBonuses.count(currentMap));
-	return getCurrentScenario().travelOptions.bonusesToChoose[currentBonusID()];
+	auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose;
+	assert(chosenCampaignBonuses.count(currentMap) || bonuses.size() == 0);
+	if(bonuses.size())
+		return bonuses[currentBonusID()];
+	else
+		return boost::optional<CScenarioTravel::STravelBonus>();
 }
 
 const CCampaignScenario & CCampaignState::getCurrentScenario() const

+ 1 - 1
lib/CCampaignHandler.h

@@ -149,7 +149,7 @@ public:
 
 	//void initNewCampaign(const StartInfo &si);
 	void mapConquered(const std::vector<CGHeroInstance*> & heroes);
-	CScenarioTravel::STravelBonus getBonusForCurrentMap() const;
+	boost::optional<CScenarioTravel::STravelBonus> getBonusForCurrentMap() const;
 	const CCampaignScenario &getCurrentScenario() const;
 	ui8 currentBonusID() const;
 

+ 99 - 87
lib/CGameState.cpp

@@ -471,11 +471,11 @@ int CGameState::pickHero(int owner)
 	if(scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
 		auto bonus = scenarioOps->campState->getBonusForCurrentMap();
-		if(bonus.type == CScenarioTravel::STravelBonus::HERO && owner == bonus.info1)
+		if(bonus.is_initialized() && bonus->type == CScenarioTravel::STravelBonus::HERO && owner == bonus->info1)
 		{
-			if(bonus.info2 != 0xffff && !map->getHero(bonus.info2)) //not random and not taken
+			if(bonus->info2 != 0xffff && !map->getHero(bonus->info2)) //not random and not taken
 			{
-				return bonus.info2;
+				return bonus->info2;
 			}
 		}
 	}
@@ -765,14 +765,17 @@ void CGameState::init(StartInfo * si)
 {
 	auto giveCampaignBonusToHero = [&](CGHeroInstance * hero)
 	{
-		const CScenarioTravel::STravelBonus & curBonus = scenarioOps->campState->getBonusForCurrentMap();
-		if(curBonus.isBonusForHero())
+		const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
+		if(!curBonus)
+			return;
+
+		if(curBonus->isBonusForHero())
 		{
 			//apply bonus
-			switch (curBonus.type)
+			switch (curBonus->type)
 			{
 			case CScenarioTravel::STravelBonus::SPELL:
-				hero->spells.insert(curBonus.info2);
+				hero->spells.insert(curBonus->info2);
 				break;
 			case CScenarioTravel::STravelBonus::MONSTER:
 				{
@@ -780,24 +783,24 @@ void CGameState::init(StartInfo * si)
 					{
 						if(hero->slotEmpty(i))
 						{
-							hero->addToSlot(i, curBonus.info2, curBonus.info3);
+							hero->addToSlot(i, curBonus->info2, curBonus->info3);
 							break;
 						}
 					}
 				}
 				break;
 			case CScenarioTravel::STravelBonus::ARTIFACT:
-				gs->giveHeroArtifact(hero, curBonus.info2);
+				gs->giveHeroArtifact(hero, curBonus->info2);
 				break;
 			case CScenarioTravel::STravelBonus::SPELL_SCROLL:
 				{
-					CArtifactInstance * scroll = CArtifactInstance::createScroll(VLC->spellh->spells[curBonus.info2]);
+					CArtifactInstance * scroll = CArtifactInstance::createScroll(VLC->spellh->spells[curBonus->info2]);
 					scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
 				}
 				break;
 			case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
 				{
-					const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus.info2);
+					const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus->info2);
 					for (int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
 					{
 						int val = ptr[g];
@@ -811,7 +814,7 @@ void CGameState::init(StartInfo * si)
 				}
 				break;
 			case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
-				hero->setSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(curBonus.info2), curBonus.info3, true);
+				hero->setSecSkillLevel(static_cast<CGHeroInstance::SecondarySkill>(curBonus->info2), curBonus->info3, true);
 				break;
 			}
 		}
@@ -976,98 +979,108 @@ void CGameState::init(StartInfo * si)
 
 	/*********give starting hero****************************************/
 	tlog4 << "\tGiving starting hero";
-	for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
 	{
-		const PlayerInfo &p = map->players[it->first];
-		bool campaignGiveHero = it->second.human && scenarioOps->mode == StartInfo::CAMPAIGN &&
-			scenarioOps->campState->getBonusForCurrentMap().type == CScenarioTravel::STravelBonus::HERO;
-		bool generateHero = (p.generateHeroAtMainTown || campaignGiveHero) && p.hasMainTown;
-		if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
+		auto bonus = scenarioOps->campState->getBonusForCurrentMap();
+		if(bonus.is_initialized())
 		{
-			int3 hpos = p.posOfMainTown;
-			hpos.x+=1;
-
-			int h = pickHero(it->first);
-			if(it->second.hero == -1)
-				it->second.hero = h;
-
-			CGHeroInstance * nnn =  static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first));
-			nnn->id = map->objects.size();
-			nnn->initHero();
-			map->heroes.push_back(nnn);
-			map->objects.push_back(nnn);
-			map->addBlockVisTiles(nnn);
+			for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
+			{
+				const PlayerInfo &p = map->players[it->first];
+				bool campaignGiveHero = it->second.human && scenarioOps->mode == StartInfo::CAMPAIGN &&
+					bonus.get().type == CScenarioTravel::STravelBonus::HERO;
+				bool generateHero = (p.generateHeroAtMainTown || campaignGiveHero) && p.hasMainTown;
+				if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
+				{
+					int3 hpos = p.posOfMainTown;
+					hpos.x+=1;
+
+					int h = pickHero(it->first);
+					if(it->second.hero == -1)
+						it->second.hero = h;
+
+					CGHeroInstance * nnn =  static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first));
+					nnn->id = map->objects.size();
+					nnn->initHero();
+					map->heroes.push_back(nnn);
+					map->objects.push_back(nnn);
+					map->addBlockVisTiles(nnn);
+				}
+			}
 		}
 	}
+	
 
 	/*************************replace hero placeholders*****************************/
 	tlog4 << "\tReplacing hero placeholders";
 	if (scenarioOps->campState)
 	{
 		auto campaign = scenarioOps->campState;
-		CScenarioTravel::STravelBonus bonus = campaign->getBonusForCurrentMap();
+		auto bonus = campaign->getBonusForCurrentMap();
 
-
-		std::vector<CGHeroInstance *> Xheroes;
-		if (bonus.type == CScenarioTravel::STravelBonus::PLAYER_PREV_SCENARIO)
+		if(bonus.is_initialized())
 		{
-			Xheroes = campaign->camp->scenarios[bonus.info2].crossoverHeroes;
-		}
-
-		//selecting heroes by type
-		for(int g=0; g<map->objects.size(); ++g)
-		{
-			CGObjectInstance * obj = map->objects[g];
-			if (obj->ID != Obj::HERO_PLACEHOLDER)
+			std::vector<CGHeroInstance *> Xheroes;
+			if (bonus->type == CScenarioTravel::STravelBonus::PLAYER_PREV_SCENARIO)
 			{
-				continue;
+				Xheroes = campaign->camp->scenarios[bonus->info2].crossoverHeroes;
 			}
-			CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
 
-			if(hp->subID != 0xFF) //select by type
+			//selecting heroes by type
+			for(int g=0; g<map->objects.size(); ++g)
 			{
-				bool found = false;
-				BOOST_FOREACH(CGHeroInstance * ghi, Xheroes)
+				CGObjectInstance * obj = map->objects[g];
+				if (obj->ID != Obj::HERO_PLACEHOLDER)
 				{
-					if (ghi->subID == hp->subID)
-					{
-						found = true;
-						replaceHero(g, ghi);
-						Xheroes -= ghi;
-						break;
-					}
+					continue;
 				}
-				if (!found)
+				CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
+
+				if(hp->subID != 0xFF) //select by type
 				{
-					//TODO: create new hero of this type
+					bool found = false;
+					BOOST_FOREACH(CGHeroInstance * ghi, Xheroes)
+					{
+						if (ghi->subID == hp->subID)
+						{
+							found = true;
+							replaceHero(g, ghi);
+							Xheroes -= ghi;
+							break;
+						}
+					}
+					if (!found)
+					{
+						//TODO: create new hero of this type
+					}
 				}
 			}
-		}
 
-		//selecting heroes by power
+			//selecting heroes by power
 
-		std::sort(Xheroes.begin(), Xheroes.end(), [](const CGHeroInstance * a, const CGHeroInstance * b)
+			std::sort(Xheroes.begin(), Xheroes.end(), [](const CGHeroInstance * a, const CGHeroInstance * b)
 			{
 				return a->getHeroStrength() > b->getHeroStrength();
 			}); //sort, descending strength
-		for(int g=0; g<map->objects.size(); ++g)
-		{
-			CGObjectInstance * obj = map->objects[g];
-			if (obj->ID != Obj::HERO_PLACEHOLDER)
+			for(int g=0; g<map->objects.size(); ++g)
 			{
-				continue;
-			}
-			CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
+				CGObjectInstance * obj = map->objects[g];
+				if (obj->ID != Obj::HERO_PLACEHOLDER)
+				{
+					continue;
+				}
+				CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
 
-			if (hp->subID == 0xFF) //select by power
-			{
-				if(Xheroes.size() > hp->power - 1)
-					replaceHero(g, Xheroes[hp->power - 1]);
-				else
-					tlog2 << "Warning, to hero to replace!\n";
-				//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
+				if (hp->subID == 0xFF) //select by power
+				{
+					if(Xheroes.size() > hp->power - 1)
+						replaceHero(g, Xheroes[hp->power - 1]);
+					else
+						tlog2 << "Warning, to hero to replace!\n";
+					//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
+				}
 			}
 		}
+		
 	}
 
 	/******************RESOURCES****************************************************/
@@ -1092,17 +1105,17 @@ void CGameState::init(StartInfo * si)
 	//give start resource bonus in case of campaign
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
-		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
-		if(chosenBonus.type == CScenarioTravel::STravelBonus::RESOURCE)
+		auto chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
+		if(chosenBonus.is_initialized() && chosenBonus->type == CScenarioTravel::STravelBonus::RESOURCE)
 		{
 			std::vector<const PlayerSettings *> people = getHumanPlayerInfo(); //players we will give resource bonus
 			BOOST_FOREACH(const PlayerSettings *ps, people)
 			{
 				std::vector<int> res; //resources we will give
-				switch (chosenBonus.info1)
+				switch (chosenBonus->info1)
 				{
 				case 0: case 1: case 2: case 3: case 4: case 5: case 6:
-					res.push_back(chosenBonus.info1);
+					res.push_back(chosenBonus->info1);
 					break;
 				case 0xFD: //wood+ore
 					res.push_back(Res::WOOD); res.push_back(Res::ORE);
@@ -1117,7 +1130,7 @@ void CGameState::init(StartInfo * si)
 				//increasing resource quantity
 				for (int n=0; n<res.size(); ++n)
 				{
-					players[ps->color].resources[res[n]] += chosenBonus.info2;
+					players[ps->color].resources[res[n]] += chosenBonus->info2;
 				}
 			}
 		}
@@ -1176,9 +1189,8 @@ void CGameState::init(StartInfo * si)
 
 	if (scenarioOps->mode == StartInfo::CAMPAIGN) //give campaign bonuses for specific / best hero
 	{
-
-		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
-		if (chosenBonus.isBonusForHero() && chosenBonus.info1 != 0xFFFE) //exclude generated heroes
+		auto chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
+		if (chosenBonus.is_initialized() && chosenBonus->isBonusForHero() && chosenBonus->info1 != 0xFFFE) //exclude generated heroes
 		{
 			//find human player
 			int humanPlayer=GameConstants::NEUTRAL_PLAYER;
@@ -1194,7 +1206,7 @@ void CGameState::init(StartInfo * si)
 
 			std::vector<ConstTransitivePtr<CGHeroInstance> > & heroes = players[humanPlayer].heroes;
 
-			if (chosenBonus.info1 == 0xFFFD) //most powerful
+			if (chosenBonus->info1 == 0xFFFD) //most powerful
 			{
 				int maxB = -1;
 				for (int b=0; b<heroes.size(); ++b)
@@ -1213,7 +1225,7 @@ void CGameState::init(StartInfo * si)
 			{
 				for (int b=0; b<heroes.size(); ++b)
 				{
-					if (heroes[b]->subID == chosenBonus.info1)
+					if (heroes[b]->subID == chosenBonus->info1)
 					{
 						giveCampaignBonusToHero(heroes[b]);
 						break;
@@ -1393,9 +1405,9 @@ void CGameState::init(StartInfo * si)
 	//campaign bonuses for towns
 	if (scenarioOps->mode == StartInfo::CAMPAIGN)
 	{
-		CScenarioTravel::STravelBonus chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
+		auto chosenBonus = scenarioOps->campState->getBonusForCurrentMap();
 
-		if (chosenBonus.type == CScenarioTravel::STravelBonus::BUILDING)
+		if (chosenBonus.is_initialized() && chosenBonus->type == CScenarioTravel::STravelBonus::BUILDING)
 		{
 			for (int g=0; g<map->towns.size(); ++g)
 			{
@@ -1408,7 +1420,7 @@ void CGameState::init(StartInfo * si)
 						map->towns[g]->pos == pi.posOfMainTown + int3(2, 0, 0))
 					{
 						map->towns[g]->builtBuildings.insert(
-							CBuildingHandler::campToERMU(chosenBonus.info1, map->towns[g]->town->typeID, map->towns[g]->builtBuildings));
+							CBuildingHandler::campToERMU(chosenBonus->info1, map->towns[g]->town->typeID, map->towns[g]->builtBuildings));
 						break;
 					}
 				}