Difference between GetBaseYieldRateFromSpecialists and getExtraSpecialistYield?

Tokata_RuNeLess

Chieftain
Joined
Sep 17, 2015
Messages
39
Location
USTC in Hefei, China
I wanna add a table to the game as Specialist_ResourceQuantity. So I edited CvInfos.cpp and CvCity.cpp.

While reading these code there comes a question. I cannot find out the difference between m_aiExtraSpecialistYield[(YieldTypes) eIndex] and m_aiBaseYieldRateFromSpecialists[(YieldTypes) eIndex]. It seems that they always return the same value, like this:

Code:
/// Base yield rate from Specialists
int CvCity::GetBaseYieldRateFromSpecialists(YieldTypes eIndex) const
{
	VALIDATE_OBJECT
	CvAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	CvAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");

	return m_aiBaseYieldRateFromSpecialists[eIndex];
}

//	--------------------------------------------------------------------------------
/// Base yield rate from Specialists
void CvCity::ChangeBaseYieldRateFromSpecialists(YieldTypes eIndex, int iChange)
{
	VALIDATE_OBJECT
	CvAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	CvAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");

	if(iChange != 0)
	{
		m_aiBaseYieldRateFromSpecialists.setAt(eIndex, m_aiBaseYieldRateFromSpecialists[eIndex] + iChange);

		if(getTeam() == GC.getGame().getActiveTeam())
		{
			if(isCitySelected())
			{
				DLLUI->setDirty(CityScreen_DIRTY_BIT, true);
			}
		}
	}
}

Code:
int CvCity::getExtraSpecialistYield(YieldTypes eIndex) const
{
	VALIDATE_OBJECT
	CvAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	CvAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	return m_aiExtraSpecialistYield[eIndex];
}


//	--------------------------------------------------------------------------------
int CvCity::getExtraSpecialistYield(YieldTypes eIndex, SpecialistTypes eSpecialist) const
{
	VALIDATE_OBJECT
	CvAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	CvAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	CvAssertMsg(eSpecialist >= 0, "eSpecialist expected to be >= 0");
	CvAssertMsg(eSpecialist < GC.getNumSpecialistInfos(), "GC.getNumSpecialistInfos expected to be >= 0");

	if (eSpecialist == GC.getDEFAULT_SPECIALIST())
	{
		return 0;
	}

	int iYieldMultiplier = GET_PLAYER(getOwner()).getSpecialistExtraYield(eSpecialist, eIndex) +
	                       GET_PLAYER(getOwner()).getSpecialistExtraYield(eIndex) +
	                       GET_PLAYER(getOwner()).GetPlayerTraits()->GetSpecialistYieldChange(eSpecialist, eIndex);
#if defined(MOD_API_UNIFIED_YIELDS)
	iYieldMultiplier += GET_PLAYER(getOwner()).getSpecialistYieldChange(eSpecialist, eIndex);

	ReligionTypes eMajority = GetCityReligions()->GetReligiousMajority();
	if(eMajority >= RELIGION_PANTHEON)
	{
		const CvReligion* pReligion = GC.getGame().GetGameReligions()->GetReligion(eMajority, getOwner());
		if(pReligion)
		{
			iYieldMultiplier += pReligion->m_Beliefs.GetSpecialistYieldChange(eSpecialist, eIndex);
			BeliefTypes eSecondaryPantheon = GetCityReligions()->GetSecondaryReligionPantheonBelief();
			if (eSecondaryPantheon != NO_BELIEF)
			{
				iYieldMultiplier += GC.GetGameBeliefs()->GetEntry(eSecondaryPantheon)->GetSpecialistYieldChange(eSpecialist, eIndex);
			}
		}
	}
#endif
	int iExtraYield = GetCityCitizens()->GetSpecialistCount(eSpecialist) * iYieldMultiplier;

	return iExtraYield;
}


