2 more things for the to do list

timschuett

Chieftain
Joined
Feb 20, 2013
Messages
72
Location
Lombard, IL
1. The food Waste Bug as discussed in previous posts. As I continue playing, I'm seeing stranger behavior of the waste modifier. Now I have a city that is wasting far more than the net food growth, and net growth is much less than 100 of the food consumed by citizens. I was under the impression that waste only began when you were over that 100% threshold (ie, citizens consume 100 :food: , waste begins at 200 total :food: and only affects the surplus over 100 net :food:)

2. Enemy cities on my border try to join my empire every several turns as a result of my espionage; culture spread and aid rebel faction. I get a popup with 2 choices at the start of the turn saying "good news! The roman cities of..." wanna join you or they'll split off and form another civ. Neither option works. Next turn, no change, and the rev levels of the cities in question return to normal. Not sure if thats a custom game setting I have, the fact they're a vassal civ, or a bug.

Something else to do during the freeze.
 
I MIGHT be able to look into the 2nd one there before release but it's low priority as it's frustrating, yes, but not gamebreaking. The first is just too far out of my scope at the moment.

Any of these that don't get taken care of should go on the 'known bugs list'. It was a good idea for DH to post those known unresolved bugs onto the first page of the cycle's bugs and crashes forum and if we can keep doing that we can probably track them better in general.
 
I MIGHT be able to look into the 2nd one there before release but it's low priority as it's frustrating, yes, but not gamebreaking. The first is just too far out of my scope at the moment.

Any of these that don't get taken care of should go on the 'known bugs list'. It was a good idea for DH to post those known unresolved bugs onto the first page of the cycle's bugs and crashes forum and if we can keep doing that we can probably track them better in general.

Cool. Will post there next. Also, Did some more digging and it appears that the city switching mechanism DOES work for AI players, both to join an empire and create a new civ. For What its worth....
 
Cool. Will post there next. Also, Did some more digging and it appears that the city switching mechanism DOES work for AI players, both to join an empire and create a new civ. For What its worth....

Actually that IS helpful because that means I can find the AI code and make sure the popup's routines follow this procedure correctly.
 
Ack... I realized that second issue you have there is controlled by Rev which is controlled in python which means that the popup is not handled in the dll which means it's out of my territory to mess with. Sorry... Rev is a bit buggy at times is about all I can say since I'm not qualified to work with deep python programming of that nature.
 
Looking into the first issue I'm a little confused because it's programmed with some methods I don't understand. Perhaps some other programmers could clarify for me what is going on in this:


Code:
float CvCity::foodWastage(int surplass) const
{
#define	MAX_SURPLASS	500
	static	float	calculatedWaste[MAX_SURPLASS];
	static	int calculatedTo = -1;
	int		startWasteAtConsumptionPercent = GC.getDefineINT("WASTAGE_START_CONSUMPTION_PERCENT");
	float	wastageGrowthFactor = GC.getDefineFLOAT("WASTAGE_GROWTH_FACTOR");

	if ( wastageGrowthFactor == 0 )
	{
		wastageGrowthFactor = (float)0.05;	//	default
	}

	if ( startWasteAtConsumptionPercent >= 0 )
	{
		if ( surplass == -1 )
		{
			surplass = foodDifference(true, false) - (GC.getFOOD_CONSUMPTION_PER_POPULATION()*getPopulation()*startWasteAtConsumptionPercent)/100;
		}
	}
	else
	{
		surplass = -1;
	}

	//	Nothing wasted if there is no surplass
	if ( surplass <= 0 )
	{
		return 0;
	}
	//	Cache what we can as it's not a trivially cheap computation
	else if ( surplass <= calculatedTo )
	{
		return calculatedWaste[surplass];
	}
	else
	{
		if ( surplass >= MAX_SURPLASS )
		{
			//	After the max we bother calculating it all gets wasted
			return calculatedWaste[MAX_SURPLASS-1] + (surplass - MAX_SURPLASS + 1);
		}
		else
		{
			calculatedWaste[surplass] = foodWastage(surplass-1) + ((float)1 - (wastageGrowthFactor + pow((float)1.0 - wastageGrowthFactor, surplass))/((float)1.0+wastageGrowthFactor));
			calculatedTo = surplass;

			return calculatedWaste[surplass];
		}
	}
}
The first confusing point I can identify here is calculatedWaste[whateveryouputinhere]. I don't understand this expression. It's declared as a static float. I've seen it elsewhere where an int or a float has a [] after it and a variable between the brackets but I don't know what that means or does.
 
Looking into the first issue I'm a little confused because it's programmed with some methods I don't understand. Perhaps some other programmers could clarify for me what is going on in this:


