#### Theorycrafting 101: Haste Part 2 - DoTs and HoTs Math

by

, 24-09-2012 at 04:24 AM (18502 Views)
The math behind how haste effects damage & healing over time is complicated. Working out the number of ticks from a given amount of haste is fairly straightforward, but reverse calculating the break points for additional ticks is a bit more complicated.

Before we get started, some history on how we arrived at the current mechanics. Back in July 2011 Hamlet posted a Theorycraft 101 post on Haste Breakponts & Rounding. Comments started to come in with occasional observed values that didn’t quite match the breakpoints his calculations produced. A bit of investigation produced a new post in which it was discovered that “Banker’s Rounding” or Round Half to Even was being used to calculate the number of ticks. The problem with reading those entries is that the LaTeX plugin on ElitistJerks is currently (as of this post, at least) not working, so it makes it a bit hard to follow the math.

Precursor: Haste Rating to Percentages

Before we begin, I’ll review how your total haste percentage is calculated, as this will be used in reverse in the breakpoint section. The formula goes like this:

The first part is your total haste rating, divided by the conversion factor at level 90 which is 425, and divided again by 100 to convert it into a percentage. Then all %-based haste effects have 1 added to them and are multiplied in. Note that this applies to all haste buffs, not just two as mentioned in the above formula. Once that is done, subtract 1 to return it to a normal percentage.Code:TotalHastePercentage = ( 1 + ( hasterating / 42500 ) * (1 + hastebuff1 ) * (1 + hastebuff2 ) - 1

Forward Calculating: Tick Count from Haste

Now on to the forward calculation, where we go from a total haste value as calculated above, to a number of haste ticks. The unrounded tick count formula is this:

What we’re doing here is finding the number of ticks the DoT has before haste, and then increasing to account for the fact that haste make all ticks occur more quickly.Code:HastedTickCount = (BaseDuration/BaseTickTime) * (1 + Haste)

The complicated bit for this section is that the Banker’s Rounding (Half to Even) applies here. If we have exactly 6.5 ticks, it will round to 6, but 7.5 ticks rounds to 8. In practice it’s unlikely that you’ll hit exactly half a tick, so it’s OK to use normal rounding:

Code:HastedTickCount = Round( (BaseDuration/BaseTickTime) * (1 + Haste) ,0 )Reverse Calculation: Haste Breakpoint from Tick Count

This is where it gets complicated. I’ll take things step by step here to make it a bit easier to follow. Note: Time is measured in milliseconds (ms) for this, as the game rounds to the nearest whole millisecond.

Part 1: Tick Speed

First we need to work out the tick speed required for a particular breakpoint.

Subtracting 0.5 off the tick count gives us that point where the tick count will round up to our target value, or would do if normal rounding was used. In order to get it working correctly for Banker’s Rounding, we have to do something complicated. The following is from my haste breakpoint spreadsheet:Code:TickSpeed = BaseDuration / ( TickCount - 0.5 )

There are a few functions here that are probably unfamiliar to most, so I’ll explain what they do:Code:=IF ( ISEVEN ( TickCount ) , FLOOR ( TickSpeed , 1 ) + 0.5 , CEILING ( TickSpeed , 1 ) - 0.5 )

So what the formula is doing is this:

- ISEVEN returns true or false depending on whether the number, truncated to zero decimal places, is even or not.
- FLOOR rounds a number down to the nearest multiple of the second number
- CEILING does the same thing as FLOOR, but rounds up rather than down.

The reason we do this, even though the THEN and ELSE parts of the formula look very similar, is because if we hit an exact whole millisecond tick speed the result depends on whether the tick count is even or odd. For any tick speed that isn’t a whole number the results will be the same either way.

IFthe TickCount is evenTHENround TickSpeed down to the nearest multiple of 1, then add 0.5ELSEround TickSpeed up to the nearest multiple of 1, then subtract 0.5

This is done because the even ticks will include the normal breakpoints, while odd ticks will occur at a slightly lower tick speed than the normal breakpoint. This is that Banker’s Rounding or Round to Nearest Even behaviour mentioned earlier.

Part 2: Haste Percentages

Now that we have our tick speed (in milliseconds) it’s time to convert that into a haste value. This part is fairly easy.

Code:Haste% = BaseTickSpeed / NewTickSpeed - 1Part 3: Haste Ratings

To calculate the haste rating required to obtain that Haste %, we use:

If you remember the earlier sections, this is fairly self explanatory. Multiply the Haste% by 42500 to both convert it out of a percentage and get the amount of rating required, and use the CEILING function to round it up to the nearest multiple of 1. The MAX function is to make sure that the lowest result returned is zero. Why we do this will become apparent as we calculate multiple haste sources.Code:CEILING ( MAX ( Haste% * 42500 , 0 ) , 1 )

For those, we divide the Haste% by each haste source:

As before, there are cases where there are additional haste buffs, so they will get treated in the same way, continually dividing the required haste value by each haste buff until you’ve included them all. With one or more haste buffs it’s likely that one or more of the breakpoint calculations are negative, so because you can’t have negative haste rating that’s why the MAX function was added in.Code:CEILING ( MAX ( ( (1 + Haste%) / (1 + HasteBuff1%) / ( 1 + HasteBuff2% ) ) * 42500 , 0 ) , 1 )

And now you’re an expert too

Or at least less confused than you were before. It’s OK if you don’t understand some of the formulae (they do my head in sometimes too), but now you know what calculations to run to do this yourself. If you follow the reverse calculations correctly you should match the Caster and Healer haste breakpoint cards I’ve made.

Many thanks to Hamlet for clarifying a few things & helping me simplify my formulae.