//	--------------------------------------------------------------------------------
void CvCity::updateExtraSpecialistYield(YieldTypes eYield)
{
	VALIDATE_OBJECT
	int iOldYield;
	int iNewYield;
	int iI;

	CvAssertMsg(eYield >= 0, "eYield expected to be >= 0");
	CvAssertMsg(eYield < NUM_YIELD_TYPES, "eYield expected to be < NUM_YIELD_TYPES");

	iOldYield = getExtraSpecialistYield(eYield);

	iNewYield = 0;

	for(iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
	{
		iNewYield += getExtraSpecialistYield(eYield, ((SpecialistTypes)iI));
	}

	if(iOldYield != iNewYield)
	{
		m_aiExtraSpecialistYield.setAt(eYield, iNewYield);
		CvAssert(getExtraSpecialistYield(eYield) >= 0);

		ChangeBaseYieldRateFromSpecialists(eYield, (iNewYield - iOldYield));
	}
}


//	--------------------------------------------------------------------------------
void CvCity::updateExtraSpecialistYield()
{
	VALIDATE_OBJECT
	int iI;

	for(iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		updateExtraSpecialistYield((YieldTypes)iI);
	}
}

Is there anyone who can tell me the difference between them (and however the necessity of defining 2 variables)? Thanks a lot!
 
A year ago I could have given you a definitive answer ... but time passes and the memory dulls

Civ5 has a very confusing use of the term specialist, it can, in different parts of the code, mean
a) a specific specialist type - eg a scientist or a merchant
b) an citizen assigned to specialist slots (ie the sum of all specific specialist)
c) an unemployed citizen
d) any citizen not working a tile (ie the sum of b + c)

Assuming your table is for a modifier bonus based on "per gems per scientist" (say), then, IIRC, you need to modify CvCity:: getExtraSpecialistYield()

But your best bet is to check the Unified Yields code/thread for something pretty close and then hunt through the code duplicating/modifying it's use

W
 
Thanks to whoward69's reply and I made the first step work.:)

Here I met another problem while trying to add a table as "Policy_SpecialistExtraResourceQuantity" based on "Policy_SpecialistExtraYields" or somewhat.
In order to do so I used a variable "m_ppaaiSpecialistExtraResourceQuantity", inserted it into CvPlayer.cpp as follows:

Code:
CvPlayer::CvPlayer() :
	m_syncArchive(*this)
	, m_iStartingX("CvPlayer::m_iStartingX", m_syncArchive)
	, m_iStartingY("CvPlayer::m_iStartingY", m_syncArchive)
	, m_iTotalPopulation("CvPlayer::m_iTotalPopulation", m_syncArchive, true)
	, m_iTotalLand("CvPlayer::m_iTotalLand", m_syncArchive)

...

	, m_pabGetsScienceFromPlayer("CvPlayer::m_pabGetsScienceFromPlayer", m_syncArchive)
	, m_ppaaiSpecialistExtraYield("CvPlayer::m_ppaaiSpecialistExtraYield", m_syncArchive)
	[B]// MOD - TOKATA
	, m_ppaaiSpecialistExtraResourceQuantity("CvPlayer::m_ppaaiSpecialistExtraResourceQuantity", m_syncArchive)
	// MOD - TOKATA END[/B]

...

