[SDK] Combining bonus stockpiles between cities when they are connected

johnny_cash

Chieftain
Joined
Aug 4, 2009
Messages
32
Location
los angeles, ca
Hi, first post :goodjob:. first off i'd like to say thanks to faichele because i am working almost entirely off his code.

If I am stockpiling bonuses from improvements that are worked in a city radius, how would I combine the stockpiles of two or more cities that are now connected?

For example: city A has stockpiled 5 iron, and city B has stockpiled 2 iron and 3 cow. they were previously unconnected, but now i built a road between the two, so they should both share a stockpile of 7 iron and 3 cow.

here is what i have so far for the cities independent of each other:

this is what stockpiles at the end of each turn:
Code:
void CvCity::doBonusStock()
{	
	long iChange;
	CvPlot* pLoopPlot;
	int iX, iY;
	for (iX = -(CITY_PLOTS_RADIUS + 1); iX < (CITY_PLOTS_RADIUS + 1); iX++)
	{
		for (iY = -(CITY_PLOTS_RADIUS + 1); iY < (CITY_PLOTS_RADIUS + 1); iY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->getBonusType() != NO_BONUS)
				{
					CvBonusInfo& pBonusInfo = GC.getBonusInfo(pLoopPlot->getBonusType());
					if (/*pLoopPlot->isConnectedTo(this) && */pLoopPlot->isBeingWorked() && pLoopPlot->getWorkingCity()->getIDInfo() == getIDInfo())
					{
						if (pLoopPlot->isOwned() && (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()))
						{
							CvTeamAI& team = GET_TEAM(getTeam());
							bool bCollectOK = false;

							if (pBonusInfo.getTechReveal() == NO_TECH)
							{
								bCollectOK = true;
							}
							else
							{
								if (team.isHasTech((TechTypes) pBonusInfo.getTechReveal()))
								{
									bCollectOK = true;
								}
							}
							
							if (bCollectOK == true)
							{
								if (pBonusInfo.getTechObsolete() != NO_TECH && team.isHasTech((TechTypes) pBonusInfo.getTechObsolete()))
								{
									bCollectOK = false;
								}
							}
							
							if (bCollectOK == true)
							{
								
								iChange = getNumBonuses(pLoopPlot->getBonusType());
								changeBonusStock(pLoopPlot->getBonusType(), iChange);
							}
						}
					}
				}
			}
		}
	}
}

Code:
long CvCity::getBonusStock(BonusTypes eBonus)
{
	if (m_aiBonusStock != NULL)
	{
		return m_aiBonusStock[(int) eBonus];
	}
	else
	{
		return -1;
	}
}

void CvCity::setBonusStock(BonusTypes eBonus, long iValue)
{
	if (m_aiBonusStock != NULL)
	{
		m_aiBonusStock[(int) eBonus] = iValue;
	}
}

void CvCity::changeBonusStock(BonusTypes eBonus, long iChange)
{
	if (m_aiBonusStock != NULL)
	{
		if (getBonusStock(eBonus) + iChange > 0)
		{
			setBonusStock(eBonus, getBonusStock(eBonus) + iChange);
		}
		else
		{
			setBonusStock(eBonus, 0);
		}
	}
}

You might recognize A LOT of this from faichele's restricted resources, however I am going a different route and would like to avoid creating a new class for trade goods, and just stick to stockpiling bonuses and using this stockpile to create other bonii :D .
 
so here is the idea of what i am trying to do in CvCity:

Code:
void CvCity::doOverallBonusStock()
{
	int iI;
	int iZ;

	for (iZ = 0; iZ < getNumCities(); iZ++)
	{
		CvCity* ConnectedCity = getCity(iZ);
		
		if (isConnectedTo(ConnectedCity))
		{	
	
			for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
			{
				BonusTypes eBonus = GC.getBonusInfo((BonusTypes) iI);
					
				m_aiOverallBonusStock[(int) eBonus] = getBonusStock(eBonus) + ConnectedCity->getBonusStock(eBonus);
			}
		}
	}
}