Code:
float CvCity::foodWastage(int surplass) const
{
#define	MAX_SURPLASS	500
	static	float	calculatedWaste[MAX_SURPLASS];
	static	int calculatedTo = -1;
	int		startWasteAtConsumptionPercent = GC.getDefineINT("WASTAGE_START_CONSUMPTION_PERCENT");
	float	wastageGrowthFactor = GC.getDefineFLOAT("WASTAGE_GROWTH_FACTOR");

	if ( wastageGrowthFactor == 0 )
	{
		wastageGrowthFactor = (float)0.05;	//	default
	}

	if ( startWasteAtConsumptionPercent >= 0 )
	{
		if ( surplass == -1 )
		{
			surplass = foodDifference(true, false) - (GC.getFOOD_CONSUMPTION_PER_POPULATION()*getPopulation()*startWasteAtConsumptionPercent)/100;
		}
	}
	else
	{
		surplass = -1;
	}

	//	Nothing wasted if there is no surplass
	if ( surplass <= 0 )
	{
		return 0;
	}
	//	Cache what we can as it's not a trivially cheap computation
	else if ( surplass <= calculatedTo )
	{
		return calculatedWaste[surplass];
	}
	else
	{
		if ( surplass >= MAX_SURPLASS )
		{
			//	After the max we bother calculating it all gets wasted
			return calculatedWaste[MAX_SURPLASS-1] + (surplass - MAX_SURPLASS + 1);
		}
		else
		{
			calculatedWaste[surplass] = foodWastage(surplass-1) + ((float)1 - (wastageGrowthFactor + pow((float)1.0 - wastageGrowthFactor, surplass))/((float)1.0+wastageGrowthFactor));
			calculatedTo = surplass;

			return calculatedWaste[surplass];
		}
	}
}
The first confusing point I can identify here is calculatedWaste[whateveryouputinhere]. I don't understand this expression. It's declared as a static float. I've seen it elsewhere where an int or a float has a [] after it and a variable between the brackets but I don't know what that means or does.

It's an array allocated with MAX_SURPLASS elements. Because of the "static" in the declaration it is permanently allocated, not allocated each time the function is run, and it remembers what was in it across calls to the function. This is similar to making it global except that it is allocated the first time it is encountered and it is accessible only in the function where it is created (well, it is possible, I expect, to find it and use it if you really wanted to but it would be such a huge nuisance that there is no real point in doing so). Every instance of the CvCity object will use the same static array in that function, so the data is shared (not 500 floats per CvCity, just 500 total).

In this case its purpose is to act as a cache of the calculated values. Each time it hits a surplus level higher than the highest calculated value so far it calculates the waste for that new surplus value, puts it in the array, updates the calculatedTo value (which records the highest point in the array that has been used), and then returns the value. If the value of the "surplass" variable is less than or equal to calculatedTo then it has already calculated the waste amount for that surplus value and just returns what is in the array.

Edit: argh. I failed to notice the waste calculation ends up calling this same function at the calcualted surplus -1 when calculating the waste. Therefore you can ignore everythign after this as it is wrong...

I think this is the cause of some of the wild fluctuations in food waste as it has a significant flaw. It assumes that each time the "surplass" variable exceeds the "calculatedTo" value that it only is 1 higher. If it is not, then there are elements of the "calculatedWaste" array which never have a value calculated for them. At those amounts of surplus it will just return whatever the value was set to during the array allocation (it ought to be 0 since the elements of static arrays are supposed to be initialized to 0 if nothing else is specified).

So if you skip one or more surplus values there will be 0 values in the array that never get changed because they are at indexes less than he calculatedTo value. This is probably happening pretty often. Consider a city that has a surplus of 5 which then gets an improvement built or switches which plot it works so that the city is now producing 2 more food than before. It's surplus goes from 5 to 7 and therefore the waste for the specific surplus values of 5 and 7 have been calculated and stored in the array, but the waste for the surplus value of 6 has never been calculated and never will be so at the surplus value of 6 the waste is 0.

The fix is to loop over every value from calculatedTo +1 to the value of "surplass" and calculate a new value for each of these elements of the array, instead of just calculating the one at the value of "surplass".
 
Ok... I'm following that. (Well... not quite sure how to structure the loop you're talking about necessarily but I might be able to figure that out still.)

Trying to understand the equation that determines the wastage here too... what does 'pow()' mean?
 
Trying to understand the equation that determines the wastage here too... what does 'pow()' mean?

The function name "pow" is short for "power". It raises the number in the first argument to the power in the second argument, so pow(5.0,2.0) is 5 squared (often expressed as 5.0**2.0, or occasionally 5.0^2.0, in languages that have a power operator built in: in C and C++ these don't do that as it has no power operator so you need to use this function).
 
Wait. Hold on.

I may have been hasty in mentioning that flaw...

I did not look at how it was actually calculating the waste, so I did not notice something that invalidates my whole "flaw". It is actually calling the same function to get the amount of waste at the calculated surplus -1. Since this is done before updating the calculatedTo it will recursively keep calling the function until it hits a value that has been stored in the array, after which it will walk up the values filling in the array as each call on the stack completes. (Going back to my example, to calculate the waste at a surplus of 7 it calls the function to get the surplus at 6 which is still above the calculatedTo value so that will do the calculation for the surplus level of 6 which calls this same function specifying a surplus of 5 which will actually return the waste value from the array as it was already calculated; then the calculation for waste at surplus of 6 completes, adding it to the array and updating calculatedTo, and then finally the calculation for 7 surplus completes, gets added to the array, updates calculatedTo, and returns the actual desired value. Fun with recursion.)

Well nuts. Apparently this perfectly good explanation of why the waste calculation apparently goes awry sometimes is neither perfect nor good.
 
Top Bottom