浏览代码

- Fixed bug when the type id of the hero placeholder is the same as a already placed hero or prisoned hero

beegee1 12 年之前
父节点
当前提交
9d0387140f
共有 2 个文件被更改,包括 66 次插入11 次删除
  1. 65 11
      lib/CGameState.cpp
  2. 1 0
      lib/CGameState.h

+ 65 - 11
lib/CGameState.cpp

@@ -1127,13 +1127,55 @@ void CGameState::placeCampaignHeroes()
 			const auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes);
 
 			// remove same heroes on the map which will be added through crossover heroes
-			/*for(auto & campaignHeroReplacement : campaignHeroReplacement)
+			// INFO: we will remove heroes because later it may be possible that the API doesn't allow having heroes
+			// with the same hero type id
+			std::vector<CGHeroInstance *> removedHeroes;
+
+			for(auto & campaignHeroReplacement : campaignHeroReplacements)
 			{
-				campaignHeroReplacement.first->subID
-			}*/
+				auto hero = getUsedHero(HeroTypeID(campaignHeroReplacement.first->subID));
+				if(hero)
+				{
+					removedHeroes.push_back(hero);
+					map->heroesOnMap -= hero;
+					map->objects[hero->id.getNum()] = nullptr;
+					map->removeBlockVisTiles(hero, true);
+				}
+			}
 
 			logGlobal->debugStream() << "\tReplace placeholders with heroes";
 			replaceHeroesPlaceholders(campaignHeroReplacements);
+
+			// now add removed heroes again with unused type ID
+			for(auto hero : removedHeroes)
+			{
+				si32 heroTypeId = 0;
+				if(hero->ID == Obj::HERO)
+				{
+					heroTypeId = pickUnusedHeroTypeRandomly(hero->tempOwner);
+				}
+				else if(hero->ID == Obj::PRISON)
+				{
+					auto unusedHeroTypeIds = getUnusedAllowedHeroes();
+					if(!unusedHeroTypeIds.empty())
+					{
+						heroTypeId = std::next(unusedHeroTypeIds.begin(), ran() % unusedHeroTypeIds.size())->getNum();
+					}
+					else
+					{
+						logGlobal->errorStream() << "No free hero type ID found to replace prison.";
+						assert(0);
+					}
+				}
+				else
+				{
+					assert(0); // should not happen
+				}
+
+				hero->subID = heroTypeId;
+				hero->portrait = hero->subID;
+				map->getEditManager()->insertObject(hero, hero->pos);
+			}
 		}
 	}
 }
@@ -1143,7 +1185,7 @@ void CGameState::placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeI
 	townPos.x += 1;
 
 	CGHeroInstance * hero =  static_cast<CGHeroInstance*>(createObject(Obj::HERO, heroTypeId.getNum(), townPos, playerColor));
-	hero->initHero();
+	hero->initHeroDefInfo();
 	map->getEditManager()->insertObject(hero, townPos);
 }
 
@@ -2721,7 +2763,8 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::generateC
 				if(!found)
 				{
 					auto nh = new CGHeroInstance();
-					nh->initHero(HeroTypeID(hp->subID));
+					nh->subID = hp->subID;
+					nh->initHeroDefInfo();
 					campaignHeroReplacements.push_back(std::make_pair(nh, gid));
 				}
 
@@ -2803,22 +2846,33 @@ void CGameState::replaceHeroesPlaceholders(const std::vector<std::pair<CGHeroIns
 		map->heroesOnMap.push_back(heroToPlace);
 		map->objects[heroToPlace->id.getNum()] = heroToPlace;
 		map->addBlockVisTiles(heroToPlace);
-
-		//const auto & travelOptions = scenarioOps->campState->getCurrentScenario().travelOptions;
 	}
 }
 
 bool CGameState::isUsedHero(HeroTypeID hid) const
+{
+	return getUsedHero(hid);
+}
+
+CGHeroInstance * CGameState::getUsedHero(HeroTypeID hid) const
 {
 	for(auto hero : map->heroesOnMap)  //heroes instances initialization
+	{
 		if(hero->subID == hid.getNum())
-			return true;
+		{
+			return hero;
+		}
+	}
 
 	for(auto obj : map->objects) //prisons
-		if(obj && obj->ID == Obj::PRISON  && obj->subID == hid.getNum())
-			return true;
+	{
+		if(obj && obj->ID == Obj::PRISON && obj->subID == hid.getNum())
+		{
+			return dynamic_cast<CGHeroInstance *>(obj.get());
+		}
+	}
 
-	return false;
+	return nullptr;
 }
 
 CGPathNode::CGPathNode()

+ 1 - 0
lib/CGameState.h

@@ -498,6 +498,7 @@ private:
 
 	// ---- misc helpers -----
 
+	CGHeroInstance * getUsedHero(HeroTypeID hid) const;
 	bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
 	std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
 	std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>