I just want to loop through every city, if it's connected to "this city" i want to add the bonus stockpiles for all bonuses. the code in the first post works fine and gets stockpiles for the individual cities by themselves but i'm getting these errors on the code in this post:

Code:
||=== CvGameCoreDLL, Final Release Win32 ===|
CvCity.cpp|10729|error C3861: 'getNumCities': identifier not found, even with argument-dependent lookup|
CvCity.cpp|10731|error C2664: 'getCity' : cannot convert parameter 1 from 'int' to 'IDInfo'|
CvCity.cpp|10738|error C2440: 'initializing' : cannot convert from 'CvBonusInfo' to 'BonusTypes'|
||=== Build finished: 3 errors, 0 warnings ===|

i think i'm getting the error on getnumcities because it's actually in cvplayer. but i don't understand why the globals are giving me funk.

i'm just starting to learn C++ and the pointers and arrays are really confusing me, any help would be greatly appreciated!
 
so i guess my final question, as i've gotten my code down to 1 error, is how do i turn an integer into a bonustype? i thought GC.getBonusInfo? Any comment on what i'm missing in the logic?

Code:
void CvCity::doOverallBonusStock()
{
	int iI;
	int iZ;

	for (iZ = 0; iZ < GET_PLAYER(getOwnerINLINE()).getNumCities(); iZ++)
	{
		CvCity* ConnectedCity = GET_PLAYER(getOwnerINLINE()).getCity(iZ);
		
		if (isConnectedTo(ConnectedCity))
		{	
	
			for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
			{
				BonusTypes eBonus = GC.getBonusInfo((BonusTypes) iI);
					
				m_aiOverallBonusStock[(int) eBonus] = getBonusStock(eBonus) + ConnectedCity->getBonusStock(eBonus);
			}
		}
	}
}

this is the error:
Code:
CvCity.cpp|10738|error C2440: 'initializing' : cannot convert from 'CvBonusInfo' to 'BonusTypes'|
||=== Build finished: 1 errors, 0 warnings ===|
 
Just glazed things over real quickly since I am not familiar with the Stockpiling, but in regards to the last question, to change an INT to a BonusType: (BonusTypes)iI


And you can use iI instead of (int)eBonus, since you used that int to get the BonusType to begin with. But you can also get away with just saying [eBonus] and it'll translate to an INT for you automatically.


EDIT: For your second Post: getNumCities needs to be targetted at a player. The City itself doesn't own some number of cities. Hrm... You figured that out for Post 3 though, so I'm not sure you have any questions OTHER than the one in post 3, which I answered. So I guess if you have further questions, or some which you asked that still need answered, re-state them :)
 
This line should tell you something:
Code:
				BonusTypes eBonus = GC.getBonusInfo((BonusTypes) iI);
GC.getBonusInfo takes a BonusType as its argument and returns a CvBonusInfo. Do you want a CvBonusInfo? I think you want a BonusTypes.

Note that "(BonusTypes) iI" is a BonusTypes...
 
so this is what i've got working. for some reason, if two cities are connected, one of the cities has 1 less stockpile than it should following the logic in the OP.

example of what happens:
3 cities, A, B, C. Each has a stockpile of 5 iron. if A connected to B, A will have 10 iron, and B will have 9 iron. THEN if A connected to B, B connected to C, A will have 15 iron, B will have 14 iron, and C will have 13 iron. However, if the connections are cut, each individual city will have the proper stockpile of 5 iron. Why is this happening?

the goal is that when A and B are connected they will both have 10 iron, and when all three are connected they will all have 15 iron.

Code:
void CvCity::doOverallBonusStock()
{
	int iI;
	int iLoop;
	CvCity* pLoopCity;
	

	
		
	for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
	{				
		BonusTypes eBonus = ((BonusTypes) iI);
		m_aiOverallBonusStock[(int) eBonus] = getBonusStock(eBonus);
	
		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
		
			if (pLoopCity->isConnectedTo(this))
			{	
			
				if ((pLoopCity->getID()) != getID())
				{
								
					m_aiOverallBonusStock[(int) eBonus] = m_aiOverallBonusStock[(int) eBonus] + (pLoopCity->getBonusStock(eBonus));
				}
				
			}

		}
	}
}
 
