Adding new Resource Yields to Future Techs

Check if the owner is following this religion, or not following ANY religion at all

If he is, check if this city has the religion

If we have the religion, we get the default bonus of this religion in every city

Oh for pete's sake...

Thank-you both for explaining that to me. I'll be able to read things a little better going forward.

I've been looking in the completely wrong place. This snippet adds a (Commerce) bonus to each city that is following the State religion of the Civ! That's not what I need at all!

Ok, so, since CvCity seems to contain (if I understand correctly) calculations that will be run on every city, and I only want to deal with what happens in the city that builds a Shrine and nowhere else, I should be messing about in... umm, hmm... where? There's no "CvBuildings" file, not that I can see. Would it be CvPlayer?

EDIT: Think I found it. It's still CvCity, but I should be copying getExtraSpecialistYield, right? With this piece of code I think:
Code:
if (GC.getBuildingInfo(eBuilding).getGlobalReligionYields() != NO_RELIGION)
	{
		iYield += (GC.getReligionInfo((ReligionTypes)(GC.getBuildingInfo(eBuilding).getGlobalReligionYields())).getGlobalReligionYields(eIndex) * GC.getGameINLINE().countReligionLevels((ReligionTypes)(GC.getBuildingInfo(eBuilding).getGlobalReligionYields()))) * getNumActiveBuilding(eBuilding);
	}

EDIT AGAIN: OK, I think I'm getting close. I stil have a major problem, I'm not quite sure how to re-word the bolded line to make it make more sense in comparison to the original line for Specialists. It definately doesn't work as-is, and I know there's a better way to word it, but I'm having trouble putting it together.
Code:
int CvCity::getGlobalReligionYield(YieldTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");

	return m_aiGlobalReligionYield[eIndex];
}


int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion, eBuilding) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	FAssertMsg(eReligion >= 0, "eReligion expected to be >= 0");
	FAssertMsg(eReligion < GC.getNumReligionInfos(), "GC.getNumReligionInfos expected to be >= 0");

//	return ((getSpecialistCount(eSpecialist) + getFreeSpecialistCount(eSpecialist)) * GET_PLAYER(getOwnerINLINE()).getSpecialistExtraYield(eSpecialist, eIndex));
//	return ((
	[B]return GC.getReligionInfo((ReligionTypes)(GC.getBuildingInfo(eBuilding).getGlobalReligionYields()).getGlobalReligionYields(eIndex)) * GC.getGameINLINE().countReligionLevels((ReligionTypes)(GC.getBuildingInfo(eBuilding).getGlobalReligionYields())) * getNumActiveBuilding(eBuilding);[/B]
	 
}


