I've been mulling this over for too long now. I figured I should post this publicly to get other thoughts rather than to let it fester and rot in my head. Kinda long read, and uh...
I'm afraid we need to use...MATH - YouTube
Basically, the way Combat is done right now relies on iteration to convergence. If you don't know what that is, it means we calculate the interactions with Restless Blades until the DPS stops moving much. Since Restless Blades means the more finishers we do, the more ARs we cast, which means we have more energy for more finishers. It leads into itself.
What I want to do, is break the Combat calculations up into phases. 4 of them to be precise. One phase with neither AR nor SB active, a phase with just AR, another phase with just SB, and another phase with both. I think this gives us greater control over energy capping (which I definitely think will come up as a concern again), and it lets us handle scenarios like the 4 piece since we don't have to extensively rewrite anything.
The concern that comes up then, is that the Restless Blades effect would pose a serious problem when we call the attack_counts up to 4 times. So the idea is that we treat RB as a sort of vector.
CD(1-RB/(INT+RB))
i.e.
180(1-10/(1/x+10)) from 0 to 1
180(1-10/(1/x+10)) from 0 to 1 - Wolfram|Alpha
CD would be the CD of the ability, RB is the impact of RB in seconds, and INT is the interval of finishers that trigger RB. Since we store them as
finishers per second in the engine, we need to grab the reciprocal to get the average interval.
As we can see from the graph, one RB finisher every 10s (.1 finishers per second) generates an actual CD of 90s from 180s. This makes perfect sense once you realize you shave 10s off your CD every 10s (aka 20s for every 10s), which is another way of saying we're progressing through the cooldown twice as fast as normal, or half the base CD.
The next point of reference should be .2 finishers per second (once every 5 seconds). This generates an actual CD of 60s, which is 1/3 of 180, aka we're progressing through the CD 3 times as fast. Which again makes sense since that's 20s off the CD every 10s, or 30s for every 10s.
Now, this function does break at 0 (the condition needs to be handled prior to execution), but we can look at the limit as X approaches 0. It does just so happen to be 180, and it should since hitting AR and never casting a finisher means we should have a 180s CD.
lim(x->0) 180(1-10/(1/x+10)) - Wolfram|Alpha
The CD length is irrelevant (meaning it applies to both KS and AR/SB), and the only thing that matters is that it can benefit from RB. Everything should scale to match the respective values.
Now, what we can do with this is determine the phase length, then subtract the relevant value from the CD based on the actual CD, and continue with this until all the phases are accounted for in the order of largest to least significant order. This is important because the no AR and no SB phase has no explicit phase limitation.
The the trajectory of the "vector" is defined by the non CD segment: "(1-RB/(INT+RB))". What we can do with this is divide the phase duration by that value to get the effective timespan, then subtract that from the base CD. This is the cached CD that gets passed through when we start to bring all this together. This method can't be used on the final phase, but we can use the final cached CD as the CD in the first function presented to get the effective length of the phase. You then add the phase lengths up to get the final,
actual, CD for the ability. As in...
Say we have .2 finishers per second during AR+SB, for 15s. That's 15/.3333= 45s effective phase length. Lets assume we have 3s of just AR after that, at .1 finishers per second. We then take 180-45= 135s as the remaining CD length, but we have 3/.5=6s. So that becomes 135-6=129s effective CD. But then we have the no AR and no SB phase. With, lets say, .05 finisher per second. We then take that last effective CD and calculate 129(1-10/(1/.05+10)) = 86... Now add 15+3+ 86 =104s for the final actual CD. That's the number we use when we weight the phase's DPS contributions to the final DPS. Phase AR+SB is 15/104, Phase AR is 3/104, Phase None is 86/104.
EDIT: I'll admit, I was expecting a little more discourse.