Do you call doOverallBonusStock() on each city? If so, I would expect a different wrong result.

Taking your example,

A: add B and C: (15, 5, 5).
B: add A and C: (15, 25, 5)
C: add A and B: (15, 25, 45)

But I haven't delved into the code. When checking a city you must find all cities connected to it (done), add up the total stockpile, store it as the value for every connected city, and then make sure you don't process any of the connected cities again.

One way to do this is to add a boolean field to CvCity. Before you loop over all cities to call doOverallBonusStock(), you set every city's field to false. Then you call that function for each city. If the field is true, exit the function. If it's false, find all connected cities, sum up the stock, set those cities values to the total, and set their fields to true.

Also, in the code that subtracts from a city's stockpile make sure you subtract the value from all connected cities' stockpiles.
 
He shouldn't have a cumulative error, because he asks each city for getBonusStock(), not getCumulativeBonusStock(). As such, completely missing a city, or double adding a city would make sense, but missing 1 point out of 5 from a city is a tad confusing.
 
I agree, and I missed that there were two separate functions. In this case, perhaps the stockpile for one of the cities is defaulting to -1 instead of 0? It would help to see the complete set of relevant changes.
 
i really appreciate the help guys, thanks again.

so i've tested all kinds of different possibilities and i still have no clue.

3 cities, A,B,C, each with stockpile of 5 iron

when B becomes connected to A, A has 10 iron and B has 9. Add C into the mix and A has 15, B 14, C 13. Take B out and A has 10, C has 9. Disconnect them all and they all are back at 5. It always decreases by 1 in terms of which city was founded first (because i'm using the city loop).

It's kinda funny because I wanted to implement this feature with a certain decay across connections (mismanagement, supply losses, etc.), but yah, not like this.

anyway here is the code:

doBonusStock() processes the individual city's stockpile. right now I set iChange to 1 for testing, but I intend to replace that with an xml tag after i get the stockpiles working properly.
Code:
void CvCity::doBonusStock()
{	
	long iChange;
	CvPlot* pLoopPlot;
	int iX, iY;
	for (iX = -(CITY_PLOTS_RADIUS + 1); iX < (CITY_PLOTS_RADIUS + 1); iX++)
	{
		for (iY = -(CITY_PLOTS_RADIUS + 1); iY < (CITY_PLOTS_RADIUS + 1); iY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->getBonusType() != NO_BONUS)
				{
					CvBonusInfo& pBonusInfo = GC.getBonusInfo(pLoopPlot->getBonusType());
					if (/*pLoopPlot->isConnectedTo(this) && */pLoopPlot->isBeingWorked() && pLoopPlot->getWorkingCity()->getIDInfo() == getIDInfo())
					{
						if (pLoopPlot->isOwned() && (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()))
						{
							CvTeamAI& team = GET_TEAM(getTeam());
							bool bCollectOK = false;

							if (pBonusInfo.getTechReveal() == NO_TECH)
							{
								bCollectOK = true;
							}
							else
							{
								if (team.isHasTech((TechTypes) pBonusInfo.getTechReveal()))
								{
									bCollectOK = true;
								}
							}
							
							if (bCollectOK == true)
							{
								if (pBonusInfo.getTechObsolete() != NO_TECH && team.isHasTech((TechTypes) pBonusInfo.getTechObsolete()))
								{
									bCollectOK = false;
								}
							}
							
							if (bCollectOK == true)
							{
								
								iChange = 1;
								changeBonusStock(pLoopPlot->getBonusType(), iChange);
							}
						}
					}
				}
			}
		}
	}
}

doOverallBonusStock (so this is the cumulative function, which like doBonusStock happens in doTurn.

Code:
void CvCity::doOverallBonusStock()
{
	int iI;
	int iLoop;
	CvCity* pLoopCity;
	

	
		
	for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
	{				
		BonusTypes eBonus = ((BonusTypes) iI);
		m_aiOverallBonusStock[(int) eBonus] = getBonusStock(eBonus);
	
		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
		
			if (pLoopCity->isConnectedTo(this))
			{	
			
				if ((pLoopCity->getID()) != getID())
				{
								
					m_aiOverallBonusStock[(int) eBonus] = m_aiOverallBonusStock[(int) eBonus] + (pLoopCity->getBonusStock(eBonus));
				}
				
			}

		}
	}
}
 