Code:
void CvPlayer::uninit()
{
	m_paiNumResourceUsed.clear();
	m_paiNumResourceTotal.clear();
	m_paiResourceGiftedToMinors.clear();

...

	m_ppaaiSpecialistExtraYield.clear();
	[B]// MOD - TOKATA
	m_ppaaiSpecialistExtraResourceQuantity.clear();
	// MOD - TOKATA END[/B]

...

Code:
// FUNCTION: reset()
// Initializes data members that are serialized.
void CvPlayer::reset(PlayerTypes eID, bool bConstructorCall)
{
	m_syncArchive.reset();
	//--------------------------------
	// Uninit class
	uninit();

	m_eID = eID;
	if(m_eID != NO_PLAYER)
	{
		m_ePersonalityType = CvPreGame::leaderHead(m_eID); //??? Is this repeated data???
	}
	else
	{
		m_ePersonalityType = NO_LEADER;
	}

	// tutorial info
	m_bEverPoppedGoody = false;

	m_aiCityYieldChange.clear();
	m_aiCityYieldChange.resize(NUM_YIELD_TYPES, 0);

	m_aiCoastalCityYieldChange.clear();
	m_aiCoastalCityYieldChange.resize(NUM_YIELD_TYPES, 0);

...

	if(!bConstructorCall)
	{

...

		[B]// MOD - TOKATA
		std::vector<int> quantity;
		for(int j = 0; j < GC.getNumResourceInfos(); ++j)
		{
			quantity.at(j) = 0;
		}

		m_ppaaiSpecialistExtraResourceQuantity.clear();
		m_ppaaiSpecialistExtraResourceQuantity.resize(GC.getNumSpecialistInfos());
		for(unsigned int i = 0; i < m_ppaaiSpecialistExtraResourceQuantity.size(); ++i)
		{
			m_ppaaiSpecialistExtraResourceQuantity.setAt(i, quantity);
		}
		// MOD - TOKATA END[/B]

		Firaxis::Array< int, NUM_YIELD_TYPES > yield;
		for(unsigned int j = 0; j < NUM_YIELD_TYPES; ++j)
		{
			yield[j] = 0;
		}

		m_ppaaiSpecialistExtraYield.clear();
		m_ppaaiSpecialistExtraYield.resize(GC.getNumSpecialistInfos());
		for(unsigned int i = 0; i < m_ppaaiSpecialistExtraYield.size(); ++i)
		{
			m_ppaaiSpecialistExtraYield.setAt(i, yield);
		}

...

Code:
// read object from a stream
// used during load
//
void CvPlayer::Read(FDataStream& kStream)
{
	// Init data before load
	reset();

	// Version number to maintain backwards compatibility
	uint uiVersion;
	kStream >> uiVersion;
	MOD_SERIALIZE_INIT_READ(kStream);

	kStream >> m_iStartingX;
	kStream >> m_iStartingY;

...

	kStream >> m_ppaaiSpecialistExtraYield;
	[B]// MOD - TOKATA
	kStream >> m_ppaaiSpecialistExtraResourceQuantity;
	// MOD - TOKATA END[/B]

...

Code:
// save object to a stream
// used during save
//
void CvPlayer::Write(FDataStream& kStream) const
{
	//Save version number.  THIS MUST BE FIRST!!
	kStream << g_CurrentCvPlayerVersion;
	MOD_SERIALIZE_INIT_WRITE(kStream);

	kStream << m_iStartingX;
	kStream << m_iStartingY;

...

	kStream << m_ppaaiSpecialistExtraYield;
	[B]// MOD - TOKATA
	kStream << m_ppaaiSpecialistExtraResourceQuantity;
	// MOD - TOKATA END[/B]

...

And in CvPlayer.h:
Code:
...

	FAutoVariable< std::vector< Firaxis::Array<int, NUM_YIELD_TYPES > >, CvPlayer> m_ppaaiSpecialistExtraYield;
	[B]// MOD - TOKATA
	FAutoVariable< std::vector< std::vector<int> >, CvPlayer> m_ppaaiSpecialistExtraResourceQuantity;
	// MOD - TOKATA END[/B]

...

It seems that this project could pass the compile but turns out to crash when a game starts. I'm sure it is this variable that caused the crash, but as a newcomer I couldn't figure out the problem. Maybe someone could tell me?
Thanks a lot!
 
IIRC auto-variables are special beasts, you almost certainly want to create and initialise the array by normal means.

Also, using comments to delineate your changes is a really bad idea - see the first half of my first DLL tutorial (linked from my sig) as to why and how to use #define/#if macros for a superior approach.
 
Thanks and I'm trying to re-write my code by "normal means" tonight (not sure whether I have enough ability to make it work, but your suggestion helps)

Planning to use #if-#else-#endif (fortunately not too much things to do) and thanks for your guidance!
 
Thanks and I'm trying to re-write my code by "normal means" tonight (not sure whether I have enough ability to make it work, but your suggestion helps)

If should just be a one-line change to not use the FAutoVarible macro, see m_ppiPlotYieldChange in the (same) CvPlayer.cpp/h files
 
Back
Top Bottom