Okay, I am CAFFEINATED!... and can finally try to make sense of this.
If you're going to include the Core CPA formula may as well include the normal one (that's why I pointed to the logs, though obviously getting a natural CPA to be announced for observation purposes is nontrivial unless you have a handy save), so here's an example log entry from a fairly vanilla diff 7 game:
Honestly I was just pointing it out there for completeness. When I rewrite the wiki article I intended to do the calculations in a separate section.
since diff > 7, numberOfSecondsPerPointOfMinimumAIPForCPAPurposes = 360 + ( (FInt)60 * ( (FInt)7 - this.AIDifficulty ) ).IntValue = 342
This is what determines the scale of the "alternative minimum AIP". At diff 7 it's just 360, and below diff 7 it's "360 + ( (FInt)51 * ( (FInt)7 - this.AIDifficulty ) ).IntValue;"
Okay, Googlefu has failed. What's FInt do, that a Floating Int declaration or something?
Also, how does this affect it on higher difficulties? I can probably figure that out once I know what FInt is doing. Also, found the CPA listing finally in Waves_MainThread. It looks like this number ends up static for the entire game, that'll make things easier. I'll probably just make that into a table for sanity's sake.
difficultyFactor = ( this.AIDifficulty * this.GetHandicapMultiplier() ) / ( 13 - this.AIDifficulty ) : 1.28
This is the diff/handicap multiplier adapted from wave-calc logic.
The "difficultyFactor" variable name is a bit imprecise, in that difficulty is factored in many times throughout this whole tour-de-pain. Its overall impact is quite explodential.
Interesting, so Diff affects both the minimum AIP calculation and then affects the CPA volume itself.
simulateMaxTimeWaveFactor = Mat.One + ( ( this.AIDifficulty * 2 ) / ( ( 14 - this.AIDifficulty ) * 3 ) ) : 1.73
This is simulating the max size increase a wave can get from simply having been a long time since the last wave. Iirc waves can have a higher multiplier than this now due to the ingress-point calculation thing (which does not apply here) but that's where this is originally from.
What's Mat.One stand in for?
humanHomeworldCountMultiplier = Mat.One + ( (FInt)( humanHomeworldCount - 1 ) * FInt.FromParts( 0, 330 ) ) + ( championCount * FInt.FromParts( 0, 066 ) ) = 1
Just accounting for champs and multiple HWs.
Just to dig into this far too deeply, what's .FromParts doing here? Not being able to find the base function I can't check out the methods associated with it.
numberOfShips (before applying cap-scale) = ( (FInt)effectiveAIPForCPAPurposes * difficultyFactor * simulateMaxTimeWaveFactor * simulateDoubleWaveFactor * simulateDifficultySpecificWaveSizeMultiplier * humanHomeworldCountMultiplier ).IntValue = 1094
Putting it all together. As Bognor pointed out, if the result would be less than 200 here it just doesn't bother and skips the CPA.
The next and final step in computing the actual number of ship is: on normal caps divide this by 2; on low it divides by 4, and on ultra low it divides by 8.
Ah, that's what you mean there by cap-scale. For some reason I thought wave ship-caps multipliers were going to come into play. That's... brutal. Explains why I nearly got eaten by the last CPA... (Yes, this particular game is going on the timescale of epicness... I'm at 15.5 hours in already).
11/27/2012 11:24:30 PM (6.009)
-----------------------------------
Triggering CPA (always from first AI); Game Time: 13:51:00
effectiveAIPForCPAPurposes = this.AIProgressionLevelEffective = 147
since diff > 7, numberOfSecondsPerPointOfMinimumAIPForCPAPurposes = 360 + ( (FInt)60 * ( (FInt)7 - this.AIDifficulty ) ).IntValue = 240
minimumAIPForCPAPurposes = Game.Instance.GameSecond / numberOfSecondsPerPointOfMinimumAIPForCPAPurposes = 207
effectiveAIPForCPAPurposes = Max(effectiveAIPForCPAPurposes,minimumAIPForCPAPurposes) = 207
difficultyFactor = ( this.AIDifficulty * this.GetHandicapMultiplier() ) / ( 13 - this.AIDifficulty ) : 2.25
simulateMaxTimeWaveFactor = Mat.One + ( ( this.AIDifficulty * 2 ) / ( ( 14 - this.AIDifficulty ) * 3 ) ) : 2.2
simulateDoubleWaveFactor = 2
simulateDifficultySpecificWaveSizeMultiplier = 2.5
humanHomeworldCountMultiplier = Mat.One + ( (FInt)( humanHomeworldCount - 1 ) * FInt.FromParts( 0, 330 ) ) + ( championCount * FInt.FromParts( 0, 066 ) ) = 1
numberOfShips (before applying cap-scale) = ( (FInt)effectiveAIPForCPAPurposes * difficultyFactor * simulateMaxTimeWaveFactor * simulateDoubleWaveFactor * simulateDifficultySpecificWaveSizeMultiplier * humanHomeworldCountMultiplier ).IntValue = 5123
Everything else looks right
Thanks Keith, appreciate the in-depth discussion on this.