• We are currently performing site maintenance, parts of civfanatics are currently offline, but will come back online in the coming days. For more updates please see here.

Militaristic City State Gifts

EricB

Prince
Joined
Feb 4, 2013
Messages
404
Location
Michigan
Anyone else seen this bug?

What happens is I have a militaristic city state ally. After a number of turns they gift me a military unit. That's normal. The bug is that they gift a unique unit of another civilization. For example, I'll be playing as Austria and they'll gift me a Russian Cossacks or a Danish Berzerker (sp?).

Happens every game. Sometimes they gift you the standard units, but sometimes the unique units. I'd like to solve this issue, but I'm not really sure where to start looking for what could be causing it.
 
Yeah I have seen that too, although I wouldn't go so far as to call it a 'feature'.

The actual C++ code from CvMinorCivAI.cpp is:
Code:
/// Picks a unique unit for Militaristic city-states
void CvMinorCivAI::DoPickUniqueUnit()
{
	m_eUniqueUnit = NO_UNIT;
	if (GetTrait() == MINOR_CIV_TRAIT_MILITARISTIC)
	{
		// Units from our starting era or before would be no fun because players won't get the chance to use them
		m_eUniqueUnit = GC.getGame().GetRandomUniqueUnitType(/*bIncludeCivsInGame*/false, /*bIncludeStartEraUnits*/false, /*bIncludeOldEras*/false, /*bIncludeRanged*/true);
	}
}

This makes a call to GetRandomUniqueUnitType which is defined in CvGame.cpp thus:

Spoiler :
Code:
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;
}

Unfortunately I see no way of changing the variables by the use of XML alone. Sorry.
 
This is definitely intentional and is considered a feature of militaristic city states.

Each militaristic city state "knows the secret" of a unique unit. If you are their ally and you have the technology to produce it then they'll give it to you. In the city state menu, you can hover over "militaristic" and it'll say which unique unit secret they have.
 
Kind of a neat feature then. I didn't know about the city state interface telling you which unit they'd give you. It does make militaristic city states a bit more valuable then.
 
I guess one man's 'feature' is another man's 'pointless extra'. :mischief:

Really how are these city-states supposed to know about other civ's unique units? And it sort of diminishes those units if they can be given away willy-nilly. That's a technical term. :)
 
I'm pretty sure this "feature" didn't persist in GEM as there was a Military CS pool that accumulated and created a unit (with era appropriate XP) instead of specific gifts being used. It's a default feature, and I'd agree with ExpiredReign, it diminishes the value of unique units to use it. It's pointless flavoring rather than a nice bonus.
 
Back
Top Bottom