In a recent game, the city grew and finished its granary on the same turn. I thought half the food would then be saved since the granary finished on the same turn, but it did not. So the granary has to be there on the turn before growth?
Code laid down for reference:
FIRST CASE: Without Granary
That one seems easy:
Let's call
m_iFoodKept our variable that represents the inner property of a granary to stock food per turn up to its defined max (0.5*threshold).
m_iFood is the variable dealing how far we got in food bar.
Second point, we have to know this section of code is compiled each turn, which makes more than 1 update.
Third point, granary starts stocking food during the IBT
AFTER the turn being built. There is no food stockage timing with granary being built given the granary is built after food is put in the bin.
First,
m_iFoodKept is like a pig coin bank that receives an allowance, which is the same value as the food rate (iDiff).
Then,
m_iFoodKept is processed through a cropping function:
setFoodKept, which maxes out at
growthThreshold()/2. It is simply a restrictive range function where
m_iFoodKept can go from 0 to
growthThreshold()/2 (e.g. 22/2=11 for size one). If it goes below, the min is imposed otherwise over max, max is imposed.
But given there is no granary, then MAX value becomes 0. So the range is 0 to 0, thus only acceptable new
m_iFoodKept is 0.
Lastly, the food rate (iDiff=
foodDifference()) is added to
m_iFood
. And then the new
m_iFood
is reduced by
growthThreshold() and gained
m_iFoodKept. Nonetheless, there is none in the granary due to its absence, thus we end up with a simple growth.
E.G. We end up with
m_iFood
=26/24. Substract
growthThreshold() =24 and then the food bin is 2/26. Denominator is different because it is adjusted to the new size and the code doesn't process fractions but numerators as integers.
Conclusion: Matched game experience with the code.
Picture for next cases:
SECOND CASE: With Granary while being lower than half growthThreshold()
That's the green section in the picture. In a nutshell, we reach the max stockage capacity of the granary because "citizens had time to stock food".
Experience told us if we finish the granary and the same turn we end up with exact
growthThreshold()/2 or less, then after growth we get max stockage of granary.
That's normal point of view of the code as when we finish the granary halfway of
growthThreshold(), we have the other halfway to stock food in the granary and then the "citizens have time enough to stock full the granary". A granary in the middle of the picture (yellow line) means while the food rate adds to both
m_iFood
and
m_iFoodKept at the same time.
If the food rate makes some "surplus", then the cropping function will do its job by returning max value, which is
growthThreshold()/2.
Thus, game experience is now compatible with code.
THIRD CASE: With Granary while being higher than half growthThreshold()
That is the most interesting case and that one where we see less granary stock after growth and what we call doubling "surplus" food.
Experience told us if we finish the granary and the food rate meanwhile goes over half of
growthThreshold(), then the granary stock is lower than expected half.
Let imagine a situation where the food rate allows an exact growth without "surplus" food. If the granary was built in the red section, then the "citizens didn't have time to fully fill the granary". As already said, each turn, the food rate is added to both
m_iFood
and
m_iFoodKept at the same time and if there is less than
growthThreshold()/2, then the cropping function will certainly return a lower value than half-
growthThreshold().
Of course, under condition there is no "surplus" food that makes
m_iFood
= (>
growthThreshold())/
growthThreshold().
When we have surplus due to a food rate allowing that,
then because adjusted m_iFoodKept is processed before substracting food, this helps to catch up the "lack of food not gathered by citizens". And indeed, if the food rate makes the
m_iFoodKept go over
growthThreshold()/2, again we see the cropping function doing its job and thus the interesting part where "too much surplus food ended with no more doubling surplus".
Now, a fictitious example to illustrate the logics:
We're size one (threshold=22 food). We built granary at 13/22. And we have now a constant food rate of 6
per turn. Whatever the food rate before the granary being built, it doesn't matter because it is not stocked. Now, in the IBT, we start stocking food. Next turn, food bin is at 19/22 and food in granary is at 6. Next turn, we reach
m_iFood
=25, which is over 22, but it doesn't matter. Concept of surplus doesn't exist. Food in granary is now at 12, but being size 1, the cropping function does its job and crops at 11.
Finally, the code does the changePopulation function:
m_iFood-
growthThreshold()+
m_iFoodKept=
25-22+11=14 food. Yes, thanks to that immense food rate, we made up the loss of finishing the granary AFTER the yellow line in the picture.
The doubling factor came from both food bin and granary bin got their same share of food rate at the last turn before growth and when the cropping function starts to crop, bam granary stock stops to double "surplus" food.
Again, we have experiences combined with code reality.
This resumes the whole knowledge we can get from granaries.
Now, a whole micro hell comes from this because plenty of finishing granary optimal points rise. With many plots, it can be hard to choose which is the best combination of tiles to get most. Waiting to get more organic flow from plot outputs or simply whip now to get max from granary max stockage. Not counting situational reasons like getting OF for another build, or emergencies or bigger priorities.