void CvCity::updateGlobalReligionYield(YieldTypes eYield)
{
	int iOldYield;
	int iNewYield;
	int iI;

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

	iOldYield = getGlobalReligionYield(eYield);

	iNewYield = 0;

	for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
	{
		iNewYield += getGlobalReligionYield(eYield, ((ReligionTypes)iI));
	}

	if (iOldYield != iNewYield)
	{
		m_aiGlobalReligionYield[eYield] = iNewYield;
		FAssert(getGlobalReligionYield(eYield) >= 0);

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


void CvCity::updateGlobalReligionYield()
{
	int iI;

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		updateGlobalReligionYield((YieldTypes)iI);
	}
}
 
I don't know how to explain it better than I already have. You are correct that the code for CvCity applies to each city individually. Each city gets its own set of CvCity data and functions, so each one tracks the religions that have spread to it. Whenever a religion is added or removed from a city, you must tell every city that has the Shrine (assuming just one) to recalculate its religion yields based on the new spread value of the religion.

Code:
void CvCity::setHasReligion(eReligion, bNewValue)
{
    ...
    CvCity* pHolyCity = ??? // some function that returns the holy city for eReligion
    pHolyCity->updateReligionYields(eReligion);
}

As I have pointed out above, this may have issues with the way BTS transfers a city from one player to another during gift/conquest/culture/etc. You'll have to either read the code for CvGame::acquireCity() thoroughly or code this up and see what happens.

You cannot handle this like other building traits because it changes based on the number of cities with the religion combined with how BTS handles yields versus commerce types. It constantly recalculates commerce values while yields are changed only when things change in the game.

Alternatively, you could create a CvGame function to handle the above and figure out all the places where you need to call it. Instead of calling it from CvCity::setHasReligion(), call it where religions are spread (CvGame::doReligionSpread()?), where missionaries operate, and other places that cause religions to spread or be removed (no removal in normal game). You wouldn't call it from CvGame::acquireCity() because the number of cities with the religion doesn't change.
 
But I do have a line in void CvCity::setHasReligion(etc), calling updateGlobalReligionYield()... :(

I modelled the code in my second edit of posting #261 after SpecialistYield instead of ReligionCommerce because the Specialist code is designed to handle Yields, and I was fairly sure (I'm questioning that now 'coz of what you just said in #262) that the logic of CvCity::setHasReligion meant that just adding updateGlobalReligionYield() to it would result in the game counting up my Shrine Yield totals properly, and would even work for conquering/gifting.

Right now, I'm trying to figure out a way to tell int CvCity::getGlobalReligionYield() to grab the Yield amount for each religion and multiply it by the number of cities with that religion. I'm sure GC.getGameINLINE().countReligionLevels((ReligionTypes) does the second half, but I don't know how to re-word to work in the present context, as I found that line in int CvCity::getBuildingCommerceByBuilding...

I'm sorry if I'm being dense, I was just so sure I had the logic right, even though my coding sucks... :blush:
 
No worries; we'll get there eventually. :) You need to remove the eBuilding parameter from getGlobalReligionYield() and loop over all buildings inside the function. IIRC, you added CvBuildingInfo.getGlobalReligionYield(YieldTypes), right?

Code:
int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	FAssertMsg(eReligion >= 0, "eReligion expected to be >= 0");
	FAssertMsg(eReligion < GC.getNumReligionInfos(), "eReligion expected to be < GC.getNumReligionInfos()");

	int iYield = 0;
	int iNumCities = GC.getGameINLINE().countReligionLevels(eReligion);

	for (int i = 0; i < GC.getNumBuildingInfos(); i++)
	{
		int iCount = getNumActiveBuilding((BuildingTypes)i);
		if (iCount > 0)
		{
			iYield += iCount * iNumCities * GC.getBuildingInfo((BuildingTypes)i).getGlobalReligionYield(eIndex);
		}
	}

	return iYield;
}
 
OK, I think we're making progress. Here's my code as it stands. Compiling throws only two errors at me now; the offending lines are bolded.

CvCity.h
Code:
	int getGlobalReligionYield(YieldTypes eIndex) const;																				// Exposed to Python
	int getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion, BuildingTypes eBuilding) const;
	void updateGlobalReligionYield(YieldTypes eYield);
	void updateGlobalReligionYield();

CvCity.cpp
Code:
int CvCity::getGlobalReligionYield(YieldTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");

	return m_aiGlobalReligionYield[eIndex];
}


int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion, BuildingTypes eBuilding) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	FAssertMsg(eReligion >= 0, "eReligion expected to be >= 0");
	FAssertMsg(eReligion < GC.getNumReligionInfos(), "eReligion expected to be < GC.getNumReligionInfos()");

	int iYield = 0;
	int iNumCities = GC.getGameINLINE().countReligionLevels(eReligion);

	for (int i = 0; i < GC.getNumBuildingInfos(); i++)
	{
		int iCount = getNumActiveBuilding((BuildingTypes)i);
		if (iCount > 0)
		{
			[B]iYield += iCount * iNumCities * GC.getBuildingInfo(eBuilding).getGlobalReligionYields(eIndex);[/B]
		}
	}

	return iYield;
}