Can you show the code in doTurn() that calls these two functions. I'm concerned that you are looping over all cities and calling each function on each city rather than calling one function on each city and then calling the other function on each city in a separate loop.

In fact, I bet this is what's happening. You merge A and then decrement it by 1. Then when you merge B, you use A's new value of 4 so B gets 9 and B gets decremented to 4. Finally you merge C and get 4 from A and 4 from B giving C a total of 13. You need two loops.

Also, I don't see anything here that maintains which connections have already been discovered. Every turn that A and B are connected, their individual stockpiles will get added to each others combined stockpile. Is this how it's supposed to work.

Finally, in the second function (merging), I would swap the two loops so you loop over all cities on the outside. When the loop city is found to be connected, you can now loop over all bonuses without having to check for connectedness for each bonus. This will save many calls to isConnectedTo().

Code:
for each city
    if loop city is not this city and is connected to this city
        for each bonus
            add loop city's stockpile to this city's combined stockpile
 
Can you show the code in doTurn() that calls these two functions. I'm concerned that you are looping over all cities and calling each function on each city rather than calling one function on each city and then calling the other function on each city in a separate loop.



Code:
void CvCity::doTurn()
{
	PROFILE("CvCity::doTurn()");

	CvPlot* pLoopPlot;
	int iI;

	if (!isBombarded())
	{
		changeDefenseDamage(-(GC.getDefineINT("CITY_DEFENSE_DAMAGE_HEAL_RATE")));
	}

	if (getOccupationTimer() > 0)
	{
		changeOccupationTimer(-1);
	}

	if (getHurryAngerTimer() > 0)
	{
		changeHurryAngerTimer(-1);
	}

	if (getConscriptAngerTimer() > 0)
	{
		changeConscriptAngerTimer(-1);
	}

	setLastDefenseDamage(getDefenseDamage());
	setBombarded(false);
	setDrafted(false);
	setAirliftTargeted(false);
	setCurrAirlift(0);

	AI_doTurn();

	if (isOccupation() || (angryPopulation() > 0) || (healthRate() < 0))
	{
		setWeLoveTheKingDay(false);
	}
	else if ((getPopulation() >= GC.getDefineINT("WE_LOVE_THE_KING_POPULATION_MIN_POPULATION")) && (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("WE_LOVE_THE_KING_RAND"), "Do We Love The King?") < getPopulation()))
	{
		setWeLoveTheKingDay(true);
	}
	else
	{
		setWeLoveTheKingDay(false);
	}

	bool bAllowNoProduction = !doCheckProduction();

	doGrowth();

	doCulture();

	doPlotCulture(false);

	doProduction(bAllowNoProduction);

	doDecay();

	doReligion();

	doGreatPeople();

	doMeltdown();

[COLOR="Red"]//begin quantres
	doBonusStock();
	doOverallBonusStock();
//end quantres[/COLOR]

	if (!isDisorder())
	{
		for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
		{
			pLoopPlot = getCityIndexPlot(iI);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->getWorkingCity() == this)
				{
					if (pLoopPlot->isBeingWorked())
					{
						pLoopPlot->doImprovement();
					}
				}
			}
		}
	}

Also, I don't see anything here that maintains which connections have already been discovered. Every turn that A and B are connected, their individual stockpiles will get added to each others combined stockpile. Is this how it's supposed to work.

Yes. This way the combined stockpile is just a "pool" of the city's stockpiles that can be accessed by any connected city only while they are connected. So if you only have one city, the pool is just that city's stockpile. So eventually, building a wall will cost let's say 10 stone. this 10 stone is pulled from the pool a city has access to, not the stockpile it has raised by itself through working improvements. e.g. city B may only have gathered up 3 stone by itself, but when it is connected to city A which has 20 stone, it will be able to use all of the stone in the pool to build things, manufacture other bonuses, etc, even though it is only contributing 3 stone to the pool.

