Based on this thread and a
district cost thread on Reddit, I think I have worked out the
COST_PROGRESSION_GAME_PROGRESS formula. It looks like it is essentially the same as the district cost formula, but with a variable scale and no below-average discount. The value is the fraction of techs or civics complete (whichever is more), expressed as a whole number percentage.
techProgress = # techs / 68
civicProgress = # civics / 51
progress = math.floor(100 * math.max(techProgress, civicProgress))
The maximum cost is based on the
PointProgressionParam1 value, which is a percentage of base cost:
maxCost = baseCost * param / 100
The total cost is then a linear interpolation from base to maximum cost (rounded down):
cost = lerp(baseCost, maxCost, progress / 100)
The
COST_PROGRESSION_NUM_UNDER_AVG_PLUS_TECH formula seems to work the same way, except that the maximum cost is always 1000% (like the Aqueduct and Neighborhood districts). For this progression, the parameter is instead the per cent discount for having fewer than the average number of districts of the type. For the current game rules, that is a 40% discount for all districts.
discountCost = math.floor(baseCost * (1 - param / 100))
I am testing this against save files from a game I just finished. So far the values work out for specialty district costs, aqueduct costs, and district project costs. I have one save with 44/68 techs progress:
progress = math.floor(100 * 44 / 68) = 64%
specialty district / neighborhood
baseCost = 54
maxCost = 54 * 1000% = 540
cost = lerp(54, 540, 64%) = 356
discounted specialty district
discountCost = math.floor(54 * 0.6) = 32
maxCost = 32 * 1000% = 320
cost = lerp(32, 320, 64%) = 216
aqueduct
baseCost = 36
maxCost = 36 * 1000% = 360
cost = lerp(36, 360, 64%) = 243
district project
baseCost = 25
maxCost = 25 * 1500% = 375
cost = lerp(25, 375, 64%) = 249
These exactly match the values in my production panel.
EDIT: After measuring a few games, I noticed that some of my numbers were off by one, so I verified counts, and it appears that my example should have been 44/68 = 64% instead of 43/67 = 64%. I suspect that the older threads are missing a tech that wasn't there at launch, perhaps Future Tech? Some of the numbers change depending on exactly how you multiply and round, and this model seems most consistent with my measurements so far.