void CvCity::updateGlobalReligionYield(YieldTypes eYield)
{
	int iOldYield;
	int iNewYield;
	int iI;

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

	iOldYield = getGlobalReligionYield(eYield);

	iNewYield = 0;

	for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
	{
		[B]iNewYield += getGlobalReligionYield(eYield, ((ReligionTypes)iI));[/B]
	}

	if (iOldYield != iNewYield)
	{
		m_aiGlobalReligionYield[eYield] = iNewYield;
		FAssert(getGlobalReligionYield(eYield) >= 0);

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


void CvCity::updateGlobalReligionYield()
{
	int iI;

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

...
ETC
...

void CvCity::setHasReligion(ReligionTypes eIndex, bool bNewValue, bool bAnnounce, bool bArrows)
	... etc...
		updateMaintenance();
		updateReligionHappiness();
		updateReligionCommerce();
		updateGlobalReligionYield();

Here's what VS2008 is telling me:
CvCity.cpp(8326) : error C2660: 'CvBuildingInfo::getGlobalReligionYields' : function does not take 1 arguments
CvCity.cpp(8348) : error C2661: 'CvCity::getGlobalReligionYield' : no overloaded function takes 2 arguments

So, changing line 8326 to this gets rid of the first error:
Code:
iYield += iCount * iNumCities * (GC.getReligionInfo((ReligionTypes)(GC.getBuildingInfo(eBuilding).getGlobalReligionYields())).getGlobalReligionYields(eIndex));

But I don't quite know what the second error is trying to tell me... Adding "ReligionTypes", or "ReligionTypes eReligion" to the void header line (and changing CvCity.h to match of course) doesn't work, so I'm left scratching my head... :confused:
 
The first error is telling you that you should have used the code I posted. :mischief: You are trying to call getGlobalReligionYields() which takes no parameters, but you should be calling getGlobalReligionYield(YieldTypes) [note the lack of trailing s on the name] which takes a yield type. The former function returns the full array, but we only want one value here.

The second error is telling you that you should have used the code I posted. :lol: You are correctly passing in two parameters: the yield type and religion, but you've declared the function to require a building type. This isn't needed since the function returns the global religion yield for all building types by using a loop.

You also need to remove it from the header file. The correct function signature is

Code:
int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion) const
 
Hmm...

Ok, here's the thing. The code you posted in #264 doesn't compile as-is. VS2008 says this:
CvCity.cpp(8326) : error C2039: 'getGlobalReligionYield' : is not a member of 'CvBuildingInfo'

This does compile though, which I only just discovered. But, it still doesn't work... :p :lol:
Code:
iYield += iCount * iNumCities * GC.getBuildingInfo((BuildingTypes)i).getGlobalReligionYields();


So, I think the difficulty might be in the way I constructed things in other files. So, for your review, here's the whole kit'n'kaboodle. Let's hope I didn't just do something stoopid... ;)

Spoiler CvGameTextMgr.cpp :
Code:
				szBuffer.append(gDLL->getText("TXT_KEY_BUILDING_NATIONAL_WONDER_LEFT", (GC.getBuildingClassInfo((BuildingClassTypes) kBuilding.getBuildingClassType()).getMaxPlayerInstances() - GET_PLAYER(ePlayer).getBuildingClassCountPlusMaking((BuildingClassTypes)(kBuilding.getBuildingClassType())))));
			}
		}
	}


[B]	if (kBuilding.getGlobalReligionYields() != NO_RELIGION)
	{
		szFirstBuffer = gDLL->getText("TXT_KEY_BUILDING_PER_CITY_WITH", GC.getReligionInfo((ReligionTypes) kBuilding.getGlobalReligionYields()).getChar());
		setYieldChangeHelp(szBuffer, L"", L"", szFirstBuffer, GC.getReligionInfo((ReligionTypes) kBuilding.getGlobalReligionYields()).getGlobalReligionYieldsArray());
	}[/B]

	if (kBuilding.getGlobalReligionYields() != NO_RELIGION)

Spoiler CyInfoInterface1.cpp :
Code:
		.def("getFoundsCorporation", &CvBuildingInfo::getFoundsCorporation, "int ()")
[B]		.def("getGlobalReligionYields", &CvBuildingInfo::getGlobalReligionYields, "int ()")
[/B]		.def("getGlobalReligionCommerce", &CvBuildingInfo::getGlobalReligionCommerce, "int ()")

Spoiler CyInfoInterface3.cpp :
Code:
		.def("getAdjectiveKey", &CvReligionInfo::pyGetAdjectiveKey, "wstring ()")

		// Arrays

[B]		.def("getGlobalReligionYields", &CvReligionInfo::getGlobalReligionYields, "int (int i)")
[/B]		.def("getGlobalReligionCommerce", &CvReligionInfo::getGlobalReligionCommerce, "int (int i)")