Finally, in the second function (merging), I would swap the two loops so you loop over all cities on the outside. When the loop city is found to be connected, you can now loop over all bonuses without having to check for connectedness for each bonus. This will save many calls to isConnectedTo().


Code:
for each city
if loop city is not this city and is connected to this city
for each bonus
add loop city's stockpile to this city's combined stockpile

Yes. This is a better approach. Thank you!
 
Yes, I was correct about the problem. Because you call these functions together in CvCity::doTurn(), the city's stock is being changed before adding in the stocks from other cities. Do the individual city stocks get reset to 0 before doing all this? If not, you're summing up their stocks over and over again, and this will not work.

That being said, there are other potential problems here. Where do you initialize the array holding the stocks for a city? I notice that you're careful not to access the array if it hasn't been allocated yet (good), but I don't see where you allocate it.

One possible source of a bug is that you return -1 for the stock if there is no array. I think 0 is a more sensible value unless you always allocate the array. But if you always allocate the array, an error return of -1 makes sense to help you catch bugs.

I've rewritten the get/set/change accessors to be simpler and more in line with how they're done in the other BTS code. I also moved the enforcement of a non-negative stock value to setBonusStock() where it belongs, simplifying changeBonusStock().

Code:
long CvCity::getBonusStock(BonusTypes eBonus)
{
	return m_aiBonusStock != NULL ? m_aiBonusStock[(int) eBonus] : 0;
}

void CvCity::setBonusStock(BonusTypes eBonus, long iValue)
{
	if (m_aiBonusStock != NULL)
	{
		m_aiBonusStock[(int) eBonus] = std::max(0, iValue);
	}
	else
	{
		// uh oh, stock is lost!
	}
}

void CvCity::changeBonusStock(BonusTypes eBonus, long iChange)
{
	setBonusStock(eBonus, getBonusStock(eBonus) + iChange);
}

You need to rethink how you're handling these shared stockpiles. Each turn the normal stockpile for city A is added to every city to which it is connected--not just the new stock added to A but the stock it had last turn as well.

Say A has 10 and B has 5, and their shared stock is 15. These are the appropriate values, right? At the end of the turn A gains 2 and B gains 4.

Code:
           A      B
start    10 15   5 15
----------------------
A += 2   12
A += B      20
----------------------
B += 4           9
B += A             27
----------------------
end      12 20   9 27

Not only do A and B's shared stockpile not match, they are both incorrect. The new value should be 15 + 2 + 4 = 21. The problem quickly escalates as you can see in the second turn (same A+2 and B+4) where the overall stock should be 21 + 2 + 4 = 27.

Code:
           A      B
start    12 20   9 27
----------------------
A += 2   14
A += B      29
----------------------
B += 4          13
B += A             41
----------------------
end      14 29  13 41

One solution is to accumulate the changes for a city in doBonusStock() and then add them to every connected city, including the city itself. You could start by creating and zeroing out a temporary array and adding to it each time you call changeBonusStock(). After looping over all plots and bonuses you would pass this array to changeOverallBonusStock() which would add the values in the array to every connected city, including itself.

Code:
CvCity::changeOverallBonusStock(long *bonusStockArray)
    for each city
        if loop city is connected or is this city
            for each bonus
                pLoopCity->changeBonusStock(eBonus, bonusStockArray[eBonus]);

BTW, int stores numbers up to 2.147 billion. Are you sure you need longs? :mischief:

Random Notes

You probably want iX/iY = - CITY_PLOTS_RADIUS without the +1 to make x/y go from -2 to 2 instead of -3 to 2. You are also including the corners. However, there is an easier method that allows you to loop over all the plots in a city's radius without relying on a hard-coded value for the radius or checking for corners:

Code:
for (int iPlot = 0; iPlot < NUM_CITY_PLOTS; ++iPlot)
{
	CvPlot* pLoopPlot = ::plotCity(getX_INLINE(), getY_INLINE(), iPlot);

	if (NULL != pLoopPlot)
	{
		... your code here ...
	}
}

