UnitTypes CvGame::GetRandomUniqueUnitType(bool bIncludeCivsInGame, bool bIncludeStartEra, bool bIncludeOldEras, bool bIncludeRanged)
{
// Find the unique units that have already been assigned
std::set<UnitTypes> setUniquesAlreadyAssigned;
for(int iMinorLoop = MAX_MAJOR_CIVS; iMinorLoop < MAX_CIV_PLAYERS; iMinorLoop++)
{
PlayerTypes eMinorLoop = (PlayerTypes) iMinorLoop;
CvPlayer* pMinorLoop = &GET_PLAYER(eMinorLoop);
if(pMinorLoop && pMinorLoop->isEverAlive())
{
UnitTypes eUniqueUnit = pMinorLoop->GetMinorCivAI()->GetUniqueUnit();
if(eUniqueUnit != NO_UNIT)
{
setUniquesAlreadyAssigned.insert(eUniqueUnit);
}
}
}
CvWeightedVector<UnitTypes, SAFE_ESTIMATE_NUM_UNITS, true> veUnitRankings;
// Loop through all Unit Classes
for(int iUnitLoop = 0; iUnitLoop < GC.getNumUnitInfos(); iUnitLoop++)
{
const UnitTypes eLoopUnit = (UnitTypes) iUnitLoop;
CvUnitEntry* pkUnitInfo = GC.getUnitInfo(eLoopUnit);
if(pkUnitInfo == NULL)
{
continue;
}
bool bValid = (pkUnitInfo->GetCombat() > 0);
// Unit has combat strength, make sure it isn't only defensive (and with no ranged combat ability)
if(bValid && pkUnitInfo->GetRange() == 0)
{
for(int iPromotionLoop = 0; iPromotionLoop < GC.getNumPromotionInfos(); iPromotionLoop++)
{
const PromotionTypes ePromotion = (PromotionTypes) iPromotionLoop;
CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(ePromotion);
if(pkPromotionInfo)
{
if(pkUnitInfo->GetFreePromotions(iPromotionLoop))
{
if(pkPromotionInfo->IsOnlyDefensive())
{
bValid = false;
break;
}
}
}
}
}
if(!bValid)
continue;
UnitClassTypes eLoopUnitClass = (UnitClassTypes) pkUnitInfo->GetUnitClassType();
CvUnitClassInfo* pkUnitClassInfo = GC.getUnitClassInfo(eLoopUnitClass);
if(pkUnitClassInfo == NULL)
{
CvAssertMsg(false, "UnitClassInfo is NULL. Please send Anton your save file and version.");
continue;
}
// We only want unique units
if(eLoopUnit == pkUnitClassInfo->getDefaultUnitIndex())
continue;
// Is it a unique unit from a civ that is in our game?
if (!bIncludeCivsInGame)
{
for(int iMajorLoop = 0; iMajorLoop < MAX_PLAYERS; iMajorLoop++) // MAX_PLAYERS so that we look at Barbarian UUs (ie. Brute) as well
{
PlayerTypes eMajorLoop = (PlayerTypes) iMajorLoop;
if(GET_PLAYER(eMajorLoop).isAlive())
{
UnitTypes eUniqueUnitInGame = (UnitTypes) GET_PLAYER(eMajorLoop).getCivilizationInfo().getCivilizationUnits(eLoopUnitClass);
if(eLoopUnit == eUniqueUnitInGame)
{
bValid = false;
break;
}
}
}
}
if(!bValid)
continue;
// Avoid Recon units
if(pkUnitInfo->GetDefaultUnitAIType() == UNITAI_EXPLORE)
continue;
// No Ranged units?
if(!bIncludeRanged && pkUnitInfo->GetRangedCombat() > 0)
continue;
// Must be land Unit
if(pkUnitInfo->GetDomainType() != DOMAIN_LAND)
continue;
// Technology level
TechTypes ePrereqTech = (TechTypes) pkUnitInfo->GetPrereqAndTech();
EraTypes ePrereqEra = NO_ERA;
if (ePrereqTech != NO_TECH)
{
CvTechEntry* pkTechInfo = GC.getTechInfo(ePrereqTech);
CvAssertMsg(pkTechInfo, "Tech info not found when picking unique unit for minor civ. Please send Anton your save file and version!");
if (pkTechInfo)
{
ePrereqEra = (EraTypes) pkTechInfo->GetEra();
}
}
if (ePrereqEra == getStartEra())
{
if (!bIncludeStartEra)
continue;
}
else if (ePrereqEra < getStartEra()) // Assumption: NO_ERA < 0
{
if (!bIncludeOldEras)
continue;
}
// Is this Unit already assigned to another minor civ?
if (setUniquesAlreadyAssigned.count(eLoopUnit) > 0)
continue;
veUnitRankings.push_back(eLoopUnit, 1);
}
UnitTypes eChosenUnit = NO_UNIT;
if (veUnitRankings.size() > 0)
{
veUnitRankings.SortItems();
RandomNumberDelegate randFn = MakeDelegate(&GC.getGame(), &CvGame::getJonRandNum);
eChosenUnit = veUnitRankings.ChooseByWeight(&randFn, "Choosing random unique unit for minor civ");
}
return eChosenUnit;
}