Bazaar developer reference

CvCitySpecializationAI::AssignSpecializations()

Defined in
CvCitySpecializationAI.cpp, line 636
Class
CvCitySpecializationAI
Hook name
CivHooks::CvCitySpecializationAI_AssignSpecializations

Hooks

static bool BeforeCvCitySpecializationAI_AssignSpecializations(CvCitySpecializationAI* self);static void AfterCvCitySpecializationAI_AssignSpecializations(CvCitySpecializationAI* self);static void ReplaceCvCitySpecializationAI_AssignSpecializations(void (*original)(CvCitySpecializationAI*), CvCitySpecializationAI* self);CivRegisterBefore<CivHooks::CvCitySpecializationAI_AssignSpecializations>(host, &BeforeCvCitySpecializationAI_AssignSpecializations);CivRegisterAfter<CivHooks::CvCitySpecializationAI_AssignSpecializations>(host, &AfterCvCitySpecializationAI_AssignSpecializations);CivRegisterReplace<CivHooks::CvCitySpecializationAI_AssignSpecializations>(host, &ReplaceCvCitySpecializationAI_AssignSpecializations);

Code

635/// Assign specializations to cities636void CvCitySpecializationAI::AssignSpecializations()637{638	int iI;639	CitySpecializationTypes eSpecialization;640	CitySpecializationData cityData;641	list<CitySpecializationData> citiesWithoutSpecialization;642	list<CitySpecializationTypes>::iterator it;643	list<CitySpecializationTypes>::iterator iterEnd;644	list<CitySpecializationData>::iterator cityIter;645	list<CitySpecializationData>::iterator cityIterEnd;646	list<CitySpecializationData>::iterator bestCity;647648	m_eNextSpecializationDesired = NO_CITY_SPECIALIZATION;649	citiesWithoutSpecialization.clear();650651	CitySpecializationTypes eWonderSpecialiation = GetWonderSpecialization();652653	// Find specializations needed (including for the next city we build)654	SelectSpecializations();655656	// OBVIOUS ASSIGNMENTS: Loop through our cities making obvious assignments657	CvCity* pLoopCity;658	int iLoop;659	for(pLoopCity = m_pPlayer->firstCity(&iLoop); pLoopCity != NULL; pLoopCity = m_pPlayer->nextCity(&iLoop))660	{661		if(pLoopCity->IsPuppet())662		{663			pLoopCity->GetCityStrategyAI()->SetSpecialization(GetEconomicDefaultSpecialization());664			LogSpecializationAssignment(pLoopCity, GetEconomicDefaultSpecialization(), true);665			continue;666		}667668		// If this is the city to build our current wonder in, mark all that669		if(m_bWonderChosen && pLoopCity->GetID() == m_iWonderCityID)670		{671			it = find(m_SpecializationsNeeded.begin(), m_SpecializationsNeeded.end(), eWonderSpecialiation);672			if(it != m_SpecializationsNeeded.end())673			{674				m_SpecializationsNeeded.erase(it);675				pLoopCity->GetCityStrategyAI()->SetSpecialization(eWonderSpecialiation);676				LogSpecializationAssignment(pLoopCity, eWonderSpecialiation, true);677				continue;678			}679		}680681		// If city default is equal to a needed type, go with that682		eSpecialization = pLoopCity->GetCityStrategyAI()->GetDefaultSpecialization();683		it = find(m_SpecializationsNeeded.begin(), m_SpecializationsNeeded.end(), eSpecialization);684		if(it != m_SpecializationsNeeded.end())685		{686			m_SpecializationsNeeded.erase(it);687			pLoopCity->GetCityStrategyAI()->SetSpecialization(eSpecialization);688			LogSpecializationAssignment(pLoopCity, eSpecialization);689		}690		else691		{692			// If cities' current specialization is needed, stick with that693			eSpecialization = pLoopCity->GetCityStrategyAI()->GetSpecialization();694			it = find(m_SpecializationsNeeded.begin(), m_SpecializationsNeeded.end(), eSpecialization);695			if(it != m_SpecializationsNeeded.end())696			{697				m_SpecializationsNeeded.erase(it);698				pLoopCity->GetCityStrategyAI()->SetSpecialization(eSpecialization);699				LogSpecializationAssignment(pLoopCity, eSpecialization);700			}701702			// Save this city off (with detailed data about what it is good at) to assign later703			else704			{705				cityData.m_eID = pLoopCity->GetID();706				for(iI = 0; iI <= YIELD_SCIENCE; iI++)707				{708					if(iI == YIELD_SCIENCE)709					{710						cityData.m_iWeight[iI] = PlotValueForScience(pLoopCity->plot()); // -- BKW, looks like PlotValueForScience is making some assumptions that are no longer true711					}712					else713					{714						cityData.m_iWeight[iI] = PlotValueForSpecificYield(pLoopCity->plot(), (YieldTypes)iI);715					}716					cityData.m_iWeight[iI] = AdjustValueBasedOnBuildings(pLoopCity, (YieldTypes)iI, cityData.m_iWeight[iI]);717					if(cityData.m_iWeight[iI] < 0)718					{719						cityData.m_iWeight[iI] = 0;720					}721				}722				citiesWithoutSpecialization.push_back(cityData);723724				LogCity(pLoopCity, cityData);725726			}727		}728	}729730	FAssert(citiesWithoutSpecialization.size() + 1 == m_SpecializationsNeeded.size());731732	// NEXT SPECIALIZATION NEEDED: Now figure out what we want to assign as our "next specialization needed"733734	// If only one specialization left, it's easy735	if(citiesWithoutSpecialization.empty())736	{737		it = m_SpecializationsNeeded.begin();738		m_eNextSpecializationDesired = *it;739		LogNextSpecialization(m_eNextSpecializationDesired);740		return;741	}742743	// If all specializations left are "general economic", set that as next needed744	bool bAllGeneral = true;745	it = m_SpecializationsNeeded.begin();746	iterEnd = m_SpecializationsNeeded.end();747	for(; it != iterEnd; ++it)748	{749		CitySpecializationTypes eType = *it;750		if(eType != GetEconomicDefaultSpecialization())751		{752			bAllGeneral = false;753		}754	}755756	if(bAllGeneral)757	{758		m_eNextSpecializationDesired = GetEconomicDefaultSpecialization();759		LogNextSpecialization(m_eNextSpecializationDesired);760		m_SpecializationsNeeded.erase(m_SpecializationsNeeded.begin());761	}762763	else764	{765		// Find best possible sites for each of the yield types766		FindBestSites();767768		// Compute the yield which we can improve the most with a new city769		int iCurrentDelta;770		int iBestDelta[YIELD_SCIENCE + 1];771		for(iI = 0; iI <= YIELD_SCIENCE; iI++)772		{773			iBestDelta[iI] = MIN_INT;774		}775		cityIter = citiesWithoutSpecialization.begin();776		cityIterEnd = citiesWithoutSpecialization.end();777		for(; cityIter != cityIterEnd; ++cityIter)778		{779			cityData = *cityIter;780			for(iI = 0; iI <= YIELD_SCIENCE; iI++)781			{782				iCurrentDelta = cityData.m_iWeight[iI] - m_iBestValue[iI];783				if(iCurrentDelta > iBestDelta[iI])784				{785					iBestDelta[iI] = iCurrentDelta;786				}787			}788		}789790		// Save yield improvements in a vector we can sort791		CvWeightedVector<int, YIELD_SCIENCE+1, true> yieldImprovements;792		for(iI = 0; iI <= YIELD_SCIENCE; iI++)793		{794			int iImprovementWithNewCity;795			if(iBestDelta[iI] > 0)796			{797				iImprovementWithNewCity = 0;798			}799			else800			{801				iImprovementWithNewCity = -iBestDelta[iI];802			}803			yieldImprovements.push_back(iI, iImprovementWithNewCity);804		}805		yieldImprovements.SortItems();806807		// Take them out in order and see if we need this specialization808		bool bFoundIt = false;809		for(iI = 0; iI < yieldImprovements.size(); iI++)810		{811			YieldTypes eMostImprovedYield = (YieldTypes)yieldImprovements.GetElement(iI);812813			// Loop through needed specializations until we find one that matches814			it = m_SpecializationsNeeded.begin();815			iterEnd = m_SpecializationsNeeded.end();816			for(; it != iterEnd; ++it)817			{818				CitySpecializationTypes eType = *it;819				YieldTypes eYield = GC.getCitySpecializationInfo(eType)->GetYieldType();820				if(eYield == eMostImprovedYield)821				{822					m_eNextSpecializationDesired = eType;823					LogNextSpecialization(m_eNextSpecializationDesired);824					m_SpecializationsNeeded.erase(it);825					bFoundIt = true;826					break;827				}828			}829			if(bFoundIt)830			{831				break;832			}833		}834	}835836	FAssert(citiesWithoutSpecialization.size() == m_SpecializationsNeeded.size());837838	// REMAINING ASSIGNMENTS: Make the rest of the assignments839	it = m_SpecializationsNeeded.begin();840	iterEnd = m_SpecializationsNeeded.end();841	for(; it != iterEnd; ++it)842	{843		const CitySpecializationTypes eType = *it;844		CvCitySpecializationXMLEntry* pkCitySpecializationEntry = GC.getCitySpecializationInfo(eType);845		if(pkCitySpecializationEntry == NULL)846			continue;847848		YieldTypes eYield = pkCitySpecializationEntry->GetYieldType();849		bool bCoastal = pkCitySpecializationEntry->IsMustBeCoastal();850		bestCity = citiesWithoutSpecialization.end();851852		// Pick best existing city based on a better computation of existing city's value for a yield type853		int iBestValue = -1;854		cityIter = citiesWithoutSpecialization.begin();855		cityIterEnd = citiesWithoutSpecialization.end();856		for(; cityIter != cityIterEnd; ++cityIter)857		{858			cityData = *cityIter;859860			if(bCoastal && !m_pPlayer->getCity(cityData.m_eID)->isCoastal(100))861			{862				continue;863			}864865			if(eYield == NO_YIELD)866			{867				// General economic is all yields added together868				int iCityValue = 0;869				for(iI = 0; iI <= YIELD_SCIENCE; iI++)870				{871					iCityValue += cityData.m_iWeight[iI];872				}873				if(iCityValue > iBestValue)874				{875					iBestValue = iCityValue;876					bestCity = cityIter;877				}878			}879			else880			{881				if(cityData.m_iWeight[(int)eYield] > iBestValue)882				{883					iBestValue = cityData.m_iWeight[(int)eYield];884					bestCity = cityIter;885				}886			}887		}888889		// Found a city to set890		if(bestCity != citiesWithoutSpecialization.end())891		{892			CvCity* pCity = m_pPlayer->getCity(bestCity->m_eID);893			pCity->GetCityStrategyAI()->SetSpecialization(eType);894			LogSpecializationAssignment(pCity, eType);895			citiesWithoutSpecialization.erase(bestCity);896		}897898		// No (coastal) city found, use default specialization as last resort899		else900		{901			CvCity* pCity = m_pPlayer->getCity(citiesWithoutSpecialization.begin()->m_eID);902			pCity->GetCityStrategyAI()->SetSpecialization(GetEconomicDefaultSpecialization());903			LogSpecializationAssignment(pCity, GetEconomicDefaultSpecialization());904			citiesWithoutSpecialization.erase(citiesWithoutSpecialization.begin());905		}906	}907908	return;909}

Calls

Called by