Spoiler CvInfos, header & code :
Code:
	DllExport int getFoundsCorporation() const;				// Exposed to Python
	[B]DllExport int getGlobalReligionYields() const;				// Exposed to Python[/B]
	DllExport int getGlobalReligionCommerce() const;				// Exposed to Python

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	int m_iFoundsCorporation;					
	[B]int m_iGlobalReligionYields;[/B]
	int m_iGlobalReligionCommerce;

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	std::wstring pyGetAdjectiveKey() { return getAdjectiveKey(); }				// Exposed to Python

	// Arrays

	[B]DllExport int getGlobalReligionYields(int i) const;		// Exposed to Python
	int* getGlobalReligionYieldsArray() const;		[/B]
	DllExport int getGlobalReligionCommerce(int i) const;		// Exposed to Python

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	CvWString m_szAdjectiveKey;

	// Arrays

[B]	int* m_paiGlobalReligionYields;		[/B]
	int* m_paiGlobalReligionCommerce;
Code:
m_iFoundsCorporation(NO_CORPORATION),
[B]m_iGlobalReligionYields(0),[/B]
m_iGlobalReligionCommerce(0),

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

int CvBuildingInfo::getFoundsCorporation() const		
{
	return m_iFoundsCorporation;
}

[B]int CvBuildingInfo::getGlobalReligionYields() const
{
	return m_iGlobalReligionYields;
}[/B]

int CvBuildingInfo::getGlobalReligionCommerce() const
{
	return m_iGlobalReligionCommerce;
}

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	stream->Read(&m_iFoundsCorporation);
[B]	stream->Read(&m_iGlobalReligionYields);[/B]
	stream->Read(&m_iGlobalReligionCommerce);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	stream->Write(m_iFoundsCorporation);
[B]	stream->Write(m_iGlobalReligionYields);[/B]
	stream->Write(m_iGlobalReligionCommerce);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	pXML->GetChildXmlValByName(szTextVal, "FoundsCorporation");
	m_iFoundsCorporation = pXML->FindInInfoClass(szTextVal);

[B]	pXML->GetChildXmlValByName(szTextVal, "GlobalReligionYield");
	m_iGlobalReligionYields = pXML->FindInInfoClass(szTextVal);
[/B]
	pXML->GetChildXmlValByName(szTextVal, "GlobalReligionCommerce");
	m_iGlobalReligionCommerce = pXML->FindInInfoClass(szTextVal);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

m_iMissionType(NO_MISSION),
[B]m_paiGlobalReligionYields(NULL),
[/B]m_paiGlobalReligionCommerce(NULL),

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

CvReligionInfo::~CvReligionInfo()
{
[B]	SAFE_DELETE_ARRAY(m_paiGlobalReligionYields);
[/B]	SAFE_DELETE_ARRAY(m_paiGlobalReligionCommerce);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

// Arrays
[B]
int CvReligionInfo::getGlobalReligionYields(int i) const
{
	FAssertMsg(i < NUM_YIELD_TYPES, "Index out of bounds");
	FAssertMsg(i > -1, "Index out of bounds");
	return m_paiGlobalReligionYields ? m_paiGlobalReligionYields[i] : -1; 
}

int* CvReligionInfo::getGlobalReligionYieldsArray() const
{
	return m_paiGlobalReligionYields;
}[/B]

int CvReligionInfo::getGlobalReligionCommerce(int i) const

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	pXML->GetChildXmlValByName(&m_iSpreadFactor, "iSpreadFactor");

[B]	if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"GlobalReligionYields"))
	{
		pXML->SetYields(&m_paiGlobalReligionYields);
		gDLL->getXMLIFace()->SetToParent(pXML->GetXML());
	}
	else
	{
		pXML->InitList(&m_paiGlobalReligionYields, NUM_YIELD_TYPES);
	}
[/B]
	if (gDLL->getXMLIFace()->SetToChildByTagName(pXML->GetXML(),"GlobalReligionCommerces"))

Spoiler CvCity, header & code :
Code:
	void changeSpecialistCommerce(CommerceTypes eIndex, int iChange);									// Exposed to Python

[B]	int getGlobalReligionYield(YieldTypes eIndex) const;												// Exposed to Python
	int getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion) const;
	void updateGlobalReligionYield(YieldTypes eYield);
	void updateGlobalReligionYield();