You check if this city is working the plot using

Code:
if (pLoopPlot->isBeingWorked() && [B]pLoopPlot->getWorkingCity() == this[/B])

No need to check if the plot is owned by the city's owner as that is a requirement for being the working city of the plot.
 
Another way you could do this easily would be to update the stocks from CvPlayer instead of CvCity.


The function CvCity::doTurn() is run completely for City A, then City B, then City C. So if I connect City A to City B at the same turn that City B acquires a bunch of new resources, then the stockpile for City B will be larger than that for City A.

If instead you go to CvPlayer::doTurn() to run these, you would have a loop over all cities to update the LOCAL stock (initialize to 0 at the start of the function), and then a SEPERATE loop over all cities to update the SHARED stock (again, initialized to 0 at the start of the function)

You would want these two loops to come after CvCity::doTurn's are all processed, so you could actually do the Local Stockpiles in CvCity::doTurn still, to save a loop.

From CvPlayer::doTurn
Code:
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		pLoopCity->doTurn();
	}

So right after this you would insert:

Code:
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		pLoopCity->doOverallBonusStock();
	}

And you should be fairly well set.
 
success!

THANK YOU to xienwolf, emperorfool, and god-emperor for your help and patience.
so the stockpiles are working exactly like i want them to. below is the code for anyone interested in the development of this.

in cvcity::reset
Code:
	if (m_aiBonusStock == NULL)
	{
		m_aiBonusStock = new int[GC.getNumBonusInfos()];
	}
	for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
	{
		m_aiBonusStock[iI] = 0;
	}
	if (m_aiOverallBonusStock == NULL)
	{
		m_aiOverallBonusStock = new int[GC.getNumBonusInfos()];
	}
	for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
	{
		m_aiOverallBonusStock[iI] = 0;
	}

in cvcity::doturn
Code:
doBonusStock();

in cvplayer::doturn
Code:
	for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
	{
		pLoopCity->doOverallBonusStock();
	}

functions:
Code:
void CvCity::doBonusStock()
{
	int iChange;
	for (int iPlot = 0; iPlot < NUM_CITY_PLOTS; ++iPlot)
	{
		CvPlot* pLoopPlot = ::plotCity(getX_INLINE(), getY_INLINE(), iPlot);
		
		if (pLoopPlot != NULL)
		{
			if (pLoopPlot->getBonusType() != NO_BONUS)
			{
				CvBonusInfo& pBonusInfo = GC.getBonusInfo(pLoopPlot->getBonusType());

				if (pLoopPlot->isBeingWorked() [COLOR="Blue"]&& pLoopPlot->getWorkingCity()->getIDInfo() == getIDInfo())[/COLOR]
				{
				
					CvTeamAI& team = GET_TEAM(getTeam());
					bool bCollectOK = false;
				
					if (pBonusInfo.getTechReveal() == NO_TECH)
					{
						bCollectOK = true;
					}
					else
					{
						if (team.isHasTech((TechTypes) pBonusInfo.getTechReveal()))
						{
							bCollectOK = true;
						}
					}
					
					if (bCollectOK == true)
					{
						if (pBonusInfo.getTechObsolete() != NO_TECH && team.isHasTech((TechTypes) pBonusInfo.getTechObsolete()))
						{
							bCollectOK = false;
						}
					}
					
					if (bCollectOK == true)
					{
[COLOR="Red"]						BonusTypes eBonus = pLoopPlot->getBonusType();
						iChange = 1;
						changeBonusStock(eBonus, iChange);
						m_aiOverallBonusStock[(int) eBonus] = getBonusStock(eBonus);[/COLOR]
					}
				}
			}
		}
	}
}

void CvCity::doOverallBonusStock()
{ 
	CvCity* pLoopCity;
	int iI, iLoop;
	[COLOR="red"]for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (pLoopCity->isConnectedTo(this) && pLoopCity !=this)
		{
			for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
			{
				BonusTypes eBonus = ((BonusTypes) iI);
				m_aiOverallBonusStock[(int) eBonus] = m_aiOverallBonusStock[(int) eBonus] + (pLoopCity->getBonusStock(eBonus));
				[/COLOR]
			}
		}
	}
} 
		

int CvCity::getBonusStock(BonusTypes eBonus)
{
	return m_aiBonusStock != NULL ? m_aiBonusStock[(int) eBonus] : 0;
}

void CvCity::setBonusStock(BonusTypes eBonus, int iValue)
{
	if (m_aiBonusStock != NULL)
	{
		if (iValue > 0)
		{
			m_aiBonusStock[(int) eBonus] = iValue;
		}
		else
		{
			m_aiBonusStock[(int) eBonus] = 0;
		}
	}
}

void CvCity::changeBonusStock(BonusTypes eBonus, int iChange)
{
	setBonusStock(eBonus, getBonusStock(eBonus) + iChange);
}

int CvCity::getOverallBonusStock(BonusTypes eBonus)
{
	return m_aiOverallBonusStock != NULL ? m_aiOverallBonusStock[(int) eBonus] : 0;
}

and then i exposed the getOverallStock function in python in CyCity and CyCityInterface1 in order to be able to replace the getnumbonuses functions in the city screen with my functions.

Everything is working very nicely and I am now going to continue sprucing things up. mainly by changing the amount of bonuses collected based on the improvement type being worked. then i will move on to buildings consuming and creating bonuses or yields. all of these things will require a new "resources" screen, so that players can keep track of where bonuses are coming from and how many are being added and subtracted every turn.

but really the most ambitious thing i've been thinking of, is a "global" market for bonus stockpiles, where civs sharing open borders can put an amount of a stockpile on the market at a market-determined price, and then proceed to buy and sell stockpiles of bonuses to each other.

again, thanks everyone for your help, i feel that i've learned quite a bit!
 
Congrats on getting it working. :goodjob:

There is still that one issue I mentioned above: a city's stock is added to the shared overall stock of its neighbors each turn--not just the new bonuses collected that turn.

For example, say you have two cities each with 10 in their individual stocks and 10 in their overall stocks (because they are isolated), and each city is collecting 1 bonus per turn.

Now you connect them with a road. They will each gain their individual 1 bonus, and then they will each add the 11 from the other city's stock to their shared stocks. Now each city has 11 individual and 21 overall bonus stockpiles.

On the next turn they will again each add 1 to their stocks (bringing them to 12), and add each others stocks to their overall stocks (21) yielding 33 in their overall stockpiles.

Is this what you want?
 
Congrats on getting it working.

There is still that one issue I mentioned above: a city's stock is added to the shared overall stock of its neighbors each turn--not just the new bonuses collected that turn.

For example, say you have two cities each with 10 in their individual stocks and 10 in their overall stocks (because they are isolated), and each city is collecting 1 bonus per turn.

Now you connect them with a road. They will each gain their individual 1 bonus, and then they will each add the 11 from the other city's stock to their shared stocks. Now each city has 11 individual and 21 overall bonus stockpiles.

On the next turn they will again each add 1 to their stocks (bringing them to 12), and add each others stocks to their overall stocks (21) yielding 33 in their overall stockpiles.

Is this what you want?

thank you! actually what happens is each city will gain 2 per turn in their overall stocks and 1 in their individual stocks. so cities A and B have 10 each. they are connected. next turn they will each have 22. this is because the overall stock is inherently based on just combining the individual stocks (2 times 11), so the individual stocks continue to grow at the normal rate, they just apply their growth to the overall stock. if the connected were severed the next turn, each city would retain their individual stock of 12 (continuing with the expectation of 1 per turn to the individual stock), and thus each of their overall stocks would be 12. had they still been connected their overall stocks would each be 24.

the problem is i have yet to implement any feedback on this process, so lets say an unconnected city has an overall and individual stock of 10 and then builds something that costs 10 from the overall stock. the city will still have the individual stock of 10 and thus the cost actually isn't applied. but that aspect will be worked in soon enough.
 
Top Bottom