[/B]	int getReligionCommerce(CommerceTypes eIndex) const;												// Exposed to Python

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	int* m_aiTradeYield;
[B]	int* m_aiGlobalReligionYield;
[/B]	int* m_aiCorporationYield;
Code:
	m_aiTradeYield = new int[NUM_YIELD_TYPES];
[B]	m_aiGlobalReligionYield = new int[NUM_YIELD_TYPES];
[/B]	m_aiCorporationYield = new int[NUM_YIELD_TYPES];

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	SAFE_DELETE_ARRAY(m_aiTradeYield);
[B]	SAFE_DELETE_ARRAY(m_aiGlobalReligionYield);
[/B]	SAFE_DELETE_ARRAY(m_aiCorporationYield);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

		m_aiTradeYield[iI] = 0;
[B]		m_aiGlobalReligionYield[iI] = 0;
[/B]		m_aiCorporationYield[iI] = 0;

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

				iCount += getNumActiveBuilding((BuildingTypes)iJ) * (GC.getBuildingInfo((BuildingTypes) iJ).getYieldChange(iI) + getBuildingYieldChange((BuildingClassTypes)GC.getBuildingInfo((BuildingTypes) iJ).getBuildingClassType(), (YieldTypes)iI));
			}

[B]			iCount += getReligionYields((YieldTypes)iI);
[/B]			iCount += getTradeYield((YieldTypes)iI);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

void CvCity::updateReligionCommerce()
	... etc...

[B]
int CvCity::getGlobalReligionYield(YieldTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");

	return m_aiGlobalReligionYield[eIndex];
}

int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	FAssertMsg(eReligion >= 0, "eReligion expected to be >= 0");
	FAssertMsg(eReligion < GC.getNumReligionInfos(), "eReligion expected to be < GC.getNumReligionInfos()");

	int iYield = 0;
	int iNumCities = GC.getGameINLINE().countReligionLevels(eReligion);

	for (int i = 0; i < GC.getNumBuildingInfos(); i++)
	{
		int iCount = getNumActiveBuilding((BuildingTypes)i);
		if (iCount > 0)
		{
			iYield += iCount * iNumCities * GC.getBuildingInfo((BuildingTypes)i).getGlobalReligionYields();
		}
	}

	return iYield;
}

void CvCity::updateGlobalReligionYield(YieldTypes eYield)
{
	int iOldYield;
	int iNewYield;
	int iI;

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

	iOldYield = getGlobalReligionYield(eYield);

	iNewYield = 0;

	for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
	{
		iNewYield += getGlobalReligionYield(eYield, ((ReligionTypes)iI));
	}

	if (iOldYield != iNewYield)
	{
		m_aiGlobalReligionYield[eYield] = iNewYield;
		FAssert(getGlobalReligionYield(eYield) >= 0);

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

void CvCity::updateGlobalReligionYield()
{
	int iI;

	for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
	{
		updateGlobalReligionYield((YieldTypes)iI);
	}
}
[/B]

int CvCity::getCorporationYield(YieldTypes eIndex) const

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

		updateReligionCommerce();
[B]		updateGlobalReligionYield();
[/B]
		AI_setAssignWorkDirty(true);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	pStream->Read(NUM_YIELD_TYPES, m_aiTradeYield);
[B]	pStream->Read(NUM_YIELD_TYPES, m_aiGlobalReligionYield);
[/B]	pStream->Read(NUM_YIELD_TYPES, m_aiCorporationYield);

&#9484;------------&#9488;
| [I]... etc...[/I] |
&#9492;------------&#9496;

	pStream->Write(NUM_YIELD_TYPES, m_aiTradeYield);
[B]	pStream->Write(NUM_YIELD_TYPES, m_aiGlobalReligionYield);
[/B]	pStream->Write(NUM_YIELD_TYPES, m_aiCorporationYield);
 
Okay, I forgot that the building only specifies the religion for which BRYs should apply whereas the religion itself specifies what those yields are.

First, to follow the GlobalReligionCommerce function names in CvReligionInfo, I recommend dropping the "-s" from CvReligion::getGlobalReligionYields(). It returns a single yield value so it should not be plural:

Code:
getGlobalReligionYield(int i)

Similarly, to match GRC in CvBuildingInfo I would drop the "-s" from the field m_iGlobalReligionYields and its accessor function getGlobalReligionYields(). This field represents the single religion for which the yields apply.

As you can see, having function names that aren't intuitive or don't match the values they return is making their names difficult to remember. Actually, it forces me to remember them rather than just think of them naturally.

As an example, would be a natural name for the Person function to return the person's age? I immediately think getAge(). What if you called it getAges()? You'd constantly be getting that wrong whenever you tried to use it because it's not intuitive. This is why it's important to pick intuitive names, and in the case of Civ4, that typically means matching their sometimes not-so-intuitive scheme. ;)

If you make those changes, getGlobalReligionYield() becomes

Code:
int CvCity::getGlobalReligionYield(YieldTypes eIndex, ReligionTypes eReligion) const
{
	FAssertMsg(eIndex >= 0, "eIndex expected to be >= 0");
	FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex expected to be < NUM_YIELD_TYPES");
	FAssertMsg(eReligion >= 0, "eReligion expected to be >= 0");
	FAssertMsg(eReligion < GC.getNumReligionInfos(), "eReligion expected to be < GC.getNumReligionInfos()");

	int iYield = 0;
	int iNumCities = GC.getGameINLINE().countReligionLevels(eReligion);

	for (int i = 0; i < GC.getNumBuildingInfos(); i++)
	{
		if (GC.getBuildingInfo((BuildingTypes)i).getGlobalReligionYield() == eReligion)
		{
			iYield += iNumCities * getNumActiveBuilding((BuildingTypes)i) * GC.getReligionInfo(eReligion).getGlobalReligionYield(eIndex);
		}
	}

	return iYield;
}

Here for each building, if its GRY matches the religion we're looking at, then we increase the running total yield by the number of cities with the religion times the number of buildings of that type in the city (probably 1) times the religion's GRY of the given yield type.
 
OK, I do get what you are saying about the -s. I've changed all the references stemming from CvReligionInfos for GRY to singular. But, I have left the CvBuildingInfos GRY plural, as that seems to make sense based on what you said.

Also, the new code still doesn't work. :wallbash: I get a complete stall of CivIV as soon as I found a city.

:hammer2: :badcomp:

:cry:

Guess it's time to use the Debug. Hope I can make this work... :crazyeye:
 
The most likely cause of a lockup like that is an infinite loop. Function A calls B which calls C which calls A which calls B and so on. Look at the foundCity() for clues. I wouldn't expect CvCity::setHasReligion() to be called when founding a city. Track down all the other places that call this function.

Also, your function doesn't really call any functions that themselves would call other functions.
 
OK, so, a few things.

I can't make Debug work.

When I compile a Debug DLL, and then copy that DLL to my Mod folder, and start a game, I get this error:
erroronloaddebugDLL.jpg

But then strangely enough, if I simply try to run the game again, it'll load... Weirder, it loads with all my Civ.ini settings set back to stock.


Once I'm actually in my Mod (cause I have to load it from the Civ main menu when running the Debug), the game doesn't show my changes in the Pedia anymore. The Pedia loads just fine, it has no overt errors, it just looks like I never did anything to it...


I always attach VS2008 to the Civ4 process before I do anything (but after I load my mod of course, if I didn't remember to put the Civ.ini back to rights). But none of my breakpoints are getting hit. Even when I found a city and the game crashes, VS2008 gets nothing.


I tried instead choosing DEBUG -> START DEBUGGING from the menu, but then I got this error:
F5fromVS2008.jpg



On the off chance, I re-compiled a regular DLL, copied it to my Mod folder, set the Civ.ini back to the way I keep it, and started Civ4. Once the main menu had loaded, I attached VS2008 to the Civ4 process. Which seemed to work. I checked the Pedia, my changes showed, but I got no hits from the breakpoint I have set in CGTM.cpp. I tried starting a new game, which worked, and checked the Pedia from in there. Still no breakpoint. I tried founding a city, jackpot. ... Kinda...


Founding a city did trigger VS2008 to recognize something had gone kerflooey, but I'm having trouble interpreting the results. For your viewing pleasure then:
VS2008scrnsht.jpg

Obviously, something's going wrong with CvCity::Reset. But I have only one line of code in that function, m_aiGlobalReligionYield[iI] = 0;, and it isn't calling anything else that I've touched. So, what the heck?

Also, I found something I think is rather strange, but would explain why none of my breakpoints are triggering, and for which I have no explanation or solution. Each of my breakpoints says this in the mouseover text:
The breakpoint will not currently be hit. No symbols have been loaded for this document.
Whaaat? :confused:
 
This line in CvCity::reset()

Code:
m_aiGlobalReligionYield[iI] = 0;

sets a single yield value to 0. I assume this is in a loop over NUM_YIELD_TYPES. Somewhere above it must be a line that creates the array:

Code:
m_aiGlobalReligionYield = new int[NUM_YIELD_TYPES];

This should probably go in the constructor, CvCity::CvCity(), along with all the other arrays. Also, make sure you are deleting the array in the destructor, CvCity::~CvCity().

Code:
SAFE_DELETE_ARRAY(m_aiGlobalReligionYield);
 
As for why you cannot get your debug DLL to work, how are you building it? Are you using a makefile with nmake? If so, post it here and I'll check over the compiler and link options. I recently rewrote the BULL makefile and finally was able to build a debug DLL. I haven't tried attaching to it, but IIRC I was able to use it just fine.
 
Yup, I've got both of those entries.
Code:
CvCity::CvCity()
{
	m_aiTradeYield = new int[NUM_YIELD_TYPES];
[B]	m_aiGlobalReligionYield = new int[NUM_YIELD_TYPES];[/B]
	m_aiCorporationYield = new int[NUM_YIELD_TYPES];
Code:
CvCity::~CvCity()
{
	CvDLLEntity::removeEntity();			// remove entity from engine
	CvDLLEntity::destroyEntity();			// delete CvCityEntity and detach from us

	uninit();

	SAFE_DELETE_ARRAY(m_aiTradeYield);
[B]	SAFE_DELETE_ARRAY(m_aiGlobalReligionYield);[/B]
	SAFE_DELETE_ARRAY(m_aiCorporationYield);
And yes, m_aiGlobalReligionYield[iI] = 0; is held within for (iI = 0; iI < NUM_YIELD_TYPES; iI++).

Here's my makefile: View attachment Makefile.rar. Oh, and the "Copy" commands don't work. I always have to copy to new DLL manually. Do you see what I did wrong? I thought I'd followed Xienwolf's instructions to the letter, but obviously I goofed somewhere...

Thanks EF.
 
The problem with your copy function is probably this:

Code:
Final_Release-after:
	-@if exist "Debug\CvGameCoreDLL.dll" copy "Debug\CvGameCoreDLL.dll" "D:\Games\Civilization IV\Beyond the Sword\Mods\RichMod\Assets"

For copying the Final Release version, you have to look in the final release folder. So use:

Code:
Final_Release-after:
	-@if exist "Final_Release\CvGameCoreDLL.dll" copy "Final_Release\CvGameCoreDLL.dll" "D:\Games\Civilization IV\Beyond the Sword\Mods\RichMod\Assets"
 
Can you post your CvCity.h and CvCity.cpp? I'd like to diff them against the 3.17 versions because I'm out of ideas. :( I'll take a look at your makefile when I get back from lunch.
 
As I have rewritten my makefile, it differs a bit from yours. Here's the relevant part from mine:

Code:
### Compiler/linker options
# /EHsc		catch C++ exceptions only; assume that extern C functions never throw a C++ exception
# /Gd		Use the __cdecl calling convention (x86 only). 
# /GR		enable run-time type information (RTTI)
# /G7		only 1 and 2 are valid; no idea what 7 does
# /MD		multithreaded normal DLL with MSVCRT.dll
# /MDd		multithreaded debug DLL with MSVCRTD.dll
# /O2		optimize for speed
# /W3		warning level 3
GLOBAL_CFLAGS= /EHsc /Gd /GR /G7 /W3 /DWIN32 /D_WINDOWS /D_USRDLL /DCVGAMECOREDLL_EXPORTS

# /debug	create debugging information
# /INC:NO	results in small DLL
# /OPT:REF	remove unreferenced data/functions
# /OPT:ICF	identical COMDAT folding (trimming identical read-only data)
# /SUB:WIN	EXE doesn't need a console; shouldn't need this
GLOBAL_LDFLAGS=

GLOBAL_INCS=/I"CxImage/general" /I"CxImage/jpeg" /I"$(BOOST)/include" /I"$(PYTHON)/include" /I"$(TOOLKIT)/include" /I"$(PSDK)/Include"
GLOBAL_LIBDIRS=/LIBPATH:"$(PYTHON)/libs" /LIBPATH:"$(BOOST)/libs/" /LIBPATH:"$(PSDK)/Lib" /LIBPATH:"$(TOOLKIT)/lib"
GLOBAL_LIBS=boost_python-vc71-mt-1_32.lib winmm.lib user32.lib gdi32.lib Ole32.lib

Debug_GLOBAL_CFLAGS=$(GLOBAL_CFLAGS) /MDd /D_DEBUG
Debug_PROJECT_CFLAGS=
Debug_GLOBAL_LDFLAGS=$(GLOBAL_LDFLAGS) /debug /pdb:Debug\CvGameCoreDLL_DEBUG.pdb [B]/NODEFAULTLIB:MSVCRT[/B]
Debug_PROJECT_LDFLAGS=
Debug_GLOBAL_INCS=$(GLOBAL_INCS)
Debug_PROJECT_INCS=
Debug_GLOBAL_LIBDIRS=$(GLOBAL_LIBDIRS)
Debug_PROJECT_LIBDIRS=
Debug_GLOBAL_LIBS=$(GLOBAL_LIBS)
Debug_PROJECT_LIBS=

Final_Release_GLOBAL_CFLAGS=$(GLOBAL_CFLAGS) /MD /O2 /DNDEBUG /DFINAL_RELEASE
Final_Release_PROJECT_CFLAGS=
Final_Release_GLOBAL_LDFLAGS=$(GLOBAL_LDFLAGS) /INCREMENTAL:NO /OPT:REF /OPT:ICF [B]/NODEFAULTLIB:MSVCRTD[/B]
Final_Release_PROJECT_LDFLAGS=
Final_Release_GLOBAL_INCS=$(GLOBAL_INCS)
Final_Release_PROJECT_INCS=
Final_Release_GLOBAL_LIBDIRS=$(GLOBAL_LIBDIRS)
Final_Release_PROJECT_LIBDIRS=
Final_Release_GLOBAL_LIBS=$(GLOBAL_LIBS)
Final_Release_PROJECT_LIBS=

The bold part is what looks most suspicious. You are omitting the debug lib MSVCRTD from your debug build. Remove the D from the name and try again; you might get that lucky.

Otherwise you'll need to look at the compiler and linker options you specify and decide if they make sense. I looked them up on MSDN using Google (link.exe/cl.exe command line options) and wrote the descriptions in my file. You have some that I didn't see in the original makefile, so you might want to make sure you need them.

The main difference with my layout is that there are GLOBAL_XXX settings that apply to both release and debug builds. That way only the things that truly differ need to be specified in the specific build profiles.
 
Xienwolf, thanks for pointing out, once again, how incredibly blind I can be. Of course that's why it's not automatically copying the DLL. Yeesh!!

And EF, this was my reaction to your last post:

:eek: :confused: :twitch:

:run:

I'm afraid that all I did for my Makefile was copy one of Xienwolf's that he had referred me to, and change the "Copy" functions (and incorrectly, at that). I don't even know if I have all the libraries it specifies, or if I need everything it specifies. It worked the first time I tried it, and I was just so relieved that it did, that I asked no questions beyond that.

Since I'm not doing anything too exotic, and I don't think BULL is either, maybe you could post a copy of yours for me? If I've understood correctly, Xienwolf is one of the prime movers behind the Fall from Heaven mod, which I think is a complete overhaul, right? Maybe his Makefile is using some esoteric stuff that doesn't work for my simple needs?

I don't know, just supposing out loud...
 
I'll retrofit my makefile to use the normal files as I have added a file for BUG, and I have some extra targets you won't need.

In the meantime, please try my suggestion of searching your makefile for

/NODEFAULTLIB:MSVCRTD​

and removing the D so it reads

/NODEFAULTLIB:MSVCRT​
 
Back
Top Bottom