This project is read-only.

Warlocks, Take 3

Topics: Rawr.Warlock
Mar 3, 2010 at 7:01 AM

It's time for me to start recruiting some help for my attempt at a fully-functional Warlock model.  Don't get excited yet, it's FAR from fully functional right now.

Currently I would love for anyone to look over what I've done so far and find mistakes.  To do that you'd have to get the Rawr source and look it over, and/or compile it with my temporary model and play with it.  Actually, for now it's probably best to focus on behavior rather than code, since the code structure will likely keep changing for a while.  Ideally I'd like to devote my time to the coding, but that would mean others out there would need to be testing for accuracy.  I can dream, right?

To see what should be working so far watch for my commit comments in the Source Code link at the top of the page.  I'll update in this thread as I think of specific questions I have, or specific parts of the model I suspect could be inaccurate.

Now, if something is showing zero benefit or zero dps, that's probably just something I haven't modeled yet (which is most things) and I already realize it.  What I'm looking for is help with the things I HAVE tried to model.  Thanks in advance to anyone who cares to spend time helping!

Mar 3, 2010 at 10:36 PM

I might be able to help a bit, but I have no programming knowledge outside of basic Excel formulas.  I can try to make sure you've accounted for all of the variables though.  I'm usually pretty good at figuring out formulas, and there's information all over the place about this stuff.

Mar 4, 2010 at 1:09 AM

Awesome.  Any help is appreciated.  For "formulas" you'll want to look at the file WarlockSpell.cs.  Anyone who is willing to help can contact me on MSN:


Mar 4, 2010 at 4:59 PM

Question for the developers out there: do we already have code somewhere that solves a linear system of 2 equations?  I only have 2 variables, so I coded in a (non-matrix) solution, but if we already have the code (or it's built into C#?) I'll use that instead.


Mar 4, 2010 at 9:06 PM
Edited Mar 4, 2010 at 9:08 PM

Even if we had it, for just 2 equations an explicit solution is better. If you ever need it for something more complex (i.e. 10+ equations) take a look at LU class in Base.Algorithms (not much in terms of documentation, look at example of use in MarkovProcess). We also have an LP solver, but I haven't generalized that to base yet.

Mar 5, 2010 at 12:15 PM

i'm working too on lock module.

i'll contact you from msn.

Mar 5, 2010 at 9:55 PM

I can't help with the theory but I can write code to a spec or write unit tests etc. One of my warlocks is level 80 and just hit a 5k GS so I can try things out if necessary.

Mar 6, 2010 at 4:18 AM

That's great, Mark.  Within the next couple days I hope to figure out C# reflection enough to make it very easy to add spells to the model.  If you get in touch with me over MSN I'll point you to the examples I've done.  That's the closest thing to code with a "spec" I can think of; it's basically just researching the different coefficients & related talents & plugging them into a constructor call.  Is wowwiki a good source for that info, does anyone know?

Mar 6, 2010 at 4:34 AM

Here is an algorithm I came up with for calculating the average delay between a spell coming off cooldown and being cast.  Please critique, all you accomplished theorycrafters!  I wanted to translate into pseudo code, but I just couldn't think of good ways to do that for most of it.  Sorry :/

/// avgSpellCastTime = <param name="avgSpellCastTime" />
/// The average spell casting time for *lower* priority spells.
private float GetCollisionDelay(float avgSpellCastTime) {

    List castTimes = *the (actual average) cast time of each higher priority spell*;
    List frequencies = *NumCasts / FightLength of each higher priority spell*;

    // Create a map of the probability of randomly choosing a point in
    // time while key[0] is being cast, and key[1-n] are all queued up
    // after it.  This assumes 1) spells have an equal chance of coming
    // off cooldown at any given point in time, and 2) no spell on a
    // cooldown can show up twice in the same string of spellcasts.  (1)
    // is a simplifying assumption.  I believe (2) holds true for any
    // in-game warlock.
    Dictionary probablities
        = new Dictionary();
    IntList allSpells = *a list from 0 to NumHigherPrioritySpells - 1*;
    foreach (
        IntList spellString
        in GetLongerPermutations(new IntList(), allSpells)) {

        // first calculate the probability of the given spell string
        int spell = spellString[0];
        float stringLength = castTimes[spell];
        float probability = stringLength * frequencies[spell];
        for (int i = spellString.Count; --i > 0; ) {
            spell = spellString[i];
            probability *= stringLength * frequencies[spell];
            stringLength += castTimes[spell];

        // then subtract the probability of it being the start
        // of a longer string of spellcasts
        foreach (
            IntList longerString
            in GetLongerPermutations(spellString, allSpells)) {

            probability -= probablities[longerString];
        probablities[spellString] = probability;

    // Use the probabilites to calculate a weighted average of how long
    // THIS spell will have to wait between coming off cooldown and
    // and being cast.
    float weightedAverage = 0f;
    float totalProbability = 0f;
    foreach (KeyValuePair pair in probablities) {
        IntList spellString = pair.Key;
        float probability = pair.Value;
        float delay = castTimes[spellString[0]] / 2;
        for (int i = spellString.Count; --i > 0; ) {
            delay += castTimes[spellString[i]];
        weightedAverage += probability * delay;
        totalProbability += probability;
        += (1 - totalProbability)
            * (AvgCastTime + Mommy.Options.Latency) / 2;
    return weightedAverage;

/// Creates all permutations longer than "stem" that can be made
/// by appending values in "values" that are not already included in
/// "stem".
/// <param name="stem" />A subset of "values".
/// <param name="values" />The universe of values to permute.
/// The order of permutations returned will be from longest to shortest.
private List GetLongerPermutations(IntList stem, IntList values);


Mar 6, 2010 at 4:41 AM

Any chance you can post the original C# for that? Your Pseudo-code is rather hard for me to understand at first glance. :)

Mar 6, 2010 at 5:47 AM

Ha!  I assume that was sarcastic - but just in case it wasn't - you can find the almost-identical code in the WarlockTmp folder of the source, in the Spells.cs file, in the Spell class.  :)


Mar 6, 2010 at 9:57 AM

The last programming language I taught myself was DOS BASIC, so I'll be useless for coding purposes.

But I'll be glad to help Afffliction Lock accuracy-testing.

Mar 7, 2010 at 5:23 AM

Great, thanks midnight.  I'll post a message here when it's ready for that!


Mar 8, 2010 at 12:35 AM

Ditto midnightlynx.  I'm a fair hand at Python or PHP, but C#/C++ are still beyond my ken (though I expect that will be changing in the near future). 

But I, too, am an interested Affliction-speced (Demo off-spec) Warlock, so any help I can provide, just ask!

Mar 8, 2010 at 7:54 AM

OK I'd like to have (at least) one of you aff. locks help me test now!  I believe I have everything modeled for an affliction rotation except the part of Everlasting Affliction that refreshes Corruption, any on-use or on-proc affects (other than Nightfall), tier bonuses, and pets.  But, even with those things missing I'm sure you'll find other problems for me to fix!  And probably other things that I didn't realize I'm missing.  Please contact me over MSN ( or the email link on Codeplex here and I'll send you a .zip.  Or if you're savvy enough, grab the source & I won't have to keep sending you .zips for testing.  After you grab source, if you're using Visual Studio (or the express version), right click on the solution -> "Add Existing Project" -> add WarlockTmp.  Thanks!

Mar 8, 2010 at 9:10 AM

Probably I could be of some help by providing a download page for the latest nightly build of rawr (of course including WarlockTmp support)?

Sorry I cannot provide more help at this time, even if I'm a C/C++ programmer playing a (destro) warlock as main char - but as I'm damn busy at the moment, I don't have a good mind to develop "after hours" ;-)

Mar 8, 2010 at 2:33 PM

I can definitely help out. C++/C# developer by day; my main is a Demonology Warlock with no real off-spec ( as the only 'Lock in the raid, I pretty much never spec out of Demo cuz of DP ). 

Mar 8, 2010 at 5:58 PM

Maleficus: That would be nice, thank you.

Shadowwolf: great.  Let me know when you're ready to start and I'll give you an assignment ;).  I'd post my next-priority changes for you now, but so far it seems popular to offer help but not follow through right away.  So again, please contact me over MSN ( or email (link on my user page).

Mar 8, 2010 at 10:56 PM
Edited Mar 8, 2010 at 11:55 PM

I set up a small page and uploaded my latest build (Commit 47266, which happens to be the latest change of the WarlockTmp module).
I'll try to update it with every change of the WarlockTmp module.

[edit]removed Download-URL[/edit]

@Astrylian: Sorry, didn't think about it.
@All interested testers: Contact me to get the Download-Location.

Mar 8, 2010 at 11:08 PM

Please do not post dev builds publically like this, to prevent user confusion. Please send it to testers like this directly.

Mar 9, 2010 at 12:06 AM

Sorry. I removed the link and changed the download location.

Mar 9, 2010 at 2:44 AM

Perhaps one of the other devs out there has seen a problem like this before and can help me fix it.  When displaying gear in the right-most pane it becomes fairly likely that Rawr will encounter an exception in my code that I can't figure out.  And it never happens when displaying talents or glyphs.  There's code that looks like this:

CalculateDps() {
    if (Dps >= 0) {
        return Dps;
    ... a bunch of calculations ...
    Dps = 3000 or whatever;
    return Dps;
The exception happens during the "bunch of calculations", and the debugger is telling me Dps = 3000-something at that point.  If you're paying attention, that means it shouldn't have been executing that code in the first place.  It's as though when displaying gear choices in the right-hand panel, it's calling CalculateDps() in two different threads on the same CharacterCalculations object at the same time (which I was definitely not anticipating).  Have any of you seen this before, and if so can you tell me how to fix it?

Mar 9, 2010 at 3:47 AM
Set a breakpoint and find out by reproducing it while running under the debugger?

From: [email removed]
To: [email removed]
Date: Mon, 8 Mar 2010 18:44:17 -0800
Subject: Re: Warlocks, Take 3 [Rawr:203628]

From: xemnosyst
Perhaps one of the other devs out there has seen a problem like this before and can help me fix it. When displaying gear in the right-most pane it becomes fairly likely that Rawr will encounter an exception in my code that I can't figure out. And it never happens when displaying talents or glyphs. There's code that looks like this:
CalculateDps() {
    if (Dps >= 0) {
        return Dps;
    ... a bunch of calculations ...
    Dps = 3000 or whatever;
    return Dps;
The exception happens during the "bunch of calculations", and the debugger is telling me Dps = 3000-something at that point. If you're paying attention, that means it shouldn't have been executing that code in the first place. It's as though when displaying gear choices in the right-hand panel, it's calling CalculateDps() in two different threads on the same CharacterCalculations object at the same time (which I was definitely not anticipating). Have any of you seen this before, and if so can you tell me how to fix it?

Read the full discussion online.
To add a post to this discussion, reply to this email (
To start a new discussion for this project, email
You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on
Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at
Mar 9, 2010 at 4:22 AM

There is a single instance of CharacterCalculations and it can be called from multiple threads at the same time. You should make GetCharacterCalculations thread-safe.

Mar 9, 2010 at 5:28 AM

You do mean Dps = -something, likely -1.0, and not Dps = 3000-something?

Also, it would be helpful to know what the exception is, and where it is occurring.  Short of that, follow Markdall's suggestion, and step through the code.

Mar 9, 2010 at 5:37 AM

Kavan pointed me in the right direction.  Fixed.  Thank you.


Mar 9, 2010 at 5:57 AM

AHHHHH!  Pets are driving me crazy.  Does anybody know an up-to-date source of pet stats and how they scale?  I'm currently naked and untalented in Undercity trying to figure this stuff out.  I have some decent stats for the basic pets' base stats and how their health & mana scales with their own stamina & intellect, but this is taking forever.  And I still don't know how each pet's stats scale with the Warlock's own stats, but I do know that the character sheet completely lies about it.  E.g. my character sheet goes from "increases your pets intellect by 46" to "329" when I put my gear on, an increase of 283.  However, my pet's actual intellect goes from 415-689, an increase of 274.  For stamina: 27-310 (283 increase) vs. 185-895 (710 increase).  Grr.  I also cannot figure out how to cancel Fel Intelligence :(.

I think I'll work on on-proc/on-use effects next and come back to this .... much later.  Say - anybody else want to just take care of pets?

Mar 9, 2010 at 7:01 AM

Cancelling Fel Int  - Open pet spell book and disable auto-cast?

I'd actually ask you to do pets first before you complete rest of model.

If you are Gnome/Human you might suffer additional problems with Int/Spirit scaling. I'm pretty sure someone has figured out pet scaling somewhere on EJ forums, We'd just have to sneak around and use the search a bit.

Mar 9, 2010 at 7:57 AM

Since you already have the pet base stats, here are the scaling stats:

        #region minion scaling factors
        /// <summary>
        /// minion inherits 75% of the master's stamina.
        /// </summary>
        protected const float InheritedStamina = 0.75f;
        /// <summary>
        /// minion inherits 30% of the master's intellect.
        /// </summary>
        protected const float InheritedIntellect = 0.30f;
        /// <summary>
        /// minion inherits 35% of the master's armor.
        /// </summary>
        protected const float InheritedArmor = 0.35f;
        /// <summary>
        /// minion inherits 40% of the master's resistances.
        /// </summary>
        protected const float InheritedResistances = 0.40f;
        /// <summary>
        /// minion inherits 15% of the master's spell power.
        /// </summary>
        protected const float InheritedSpellDamage = 0.15f;
        /// <summary>
        /// minion attack power is increased by 57% of the master's spell power.
        /// </summary>
        protected const float InheritedAttackPower = 0.57f;
        /// <summary>
        /// The minion's crit chance is increased by 10/20/30% of the master's crit chance,
        /// but only if the master has the Improved Demonic Tactics talent(s).
        /// </summary>
        protected float InheritedCriticalStrikeChance;
        /// <summary>
        /// minion inherits 100% of the master's spell penetration.
        /// </summary>
        protected const float InheritedSpellPenetration = 1.00f;
        /// <summary>
        /// minion inherits 40% of the master's resilience.
        /// </summary>
        protected const float InheritedResilience = 0.40f;
        /// <summary>
        /// minion inherits 100% of the master's hit chance - so if the master is hit capped, then the minion is too.
        /// This applies to Expertise too (according to the 3.2 patch notes), however warlocks dont have expertise ...
        /// </summary>
        protected const float InheritedHitChance = 1.00f;

Mar 9, 2010 at 9:11 AM

The reference to Expertise above works the same way as it does for Hunters. Basically, your Hit % against your Miss % affects the pet's dodges and parries. Instead of using Expertise to fill those gaps like a normal melee DPS would, you use your Hit instead.

So, if you are at the Spell Hit Cap (17% @ 83), then your pet will never miss and ALSO never be dodged/parried (for it's melee). If you are at Half that 17% which is 8.5%, then your pet's Miss gap will only be half filled and same for his Dodge/Parry gaps, half filled.

Mar 9, 2010 at 11:31 AM
Edited Mar 9, 2010 at 11:43 AM

[edit] Problem is already solved, I should have read _all_ emails before answering -.- [/edit]

Mar 9, 2010 at 7:58 PM

If you can't get fel int off by disabling autocast, try getting a mage and priest to int/spirit buff you. fel int doesn't stack with them, so your number won't change.

Mar 9, 2010 at 10:29 PM
Edited Mar 9, 2010 at 10:44 PM

Bah nevermind, I had messed up my enlistment in some profound way.

Mar 10, 2010 at 4:04 AM
Edited Mar 10, 2010 at 4:20 AM

So I "improved" the modeling of missed spells so that it mimics re-casting higher priority spells when they miss (if cooldowns don't forbid it).  However, this change has shifted the value of hit to be slightly lower than spell power, with which no other theorycraft seems to agree.  So I fear I'm doing something wrong.  Last time I posted code I got no responses, but this time I think it should be easier to follow.  Let me know if anyone sees something wrong with the way I'm doing this:


collisionDelay = avg time waiting for higher priority spells
recastPeriod = minimum time between successful spell casts
avgCastTime = the average casting time of your spells (estimated)
period = Max(recastPeriod, cooldown) + collisionDelay
if (canMiss && cooldown < recastPeriod) {

    // Decrease time between casts if this spell can miss, and
    // its cooldown is shorter than than we'd be casting it again
    // anyway.
    periodAfterMiss = Max(Cooldown, avgCastTime / 2) + collisionDelay
    period = WeightedSum(
        period, hitChance,
        periodAfterMiss, missRate);
numCasts = fightLength / period;

[Edit 1]: Nothing like expressing your thoughts to make you revise them.
I don't really know why I was trying to factor in double misses; the
period of any one spellcast is not affected by how many misses are in a
row. Changed above, though hit is even less important now.


Mar 10, 2010 at 7:19 AM

I solved this somewhat different for ShadowPriest. Any misses on recastable spells eat damage out of the filler spell. Non-recastable (MB for SP f.ex) have their damage entirely lost. Makes modelling a lot more simple, and most people want to be hit capped anyway, thus modelling works perfectly at hit cap :P

Mar 10, 2010 at 3:48 PM

Sounds like roughly the same effect.  I want to be as accurate as possible determining NumCasts, though, especially with a spell like Haunt, which causes you to looses a big damage boost when it misses.  It is also the only spell taking advantage of the "normal" recast time (which I currently have set to 10 seconds) being longer than the cooldown (8 seconds), which may help you understand the code above a little better.  And when I say "recast time", I mean the time at which a player sort of queues up the spell, after which s/he is still going to have to wait until s/he finishes whatever cast s/he was in the middle of.


Mar 11, 2010 at 7:45 PM

@ xemnosyst,  do you think any changes to Warlock model will be released anytime soon?  Just curious...

Mar 11, 2010 at 7:58 PM

Xemnosyst is not changing the current Lock model, he's making a new one from scratch utilizing all the current fun stuff that we've discovered over the course of Rawr's history.

ArPharazon is still working on the current Lock model.

Mar 11, 2010 at 10:56 PM

ArPharazon has not done anything for months now.  If we are waiting on him it will never be completed.   I'm putting my faith in Xemnosyst as we can see that he IS working hard on the new one.

Mar 11, 2010 at 11:19 PM

Not only is he working hard, it's looking pretty damn nice. Well... the 1/4 of it that's actually there.

Mar 12, 2010 at 2:54 AM

It is definitely looking very good.

Mar 12, 2010 at 3:08 AM
Edited Mar 12, 2010 at 4:03 AM

Blizzard hates theorycrafters.

[Later Edit]

So I just want to vent here.  I just got done figuring out exactly which talents & buffs get added together vs. multiplied.  Blizzard hates theorycrafters.  I wrote down all the craziness so I could vent about it:

The +damage% multipliers from talents (that do not manifest as buffs or debuffs) are added together, then multiplied with your +damage% buffs and the target's debuffs to get the final multiplier.  EXCEPT for malediction (a talent which is multiplied) and grand spellstone (a buff which is added).  Also, grand spellstone does not get applied to curse of agony (??!?!!).

Also of interest is that when Empowered Corruption says "Increases the damage ... by an amount equal to x% of your spell power", that percentage gets divided among the ticks.  HOWEVER, when Everlasting Affliction says "<spell list> gain an additional x% of your bonus spell damage", that gets applied to EACH tick.

In conclusion, Blizzard hates theorycrafters.

Mar 12, 2010 at 5:53 AM

You could have saved a lot of time and hassle if you had re-used the existing spell templates which had already been theorycrafted and validated via DrDamage.

Mar 12, 2010 at 2:44 PM

This is true.  I honestly forgot that I could probably get my info by looking at the spell objects in the current warlock model (which is really dumb of me, I know).  Also, now that I've spent a lot of time & know how these things work it'll probably be easier for me to understand the code.  I just downloaded DrDamage & checked it out; it indeed has everything I mentioned in my last post already factored into its calculations, except that Grand Spellstone does not apply to Curse of Agony.  I will definitely be using these two sources of info to speed along the development of Demo & Destro.

*Xemnosyst runs off to look at the original model's code...*

Yes, this will be helpful, but I don't think I'll just copy-paste and forget it.  Btw, I think AvgDirectDamage() is wrong.  Say I cast a spell 5 times and it score 10, 15(crit), 0(miss), 10, 10.  That's 80% hit rate and 25% crit rate.  We can see that average damage = (10+15+0+10+10)/5 = 45/5 = 9.  Using the code I see, AvgDirectDamage = AvgHit*(HitChance-CritChance)+(AvgCrit*CritChance) = 10*(.8-.25)+(15*.25) = 5.5+3.75 = 9.25.

Mar 12, 2010 at 4:07 PM

20% crit rate, not 25%. Fixing that in your calculation shows the same result as AvgDirectDamage().

Mar 12, 2010 at 4:22 PM

Correct me if I'm wrong, but I believe that's the difference between a 1-roll and 2-roll system.  For spells, you have to hit to crit, right?  So the crit rate is only applied to the 4 casts that actually hit, in the example above.  In the case of melee, you are absolutely correct.


Mar 12, 2010 at 5:33 PM

I have recently seen added to DrDamage the option to select the 2 roll system for casters.  Unless Blizz has made some changes, the standard for casters has been a 1 roll system for as long as I have known.  Some of those misses could have been crits.

Mar 12, 2010 at 6:18 PM

Well that's an important piece of information to get straight!  This page says it's a 2 roll system.  Can anybody show it is wrong?

Mar 12, 2010 at 9:55 PM

Casters had a 2 roll system for as long as I know.

Mar 12, 2010 at 10:49 PM

Yup - its been a 2 roll system from the start.

Mar 13, 2010 at 11:39 AM

It's 2 roll indeed, I was wrong. Posting while talking to a customer ftl :)

Mar 15, 2010 at 8:43 AM

Ok I'm having a lot of trouble figuring out Conflagrate + Firestone.  Maybe if I post the numbers here one of you can figure out how to calculate them.  Here's a scenario:

  • Without talents, buffs or debuffs, Immolate ticks 5 times for 695.6 each.
  • With talents: 15% Emberstorm + 30% Improved Immolate + 6% Aftermath = 51% => 1050.3 ticks.

Without Firestone, Conflagrate's direct portion hits for 1050.3 * 5 * .6 = 3150.9, as we would expect.  HOWEVER, with Firestone the direct portion hits for 3177-3178, and I cannot figure out how to calculate that.  Can anyone offer some insight?  I looked over the original warlock code & DrDamage code, but it was not immediately apparent to me how it's being calculated there.

Mar 15, 2010 at 11:32 AM

The formula DrDamage uses is:

(695.6 * 1.51 [Emberstorm + Improved Immolate + Aftermath]) * (1.01 [Spellstone] - 0.0015 [Emberstorm again]) * 5 * 0.6 = 3177,85

Mar 17, 2010 at 2:01 AM

Sorry I forgot to respond to that last post, Maleficus.  Thank you very much!  And WOW, Blizzard hates theorycrafters.

New question: given the frequency of a Corruption reset trigger (e.g. once per 3 seconds), the non-rolling duration of Corruption, and the % chance a trigger will actually work, I need a formula for Corruption's average rolling duration.  Can anybody help?

Mar 17, 2010 at 2:45 AM
Edited Mar 17, 2010 at 4:45 AM

Or, equivalently, a formula for how many times I'll have to cast it (on average) in an X minute fight :).


No wait - maybe that's not equivalent.  Ok I need a formula for the second one, not the first.  For how many times I'll be casting it, on average.


Oh yeah, yeah, it's equivalent.  :)


Mar 17, 2010 at 9:27 AM

That depends on whether the proc-chance is per tick or per cast.

If its per tick, I could think of the following (pseudo-code follows):

Assume, you have the following variables initialized:

float initial_duration = [Duration of the Corruption spell]
float trigger_freq = [Frequency of the reset trigger]
float proc_chance = [Chance of the trigger]
float fight_duration = [Maximum duration of the fight] 

You could try the following:


completeduration = initialduration;
for (int i = triggerfreq; i < completeduration; i += triggerfreq) {
    remaining = completeduration - i;
    would_add_duration = initialduration - remaining;
    completeduration += would_add_duration * procchance;



float complete_duration = initial_duration;

for (int i = 0; i < complete_duration && i < fight_duration; i += trigger_freq) {
    float time_remaining = complete_duration - i;
    float would_add_duration = initial_duration - time_remaining;
    complete_duration +=proc_chance * would_add_duration;

I cannot think of a formula for now, as the loop condition changes within the loop, but someone might have a better idea...
Oh, btw, if you implement it like this, you would like to start the loop at 'trigger_freq' instead of 0, as a proc on i=0 would have absolutely no effect.
(Re-read the piece of code a couple of times and it still makes sense to me, so I just submit this reply - However I just got up, so forgive any cerebral blackouts) ;-)

Mar 17, 2010 at 5:10 PM

I got excited thinking you solved it, but that can't be true.  Your loop would predict infinite duration for any proc_chance >= trigger_freq / (initial_duration - trigger_freq), since at that point it will be adding at least trigger_freq every time through the loop.  Sample values for those could be 3 / (12 - 3) = .33.  That would mean only 2 points in Everlasting Affliction would be more than enough to guarantee 100% uptime, which is obviously not true.  The only way to guarantee that is with proc_chance = 100%.

Mar 17, 2010 at 9:27 PM

I have very limited knowledge about Warlocks so I'm not really sure what you're talking about, but if you explain more in detail what you're trying to model I can help you with the math.

Mar 17, 2010 at 9:49 PM

Corruption lasts D seconds. (D for Duration)

Every T seconds it has a chance of P to be reset to D seconds. (T for trigger, P for probability)

How long will the effect end up lasting, on average? To put it another way, how long until it goes a full D seconds without being reset?

Given those rules it's clear that if P is 0, the answer is D. If P is 1 and T <= D, the answer is infinity.

Interesting to note is that even if T > D it still has a chance to trigger a single reset, since the first trigger may occur anywhere from 0-T seconds after the effect starts.

It's actually a simplifying assumption that the trigger will occur exactly T second apart.  In reality it will *average* T seconds apart, so if you care to tackle that problem be my guest!  However, you'd then have to know what distribution it follows, and I cannot give you that information.

Mar 17, 2010 at 10:12 PM

I believe EA procs per tick for channeled spells Drain Life and Drain Soul (source), but per cast for Haunt and Shadow Bolt.  I will try to test this tonight if I get a chance.  Also, worth noting that EA will wait to reset Corruption's duration until the next tick, thereby not robbing you of DPS.  It will never reset mid-tick.  (Source) You may know all of this already. ;)

As to Maleficus's example, I think infinite duration is actually correct for that particular view of the model. 

Each time you have the chance to proc (per cast of Haunt, for example), the model should effectively add corruption_duration * proc_chance to the existing corruption.  So, if you have 3 ranks of EA (60%), each proc opportunity (Haunt cast) should add 10.8 seconds to Corruption's duration -- 60% of Procs, over time, will add 18 seconds; thus over time you gain an average of 10.8 seconds.  Since Haunt is being re-cast every cooldown (9-10 seconds or so, including casting time), which is less than added duration, Corruption should never fall off from the model.  Granted, this doesn't factor in Haunt travel time, mistimed casting, etc.

On balance, this should work out to be true, in the same way that one models crit damage as an overall damage boost per cast (i.e. average damage * odds of not critting + average damage * odds of critting * crit multiplier = average overall damage).  Consequently, even one rank of EA would be enough to kick Corruption into essentially infinite uptime, as far as that version of the model is concerned.

The only thing worrying me is the whole additive chance/probability approach vs. subtractive (i.e. a 20% chance to proc means an 80% chance to not proc).  I have a sneaking suspicion that this is more important...


Mar 17, 2010 at 10:31 PM

Shame to me. However, I discussed the topic with two colleagues (one of them promoted in Maths) and they both came to the same result ^^

But of course you're right. And I think I see the problem: You cannot add "proc_chance * would_add_duration" in every loop, but you'll have to consider, that it may have procced before.

Given an initial_duration of 10, trigger_freq of 3 and possibility of 50, the correct durations should be as follows:

t0 (no trigger so far) -> 10 seconds
t0 + 3s (first trigger) -> 10 seconds + (3 seconds * proc_chance) -> 11.5 seconds. Up to  here, the algorithm from above is perfect :) However:
t0 + 6s (2nd trigger) -> the chance to add 6 seconds is only 25% (no proc at t0+3), and there is a 25% chance to add 3 seconds (procced at t0). The chance, that it doesn't proc is still 50%.
                                   So, the duration after this proc would be 11.5 seconds + 9*0.25 = 13.75 seconds
t0 + 9s (3rd trigger) -> there is a 12.5% chance to add 9 seconds (if no proc has been there before), a 12.5% chance to add 6 seconds (if the 2nd proc succeeded while the 1st one didn't),                                                        another 12.5% chance to add 6 seconds (if the 1st AND the 2nd proc succeeded), and a 12.5% chance to add 3 seconds (if the 1st proc succeeded, while the 2nd one didn't).
                                   So, the duration after this proc would be 13.75 seconds + 9*0.125 + 2*6*0.125 + 3*0.125 = 16.75 seconds
t0 + 12s (4th trigger) -> We have a chance to add 9 seconds (22 instead of 13, if only the 1st succeeded), a chance to add 6 seconds (22 instead of 16, if either only the 2nd or both the 1st AND
                                   the 2nd chance procced), a chance to add 3 seconds (22 instead of 19, if the 3rd succeeded, independently of the two chances before that).
                                   So, the duration after this proc would be 16.75 seconds + 9*0.0625 + 2*6*0.0625 + 4*3*0.0625 = 17.5 seconds


f(0) = 10
f(1) = 11.5 =   f(0) + 1.5
f(2) = 13.75 = f(1) + 2.25
f(3) = 16.75 = f(2) + 3
f(4) = 17.5 =   f(3) + 0.75

Weird... I think, I'll have to leave the numbers alone for a night or two, probably tomorrow will be a better day to solve things like that *rolleyes*
I think, it'd be easier to implement than trying to solve this in an editor. ;-) 

Mar 17, 2010 at 11:12 PM

McC - Thanks for the info about drain soul.  As for the rolling corruption problem, I'm afraid I don't really follow what you're saying :(.  At any rate, I know that Meleficus' loop does not give me the answer I need.  In your example, it only takes one Haunt non-proc to make Corruption's length non-infinite, therefore in that example, given the 40% chance of a non-proc, the average length of Corruption is clearly not inifinity.

Maleficus - good luck tomorrow!

For anyone working on the problem, here is some Java code that estimates the answer, to check your work against.  At least, I think this estimates the answer!

public class CorruptionDurationCalc {

    public static void main(String[] args) {

	double procRate = .4;
	double triggerPeriod = 3;
	double duration = 12;
	int numTests = 100000;

	double totalUptime = 0;
	for (int i = 0; i < numTests; ++i) {
	    double durationRemaining = duration;
	    double timeAdvance = Math.random() * triggerPeriod;
	    while (durationRemaining >= timeAdvance) {
		totalUptime += timeAdvance;
		if (Math.random() < procRate) {
		    durationRemaining = duration;
		} else {
		    durationRemaining -= timeAdvance;
		timeAdvance = triggerPeriod;
	    totalUptime += durationRemaining;

	System.out.printf("experimental duration = %f\n", totalUptime
		/ numTests);

Mar 17, 2010 at 11:14 PM
Edited Mar 17, 2010 at 11:19 PM

There might be a more elegant way to solve this, but here is the closed form solution. There are some divisions by P in the process so this'll only hold for 0 < P < 1. For edge cases you'll need special (but trivial) alternative.

I'm assuming that the trigger occurs every T seconds, but not at time=0.

Let N = D/T be max duration in terms of trigger interval. Let E(i) be expected duration of corruption if it currently has i trigger intervals left on the counter and we're at the point where we have a trigger. Then we have:

E(i) = T + P * E(N-1) + (1 - P) * E(i-1), for i > 0, i < N
E(0) = 0
E(N) = T + E(N-1)

We solve this recurrence relation:

Let K := T + P * E(N-1)

Then we have

E(0) = 0
E(i) = K + (1 - P) * E(i-1)

First we solve the homogeneous part

E(i) = (1 - P) * E(i-1)

for which we have (1 - P)^i.

Now we need a particular solution, for which we'll use method of undetermined coefficients.

The solution will have the form E(i) = A * (1 - P)^i + B

This gives us:

E(0) = A + B = 0
E(1) = A * (1 - P) + B = K

B = -A
A * (1 - P) - A = K

- A * P = K
A = -K/P
B = K/P

So this gives us the solution to recurrence:

E(i) = K/P * (1 - (1 - P)^i)

The recurrence only holds up to N-1. First we need to eliminate K:

E(N-1) = K/P * (1 - (1 - P)^(N-1))

K = T + P * E(N-1)
E(N-1) = (K - T) / P

(K - T) / P = K/P * (1 - (1 - P)^(N-1))
T = K * (1 - P)^(N-1)

K = T / (1 - P)^(N-1)

This gives

E(N-1) = (T / (1 - P)^(N-1))/P * (1 - (1 - P)^(N-1))

Let R := (1 - P)^(N-1)

Then E(N-1) = T*(1 - R)/(R*P)


E(N) = T + E(N-1)
     = T + T*(1 - R)/(R*P)
     = T * (1 + (1 - R)/(R*P))
     = T * (1 - R*(1 - P))/(R*P)

Mar 17, 2010 at 11:35 PM
Edited Mar 17, 2010 at 11:36 PM

That math is definitely over my head.  I don't understand the recurrance you set up, and I *certainly* don't remember how to solve recurances, so I'm afraid I can't help you check your work.  However, my RNG-based simulator comes up with wildly different answers than your equation.  For a couple examples:

With P=.4, T=3, D=12: my code gives 49ish and yours gives 30.222222.

With P=.8, T=3, D=12: my code gives 2300ish and yours gives 468.0.

So - since I'm unable to look for where you may have gone wrong - can you find where I may have?


Mar 17, 2010 at 11:37 PM

Actually I might have missed some subtlety. Can the last tick of Corruption, when it would normally expire also extend itself? If so then I'll have to redo the equations.

Mar 17, 2010 at 11:39 PM

What you're doing in that simulation is you choose a random time between 0 and T, this means on average it is T/2 with a uniform distribution on [0, T]. Is that intended?

Mar 17, 2010 at 11:43 PM

Corruption can never extend itself, and I don't know if a trigger occurring at EXACTLY the same time as the last tick would extend it - but on average that happens 0% of the time anyway :).

My simulation chooses a random number [0, T) for the *first* trigger, then once it gets to the bottom of the first loop resets it to the full T.  Why [0, T) instead of [0, T]?  Because that's easy to code.


Mar 17, 2010 at 11:53 PM
Edited Mar 17, 2010 at 11:57 PM

I think you're going in an interesting direction, Maleficus, but I'm not sure about the conclusion.

Disclaimer: I have no idea if I'm even on the right track with this.  I haven't logic-checked it, just math-checked it. ;)

t time
0 0 18.0
3 1.5 16.5
6 3.0 15.0
9 4.5 13.5
12 6 12.0
15 7.5 10.5
18 9.0 9.0
21 10.5 7.5
24 12.0 6.0
27 13.5 4.5
30 15.0 3.0
33 16.5 1.5
34.5 -- 0.0

Consider the table to the left. Initial Duration is 18 seconds (i.e. Corruption's length), Frequency of the trigger event is 3 seconds, and Proc Chance is 50%. Each frequency interval has a proc_chance of adding proc_chance * elapsed_time to the remaining time. 

The formula driving this (from Excel) is f(t) = init_dur - t + proc_chance*frequency*floor(t/freq) floor(t/freq) = num_procs for a given value of t.  I don't know, off hand, how one inverts this to get it purely in terms of t, unfortunately, due to the presence of the floor operation. 

What you want to do is set f(t) = 0 and solve the equation.


  0 = 18 - t + 0.5*3*floor(t/3)
-18 = -t + 1.5*floor(t/3)

It may be possible to deconstruct floor().  See the final formula in this Wikipedia article.

Mar 18, 2010 at 12:07 AM
Edited Mar 18, 2010 at 12:07 AM

Here is a revised version of the code, that takes into account McC's info that it will actually reset the duration of corruption starting from the next tick:

public class CorruptionDurationCalc {

    public static void main(String[] args) {

	double P = .5;
	double T = 3;
	double D = 16;
	int numTests = 100000;

	double totalUptime = 0;
	double tickLen = D / 6;
	for (int i = 0; i < numTests; ++i) {
	    double durationSoFar = 0;
	    double durationRemaining = D;
	    double timeAdvance = Math.random() * T;
	    while (durationRemaining >= timeAdvance) {
		durationSoFar += timeAdvance;
		if (Math.random() < P) {
		    double tillNextTick = tickLen - durationSoFar % tickLen;
		    durationRemaining = D + tillNextTick;
		} else {
		    durationRemaining -= timeAdvance;
		timeAdvance = T;
	    durationSoFar += durationRemaining;
	    totalUptime += durationSoFar;

	System.out.printf("experimental duration = %f\n", totalUptime
		/ numTests);
	double N = D / T;
	double R = Math.pow(1 - P, N - 1);
	double En = T * (1 - R * (1 - P)) / (R * P);
	System.out.printf("closed-form duration  = %f\n", En);

And here are revised numbers: P=.4, T=3, D=12 => 50ish.  P=.8, T=3, D=12 => 2300ish.

And for McC's latest post, P=.5, T=3, D=16 => 210ish.  I'm not following your logic exactly, but it looks like you thought it would be 34.5 in that case.

Mar 18, 2010 at 1:56 AM
Edited Mar 18, 2010 at 1:57 AM

I just saw the comment about refresh delaying until next tick. This simplifies things a bit. Basically the interesting value is the chance that a proc will happen in duration of one corruption tick.

For this purpose I'll rephrase the variables I was using. Let N be max number of corruption ticks. Let E(i) be expected duration of corruption in terms of ticks when we have i ticks left on the counter and we're at the point where the tick just happened.

Let S be the chance that a proc happens in duration of one corruption tick. If triggers happen on average every T seconds and TC is corruption tick interval, you can compute this as S = 1 - (1 - P) ^ (TC / T), alternatively you can go with Poisson model if you preferred depending on what distribution of triggers you want to model.

Then we have

E(i) = 1 + S * E(N) + (1 - S) * E(i-1), for i > 0,
E(0) = 0

The system is almost the same as above and we solve it similarly:

Let K := 1 + S * E(N)

Then we have

E(0) = 0
E(i) = K + (1 - S) * E(i-1)

First we solve the homogeneous part

E(i) = (1 - S) * E(i-1)

for which we have (1 - S)^i.

Now we need a particular solution, for which we'll use method of undetermined coefficients.

The solution will have the form E(i) = A * (1 - S)^i + B

This gives us:

E(0) = A + B = 0
E(1) = A * (1 - S) + B = K

B = -A
A * (1 - S) - A = K

- A * S = K
A = -K/S
B = K/S

So this gives us the solution to recurrence:

E(i) = K/S * (1 - (1 - S)^i)

This recurrence holds all the way to N.  We eliminate K:

E(N) = K/S * (1 - (1 - S)^N)

K = 1 + S * E(N)
E(N) = (K - 1) / S

(K - 1) / S = K/S * (1 - (1 - S)^N)
1 = K * (1 - S)^N

K = 1 / (1 - S)^N

This gives

E(N) = (1 / (1 - S)^N)/S * (1 - (1 - S)^N)

Let R := (1 - S)^N

Then E(N) = (1 - R) / (R*S)

Also R = (1 - P) ^ (N*TC / T) = (1 - P) ^ (D/T)

So for P=.4, T=3, D=12 we get S = 1 - (1 - P) ^ (TC / T) = 1 - 0.6 = 0.4. This gives R = 0.1296 and E(N) = 16.79 ticks or 50.37 sec.

For P=.8, T=3, D=12 we have S = 0.8, R = 0.0016, E(N) = 780 ticks or 2340 sec.

I think this matches the simulation quite well.

Mar 18, 2010 at 2:16 AM

I haven't tried to parse through all of the new formulae, but I'm happy to be incorrect in any part of it, if there seems to be a promising lead. ;)

I'm a little surprised that I would get 34.5 rather than something several orders of magnitude larger, but my calculations were all fast-and-loose in Excel.  I'll parse through Kavan's stuff later on and see where mine and his diverge.

Sounds like everything's on the right track, though.

Mar 18, 2010 at 2:33 AM

Kavan - This is getting close!  One problem is that TC is not 3, it is D/6 (it gets hasted right along with corruption's duration).  When I set D to 18 (unhasted corruption), your solution works perfectly!  As soon as I set it lower, though, the numbers are off.

Huh - but if I just hard code in 3 for the two places TC shows up, it works even with hasted corruption!  Lol.  Sweet.  Not sure why it would work when hard-coding 3 but not hard-coding any other number.

Now your number is always just a shade off.  Close enough for me - we're talking 18 instead of 17.5, or for a different value of D, 32.4 instead of 32.6.  Thanks a million!

Mar 18, 2010 at 3:39 AM

Oh I see. Well then for P=.4, T=3, D=12 you would have S = 1 - (1 - P) ^ (TC / T) = 0.2886, R remains the same R = 0.1296 and E(N) = 23.27 ticks or 46.54 sec.

Now the question is why does this differ from simulation. Simulation uses a very specific distribution of triggers. It has a trigger in two consecutive dot intervals and then one without. That nonuniformity is what skews the numbers I believe.

I guess the better question is why does using a hardcoded TC=3 better approximate it. I think that's very specific for the case T=3. If you use some other T that probably won't be the case.

Mar 18, 2010 at 3:59 AM

If we redo the whole thing for the specific distribution you're using we get this:

Let E(t,p) be expected duration of corruption in terms of seconds when we have t seconds left on the counter and we're at the point where the tick just happened and there is p seconds until next trigger. What we're looking for then is E(D, offset).

TC = D/6

E(t, p) = t, for t < TC and p > t
E(t, p) = TC + P * E(D, p + T - TC) + (1 - P) * E(t - TC, p + T - TC), for p < TC (assuming T > TC)
E(t, p) = TC + E(t - TC, p - TC), for p > TC

Now let's try to solve this for our particular example.

D = 12
TC = 2
T = 3
offset = 0.2

E(12, 0.2) = 2 + P * E(12, 1.2) + (1 - P) * E(10, 1.2)
E(12, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * E(10, 2.2)
E(12, 2.2) = 2 + E(10, 0.2)

E(10, 0.2) = 2 + P * E(12, 1.2) + (1 - P) * E(8, 1.2)
E(10, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * E(8, 2.2)
E(10, 2.2) = 2 + E(8, 0.2)

E(8, 0.2) = 2 + P * E(12, 1.2) + (1 - P) * E(6, 1.2)
E(8, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * E(6, 2.2)
E(8, 2.2) = 2 + E(6, 0.2)

E(6, 0.2) = 2 + P * E(12, 1.2) + (1 - P) * E(4, 1.2)
E(6, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * E(4, 2.2)
E(6, 2.2) = 2 + E(4, 0.2)

E(4, 0.2) = 2 + P * E(12, 1.2) + (1 - P) * E(2, 1.2)
E(4, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * E(2, 2.2)
E(4, 2.2) = 2 + E(2, 0.2)

E(2, 0.2) = 2 + P * E(12, 1.2)
E(2, 1.2) = 2 + P * E(12, 2.2)
E(2, 2.2) = 2

We solve this and get

E(12, 0.2) = 2 + P * E(12, 1.2) + (1 - P) *(2 + P * E(12, 2.2) + (1 - P) * (2 + 2 + P * E(12, 1.2) + (1 - P) * (2 + P * E(12, 2.2) + (1 - P) * 2)))
E(12, 1.2) = 2 + P * E(12, 2.2) + (1 - P) * (2 + 2 + P * E(12, 1.2) + (1 - P) * (2 + P * E(12, 2.2) + (1 - P) * (4 + P * E(12, 1.2))))
E(12, 2.2) = 2 + 2 + P * E(12, 1.2) + (1 - P) * (2 + P * E(12, 2.2) + (1 - P) * (2 + 2 + P * E(12, 1.2) + (1 - P) * (2 + P * E(12, 2.2))))

E(12, 0.2) = (2*P^12-20*P^11+92*P^10-256*P^9+476*P^8-622*P^7+596*P^6-448*P^5+290*P^4-162*P^3+70*P^2-24*P+12)/(P^8-6*P^7+16*P^6-24*P^5+22*P^4-14*P^3+8*P^2-4*P+1)

which for P = 0.4 gives 49.07635092227576 and for P = 0.8 gives 2338.502719692604

Now the problem is I have no idea how to get a closed form solution for arbitrary  D, T and offset. Probably a better question is if this particular distribution is representative of triggers in real life situations. If you can assume that triggers are more uniform then my previous model should be good enough most likely.

Mar 18, 2010 at 4:15 AM
Edited Mar 18, 2010 at 4:16 AM

So I see.  I guess I'll un-hard-code the 3.  After experimenting a bit I find your equation is quite good for lower values of P, but begins to diverge more at larger values.  Some examples (results given as simulation vs. equation):

  • P=.2, T=6, D=12: 16 vs 15.6
  • P=.2, T=6, D=12: 25 vs 22.7
  • P=.6, T=6, D=12: 50 vs 39.8
  • P=.8, T=6, D=12: 178 vs 115.6
  • P=.2, T=4, D=16: 28 vs 27.8
  • P=.4, T=4, D=16: 66 vs 62.1
  • P=.6, T=4, D=16: 253 vs 222.0
  • P=.8, T=4, D=16: 3121 vs 2528.9
  • P=.2, T=3, D=8: 11 vs 11.5
  • P=.4, T=3, D=8: 18 vs 19.1
  • P=.6, T=3, D=8: 33 vs 41.9
  • P=.8, T=3, D=8: 116 vs 188.1

I'm very grateful for the time you've put in, so if you feel done with the exercise I'll just use what you've already come up with.  Thanks!

[Edit]: Was writing this up as you wrote your last post, so it pertains to the one above it.

Mar 18, 2010 at 4:22 AM
Edited Mar 18, 2010 at 4:24 AM

I can try to answer your last question if you define "distribution" and "uniform" in regard to triggers.  Also, what are you defining as "offset"?

[Edit]: Oh now I understand "offset".  Can we say it's T/2 to come up with the average case?  And would that help make things any easier?  Lol.

Mar 18, 2010 at 4:47 AM

For the specific case above with D=12, T=3 the offset doesn't matter, because D and T are "synced" together. It doesn't simplify the problem though if you assume it is T/2. By uniformity I mean if overall chance of trigger inside dot interval is 2/3. A uniform distribution would be when any particular interval has 2/3 chance of the trigger being in it. Nonuniform would be the case used in simulation where you have a perfect pattern. So showing as a stream of probability of a trigger in dot interval, then 2/3, 2/3, 2/3, 2/3, 2/3, 2/3, ... would be uniform; 1, 1, 0, 1, 1, 0, 1, 1, 0,... would not be. In practice this'll mean the more off-sync it is with corruption ticks the more it'll fit the uniformity.

Mar 18, 2010 at 4:49 AM

One thing you can do for experiment is modify your simulation so that you set timeAdvance = T * (0.8 + 0.4 * Math.random()); in every loop and see what effect unsyncing has.

Mar 18, 2010 at 5:24 AM

Your suggestion to try setting timeAdvance to random values is a great one!  I used timeAdvance = T + T * (2 * J * Math.random() - J),  (J stands for jitter) and here's an example run with 10,000,000 tests each:

  • P=0.600000, T=4.000000, D=10.000000, J=0.000000: 37.795414
  • P=0.600000, T=4.000000, D=10.000000, J=0.200000: 40.159212
  • P=0.600000, T=4.000000, D=10.000000, J=0.400000: 42.490884
  • P=0.600000, T=4.000000, D=10.000000, J=0.600000: 39.902384
  • P=0.600000, T=4.000000, D=10.000000, J=0.800000: 37.080535
  • closed-form duration  = 46.645842

And if I run the exact same thing again I get pretty much the same results (as one might expect at 10,000,000 tests each):

  • P=0.600000, T=4.000000, D=10.000000, J=0.000000: 37.785414
  • P=0.600000, T=4.000000, D=10.000000, J=0.200000: 40.162506
  • P=0.600000, T=4.000000, D=10.000000, J=0.400000: 42.486532
  • P=0.600000, T=4.000000, D=10.000000, J=0.600000: 39.902318
  • P=0.600000, T=4.000000, D=10.000000, J=0.800000: 37.067252
  • closed-form duration  = 46.645842

As you can see, J has an odd effect on the result.

Mar 18, 2010 at 9:23 AM

I'm a bit tired to try and follow the code logically to see exactly what you are accounting for but i figured i'd pass on info about corruption to make sure everything is accounted for that can be.

Corruption is affected by haste(when glyphed), crit (with talent to be critable), spell power, and dmg % boost (for example tier 10 4 piece, or curse of elements and equivilent from boomchicken/unholy dk). without the glyph or talent, the only things affecting corruption is spell power and spell %, but the same rules apply that are mentioned next in thhe paragraph for each of them. Big problem with modeling corruption though is that when corruption refreshes automatically, only spell power and haste (when glyphed still) are factored in. The crit and dmg % from the very initial cast will stay exactly the same throughout the life of the refreshing corruption. This also applies to death embrace talent which increases dmg when a mob's health is below 35%. to take advantage of that talent on corruption, you need to cast a brand new corruption so the dmg % actually gets applied, since it doesn't refresh dmg % or crit each time. So that can complicate things a bit dmg wise when factoring in item values, talents, and buffs, because certian things need to be factored in at certain times only. Spell power is the only natural stat that affects corruption and recalculates automatically on every refresh. The other 3 have special circumstances on being recalculated or staying the same through the entire duration.

The refreshing corruption is one of the more complicated things they could have added, and even took them a cuple tries to get it right since the initial way was putting locks over 10k almost automatically when not even using the best gear. 

Corruption refresh is not a chance on proc, as its 100% refresh chance based on 4 abilities when they actually do the dmg, but the refresh will not apply until after the next tic of corruption causes dmg. It will refresh 100% of the time when a haunt or shadow bolt lands, but also keep in mind there is a slight delay in it landing from being cast since it has a little travel time from the player to the mob like an arrow. Drain Soul and Drain life can also cause it to refresh 100% of the time on each damaging tick.

Tommorow i'll take a look at the code and see if i can follow logically what is being done to help out. i'm not very experienced in C but i do a lot of vb and shell scripting with work, so i should be able to eventually follow what you guys are doing:)  Either way, i should be able to help with warlock info at the very least.

One of the biggest problems with the old version was that even though haste was stat valued well, an item with haste on it was almost always given negative item value automatically. For example, i just did a optimize on an old version where 15 haste enchant was giving 5dps, but the 20 haste enchant was -10dps. which logically makes no sense. Even if that extra 5 haste meant nothing to your char in way of being able to get another cast in, it would be valued negatively. It would just have no additional value over the 15 haste enchant. The reason i bring it up to make sure its checked is because obviously right now or affliction haste is huge do to it affecting corruption.

Mar 18, 2010 at 12:35 PM

Thanks for all the info/input, asteru.  When I get to that point, I was planning on using this info to determine the damage Corruption does.  It's almost the same as what you just said, except that %damage debuffs on the target are updated throughout corruption's span (%damage buffs on yourself, such as Tricks of the Trade, still stick through the entire duration).

As for the 100% chance to refresh when Haunt or Shadow Bolt do damage, that's only true when you have all 5 points invested in Everlasting Affliction.  Each point gives you a 20% chance.  Also, miss chance is factored into P when applying the formulas above.

Again, thanks for the input, and I do hope you get the chance to look over code!  The more critical eyes, the better.

Mar 18, 2010 at 5:37 PM

You are absolutely correct.

Note to self: don't post when half asleep lol.

Mar 18, 2010 at 7:37 PM

Kavan - in your solution you define S = 1 - (1 - P) ^ (TC / T), which makes sense to me when T < TC.  But when T > TC, it seems to me like it should be P * TC / T.  According to my simulations, I'm wrong, that makes things worse, but I'm curious to know why.

Explanation: when T<TC there can be 2 triggers during the same tick, but only 1 can count, so you have to compute the chance of ZERO successfull triggers and take the compliment.  However, every successfull trigger counts when T >=TC, so my intuition tells me to just take the chance of a trigger during 1 tick and mulitply it by P.  Why am I wrong?

Mar 18, 2010 at 7:45 PM
Even if it may be too late right now, I tried a totally different (recursive) approach. C-Code follows: float calc(float baselen, float proc_chance, float trig_freq, float curlen, float now) { if (now >= max_dur) return max_dur; if (now > curlen) return curlen; float res1 = calc(baselen,proc_chance,trig_freq,now+baselen,now+trig_freq); float res2 = calc(baselen,proc_chance,trig_freq,curlen,now+trig_freq); float res = res1*proc_chance+res2*(1-proc_chance); return res; } const float base_dur = 10.0f; const float proc_chance = 0.6f; const float trig_freq = 3.0f; calc(base_dur, proc_chance, trig_freq, base_dur, 0.0f + trig_freq); The 1st three parameters are constant. the curlen is the actual duration of the spell, now is the current timestamp. It's pretty hard to explain, but I hope, it's selfexplanatory enough. If you have questions, just ask. If you no longer care, also ok for me ;-) This algorithm is terribly slow as it's written above. I used a pretty simple caching algorithm, making it really fast. If you're interested in the original sourcecode, give me a hint.
Mar 18, 2010 at 9:11 PM

Well - I started running your solution, ran Oculus, and it's still running!  What did you set for max_dur?

Mar 18, 2010 at 11:56 PM

First of all sorry for the awful indentation in my last post, but those code-formatting gimmicks don't work with Firefox (at least not in the linux version).
Yeah, I know the original algorithm is damn slow with values for max_dur > 200.0f.

However, I tested with 300.0f, which is the default setting in rawr, using the caching algorithm I mentioned above.
The cache algorithm is pretty fast, as lots of iterations try to calculate the same, however in different iteration depths:

#include <stdio.h>
#include <stdlib.h>
#include <map>

const float max_dur = 300.0f;

typedef std::pair<float,float> cache_key_t;
typedef std::map<cache_key_t,float> cache_t;
cache_t cache;

float calc(float max_dur, float baselen, float proc_chance, float trig_freq, float curlen, float now)
     cache_key_t cache_key = std::make_pair(now,curlen);
     cache_t::iterator cr = cache.find(cache_key);
     if (cr != cache.end())
         return cr->second;

     if (now > curlen)
         return curlen;
     if (now >= max_dur)
         return max_dur;

     float res1 = calc(max_dur, baselen, proc_chance, trig_freq, now + baselen, now + trig_freq);
     float res2 = calc(max_dur, baselen, proc_chance, trig_freq, curlen, now + trig_freq);
     float res = res1 * proc_chance + res2 * (1 - proc_chance);

     cache.insert(std::make_pair(cache_key, res));

     return res;

const float max_dur = 300.0f;
const float base_dur = 10.0f;
const float proc_chance = 0.6f;
const float trig_freq = 3.0f;

calc(base_dur, proc_chance, trig_freq, base_dur, 0.0f + trig_freq);
Mar 19, 2010 at 2:21 AM

I've run Maleficus' code, and it seems about as accurate as Kavan's formula.  It takes longer to run, but I really like the fact it considers the fight length to be maximum duration, since that strongly impacts the result at high values of P and is closer to reality.  Can anyone (Kavan?) solve Maleficus' recurrence?  If not, I'll work on making it run as fast as I can in its recursive form.


Mar 19, 2010 at 2:48 AM

Maleficus, that looks like a runtime solution for the static interval trigger (the one I showed closed form solution above for D = 12,TC = 2,T = 3,offset = 0.2). If it's fast enough this should work well given that you want to model this particular trigger distribution.

As for the S = 1 - (1 - P) ^ (TC / T). I'm not sure if I have a good explanation for why P * TC / T gives worse results. At the core of the problem here is that we're trying to approximate a discrete distribution with a uniform continous distribution. If we assume that chance of proc only depends on time interval (i.e. independent of actual time position, i.e. uniform), then the following must hold:

Let P(t) be chance that a proc happens in time interval t. If we have time intervals t1 and t2, then P(t1 + t2) has to be 1 - (1 - P(t1))*(1 - P(t2)). Problem with P * TC / T is that it doesn't satisfy that requirement. With some deduction you can get that instead the following has to hold: P(k * t) = 1 - (1 - P(t))^k. So if you know P at a particular time interval that gives you value for all time intervals. If not then either it won't be uniform or you'll break some base probability properties.

Mar 20, 2010 at 1:05 PM
Edited Mar 21, 2010 at 1:30 AM

Concerning runtime, the recursive form is inacceptable in most cases, because it tries to walk a tree with 2^(max_dur / trig_freq) nodes.
In fact the number of nodes is limited, as not every proc succeeds and as most nodes calculate the same result, you can speed it up quite a lot if using a simple cache.

One of the bad things is, that the real runtime cost cannot really be forecast (or at least I did not try to find out). Another thing is the size of the cache, which can grow very quickly.

I changed it to an linear algorithm with ((max_dur / trig_freq) + 1) * ((baselen / trig_freq) + 1) iterations.
This is of course not as fast as your (Kavan) solution, which I think should run in O(1), but should be fast enough in every case. Its also using a small cache, but the cache size is limited to 2 * ((baselen / trig_freq) + 1).

Some statistics from the "real world":

D=12, T=3, fight length = 300
   Recursive solution: 781 function calls, 390 cache entries, 288 cache hits
   Iterative solution: 505 loops, 10 cache entries

D=12, T=3, fight length = 3000
   Recursive solution: 7981 function calls, 3990 cache entries, 2988 cache hits
   Iterative solution: 5005 loops, 10 cache entries

D=12, T=3, fight length = 30000
   Recursive solution: 79981 function calls, 39990 cache entries, 29988 cache hits
   Iterative solution: 50005 loops, 10 cache entries

D=12 T=1, fight length = 300
   Recursive solution: 7045 function calls, 3522 cache entries, 3212 cache hits
   Iterative solution: 3913 loops, 26 cache entries

D=12, T=6, fight length = 300
   Recursive solution: 195 function calls, 97 cache entries, 47 cache hits
   Iterative solution: 153 loops, 6 cache entries

D=12, T=7, fight length = 300
   Recursive solution: 85 function calls, 42 cache entries, 0 cache hits
   Iterative solution: 86 loops, 6 cache entries

D=12, T=8, fight length = 300
   Recursive solution: 59 function calls, 29 cache entries, 0 cache hits
   Iterative solution: 75 loops, 6 cache entries

As you can see, there is the slight possibility that the recursive solution runs faster than the iterative one. However, for most cases, the iterative way takes less iterations, it cannot produce a stack overflow and keeps the memory consumption very low.

But it still would be great to get this one running in O(1) :-)
Kavan FTW :D

[edited as Firefox (Linux) obviously eats every newline] -.-

Mar 20, 2010 at 10:42 PM

To the devs out there: Is there a way to do GetAverageCombinedUptimeCombinations for multiplicitive stats?

Mar 21, 2010 at 10:01 AM
Edited Mar 21, 2010 at 10:02 AM

It's possible, but it's not exposed in the api, I'll add some overloads for it. Can you tell me what specifically you're trying to do?

Mar 21, 2010 at 7:55 PM

I'm trying to handle haste trinkets/effects.  My plan is to take the output from a function like that, calc the cast time of each each spell under each combination, and average it together to get a more realistic average cast time.

Mar 21, 2010 at 9:42 PM

Most haste trinkets are haste rating based and haste rating is additive, not multiplicative, so be careful how you implement this.

Mar 22, 2010 at 12:06 AM

Yeah, I haven't quite figured it out yet.  I could use the additive functions get all the combinations of haste rating effects - and now I could use the multiplicitive function to get the combinations for the haste % effects (bloodlust, erradication & backdraft are the ones I know of off the top of my head).  But how do I get the combinations of the two of them together?

Mar 22, 2010 at 12:20 AM

You'll need special case logic for this, this is too specific to be in general api. Keep in mind that average combinations wasn't intended to be used for on use effects like bloodlust. It won't do any stacking or similar to position the on use effects, it'll just use them whenever cooldown is ready.

Mar 22, 2010 at 12:31 AM

Here is what I came up with.  I think I have the idea right:

WeightedStat[] finalUpStats
= new WeightedStat[ratings.Length * percentages.Length];
for (int p = percentages.Length, f = 0; --p >= 0; ) {
for (int r = ratings.Length; --r >= 0; ++f) {
finalUpStats[f]= new WeightedStat();
finalUpStats[f].Chance = percentages[p].Chance * ratings[r].Chance; finalUpStats[f].Value = (1 + percentages[p].Value) * (1 + StatConversion.GetHasteFromRating( ratings[r].Value + Stats.HasteRating, CharacterClass.Warlock)); } }
As for smarter utilization of on-use effects ... at some point I may make it smarter, but just this will be a big improvement for me right now.

Mar 22, 2010 at 2:07 AM

This isn't ideal, but it'll work as an approximation. Basically you're making an assumption that rating based and percentage based uptimes are independent which isn't the case.

Apr 4, 2010 at 7:08 AM

Does Conflagrate consume Immolate even when it misses?


Apr 6, 2010 at 1:43 AM

I don't think Conflag can miss or if it can i would assume it wouldn't consume the immolate because of the wording on the spell.  But in all honesty not 100% sure i have personally never had mine miss.  and for a while I was at about +10% hit which is 7-8% below optimal. 

Apr 7, 2010 at 6:36 PM
No conflagrate does not consume immolate when missed, I went streaking through SW bear back (black war bear, so quite literally) and with an empty glyph slot to test this on the dummies. conflagrate missed 3 times and immolate stayed on each time. Thanks for all the hard work, I love rawr on my druid and pally and look forward to using it for my lock!
Apr 8, 2010 at 2:21 AM

Excellent, thank you very much for your research!


Apr 9, 2010 at 3:47 AM

The new Warlock model is going live at the next release.  Please go easy on me!


Apr 9, 2010 at 9:23 AM

YAY! Has a release date been set yet? /so excited

Apr 9, 2010 at 1:15 PM

Awesome news!  Can't wait :)

Apr 9, 2010 at 3:02 PM

Good to hear!

Thanks for putting your free time into this!


Apr 9, 2010 at 6:33 PM

Thanks. I tried to build the latest SVN version and I have the problem that its only the "WarlockOld" model that is being loaded.

Apr 9, 2010 at 8:03 PM
Edited Apr 9, 2010 at 8:05 PM

Now just remember, "going live" does not mean "done".  It only means that all the features that were present in the old model are now also present in the new one (as far as I know).  There's still the issues of pets, the execute stage, and others that are unimplemented.  So don't be dissapointed by that!  I do expect it to give better results than the old model, though, so you can be excited about that part :).

Krendar - hmmmm.  I thought I took care of that, but apparently not.  This was my first experience with C# build configurations, so I'm not surprised.  I can't remember the screen very well and I'm not at home to look at it right now, but there is a drop down next to the green play button that has "Debug", "Release" and "Configure something something" in it.  Click on the configure one, uncheck the WarlockOld box and check the Warlock box.  Now press that play button and you should be good to go.  The WarlockOld model may not go away unless you delete it's .dll from your build folder.

Apr 9, 2010 at 9:54 PM

It appears that Configuration Manager isn't where the issue lies... it's the mixture of the Rawr.Warlock namespace with the Rawr.WarlockOld namespace in the Rawr.Warlock project.  Specifically, you'll find the WarlockOld namespace used in SpellPriorityForm.cs (and .Designer.cs) and SpellStatistics.cs.

Apr 10, 2010 at 1:28 AM
Edited Apr 10, 2010 at 1:29 AM

Nice, Thanks!

I ended up figuring how to build rawr from source (meh. express is terrible. that or I'm really out of touch with current source/compliers.) I'm currently running a build from 49228 checkin. It doesn't look like any of your more current checkins effect calculations, is that assumption true?

Also, would you say at this point it's pretty much okay to depend on the gear the optimizer chooses for Destruction except when it effects Pets? (2P T9 for instance?).

From what I've seen from my testing it matches pretty closely with what is expected. (Selected the T10 Warlock BiS gear, from elitistjerks) and the optimizer correctly selected the gear, and *almost* matched the gemming that the BiS gear has set. (and the reason it was almost might be a difference in the build, eg. Suppression or rotation that I didn't match perfectly.. they didn't say how they came up with the BiS list.)

I noticed with the Optimizer that it's pretty slow, verses some models and the old lock model.. is this due to the new calculation style? I ran the Optimizer at ~25% 50% and 75% and it came up with the same exact stats every time.. is Thoroughness actually used in the current model?

There were a few things I noticed, but I think I'll wait until release before I report them, in case I messed up my copy somehow. I'm hoping we'll see a new release soon with this new model in it.

Again @Xemnosyst, thanks a lot for all of your work, it's great having an active devoloper keeping an eye on us, and one that works with and is friendly with the community.

Apr 10, 2010 at 5:52 AM

Roncli - thanks for figuring that out.  Looks like Kavan did some work with the project files - probably tomorrow I'll check out if the issue still remains.

Bugmenot2 - thank you for that encouraging report!  I would not say it's OK to depend on my model for Destruction; it may be, but it's too early for me to declare that.  However, your report that it almost exactly matches other people's reports for BiS makes it sound much more likely!  You will definitely want to update your source, though.  Revision 49246 fixed a bug that basically ignored haste buffs (e.g. Wrath of Air Totem & Swift Retribution).  Unfortunately the file format changed since the revision you used, so you'll have to re-make your character.

The speed of the model is one of my concerns.  Not sure where exactly where that will fall on my priority list, because it is bearable, but I know there are several things that can be optimized and I will do that at some point.  As for thoroughness, that has nothing to do with individual models, so it should be functioning just fine.  I don't know anything about how it works, so I can't answer the question of why it gives you the same gear set at 25% as 100%.

Apr 10, 2010 at 6:57 AM

So now that you've caught up to the existing model and gone live...

Pets are priority one, right?


lack of pets makes Demo specs pretty much useless to run through Rawr, even when all talents are initialized. And to a lesser extent, it seems to me Destro depends more than a little on Machine Gun Imp and his crit rating.

Apr 11, 2010 at 4:17 AM

I wouldn't say they are my first priority.  I'm warming up to the idea of implementing them slowly, piece by piece - but not priority one.


Apr 11, 2010 at 5:17 AM


So what *is* your first priority?

Apr 11, 2010 at 8:23 PM

Pets are very important and they have been missing for forever it seems now.  I would think it would be a top priority.  At any rate, as usual, we will wait.  Xemnosyst has done an awesome job and devoted a lot of time to this project.  /Salute!  Didn't you say earlier that releases will not include Warlocks until pets are done? 

Apr 12, 2010 at 12:08 AM

I recall him saying from the begining that pets would not be a priority.  He even asked if I recall correctly, for help regarding this undertaking due to the amount of time/agony involved in implementing pets.

IMO its great to have them, however I am one to believe that they are (other than T9_2P, a set that will be used for a limited timeframe anyway) a predefined DPS value.  As our gear goes up, they go up in direct proportian.  (I wont say exactly, no, but should almost scale smoothly with gear.)  If we select gear based on personal DPS, reselect gear thats better, our pets will feel this increase.  To have them to show us total (player + pet) DPS, all good, however when selecting gear even as Demo, I cant see a scenario where I'd try to at any time select gear that would enhance my pets DPS specafically.

If im doing 6.5k with selected gear and my pet is doing 800 DPS.. If just fine to 'AssUMe' that if Im now doing 7.0k, my pet is doing ((7K/6.5K)*800).

Thanks again Xemnosyst, and all others involved in the project.  I'm very much so looking foreward to giving it a test run upon release.

Apr 12, 2010 at 1:54 AM

My only concern was that Astrylian said she would not release the warlock model until pets were done.  That is why I thought it was very important.  I would be more than happy to have it w/o pets.  I'm hoping this will be release whether pets are included or not. 

Apr 12, 2010 at 2:07 AM

Xemno's work will be in today's release.

Going forward, pets will be at the top of the priority list.

Apr 12, 2010 at 6:17 AM
JustAnotherToon wrote:

IMO its great to have them, however I am one to believe that they are (other than T9_2P, a set that will be used for a limited timeframe anyway) a predefined DPS value.  As our gear goes up, they go up in direct proportian.  (I wont say exactly, no, but should almost scale smoothly with gear.)  If we select gear based on personal DPS, reselect gear thats better, our pets will feel this increase.  To have them to show us total (player + pet) DPS, all good, however when selecting gear even as Demo, I cant see a scenario where I'd try to at any time select gear that would enhance my pets DPS specifically.


I agree with you there. But what about, say, comparing a demo spec to a destro spec? Pretty impossible without the pet info activated, other than by manually testing in game. And if you can't really afford to respec/regem to do that...

Or deciding if going demo hybrid is worth the loss of felguard...

I'm personally satisfied with Affliction, but I can't only think of myself here. Think of the children, man. The children! *tears*

Apr 13, 2010 at 6:51 AM

Demo lock here. I used the same set of equipment I had available in the last Rawr release (old Warlock).

Following Simcraft (and raid tonight reflects it as well), my pre-newlock profile got about 11k, my newlock profile gets 11.5k. And it told me to utilize my 4xT10 properly, where the old one told me to ignore 4xT10, stick with 2xT10 and stack SP instead.

So great work, you improved my DPS even if you seem to think your release is still broken. :)

I guess the point is... Even if it is broken, it seems to at least work better than the old one already :D

Thanks, and keep up the great work!

Apr 14, 2010 at 4:06 PM
Edited Apr 14, 2010 at 4:06 PM

As far as gear selection goes, it is unlikely that pets are required for such choices. Even though the Felguard does 20% or so of my damage output on most fights, it's not something that gearing would actually affect. That said, pets are definitely very important long-term because there are many glyphs and talents that directly buff them. For example, what if there's some gearing threshold over which Improved Demonic Tactics is no longer much of a DPS increase? Or what about Glyph of Imp? Rawr could answer that question for me instead of having to run two entire simulationcraft tests just to see what the differences would be.

I think it's definitely above the "It'd be nice to have" but probably below the "Is this module even relatively functional?"

Apr 14, 2010 at 4:07 PM
Edited Apr 14, 2010 at 5:13 PM

Xioustic: Thanks for the good report!  I'm glad it has already helped you :).  It'll be interesting to see how much adding pets changes its gear recommendation (if at all).

Apr 14, 2010 at 5:19 PM

ShadowWolf: I wouldn't be too surprised if pets made some small changes to gear.  For example SP should become even more valuable than haste than it already is, because Haste does not buff your pet.  So, if there is a haste pieces that the model currently rates slightly higher than one with more SP, adding in pets may (correctly) shift the balance to recommending the SP piece.

Apr 18, 2010 at 6:15 AM
Edited Apr 18, 2010 at 6:17 AM

In my anecdotal experience, that's really only the case for Trinkets. Most items of the same iLevel have the same spellpower, so you're really just comparing haste to crit or spirit. There may be some variance, but I don't think those would be the normal case.

to add: I think that, if two items were close enough that pets mattered, you're probably talking less than 20 DPS between the two of 'em.

Apr 18, 2010 at 8:49 AM
shadowwolf wrote:

In my anecdotal experience, that's really only the case for Trinkets. Most items of the same iLevel have the same spellpower, so you're really just comparing haste to crit or spirit. There may be some variance, but I don't think those would be the normal case.

to add: I think that, if two items were close enough that pets mattered, you're probably talking less than 20 DPS between the two of 'em.

This is a link to wowhead items filtered for Ilevel 264 items, grouped by slot:;minle=264;maxle=264;ub=9;cr=123;crs=1;crv=0;gb=1#chest

Every slot has 2 possible values of spell power at a given item level, but in addition to that the variance in spell power values between slots is very large.Do you wear the chest that uses the higher sp value with spirit/crit plus the bracers that have the lower sp value +hit instead of the pants with low sp value haste/crit and shoulders with low sp value haste/crit?You -are- comparing different sp values: 32 different ones.

In this case if you remove pets the value on the items that are sp heavy will be undervalued and be more significant to your gear selection than you'd think. Pets also scale with more than just spell power or more than with crit if you're demo. Pets scale with stam, int, and more importantly, possibly more than sp, hit . Now by ignoring pets your not just taking out accuracy for sp scaling, your taking out accuracy with hit scaling and no it's simply not enough to know that hit is the most valuable stat.

Here's a H festergut kill from my guild this week:

the two affliction locks I was raiding with had 9.3% and 11.6% of their damage on this fight done by their pets even if we assume gear only accounted for half of those percents that's a 4-5% difference in your output from gear.

Also, 20 dps does matter, maybe not for your average 5 man player but for a raider 20 dps per person in the raid can make or break a fight thus accurately knowing which item will give you the greater dps return is important as opposed to not caring because its just a difference of less than 20.

Warlocks are a pet class. We're becoming more and more of a pet class over time and its probably going to continue to happen in the future since that seems to be the direction blizzard wants to go taking the last 3-4 patches into considering; not taking pets into account means not seeing the whole picture.


Apr 21, 2010 at 7:31 PM

Just started playing with 2.3.15 release.. is there any reason you made the Glyph of Life Tap a default? Importing a character does not remove the check mark next to it, and leaves you with 4 active Glyphs which totally throws off your stats. 

Lifetap for Destruction at t10 is pretty weak, and has went from being a mandatory to optional glyph. I don't mind switching spellstones, because I'm use to going through the buffs and turning those on anyways.. but I could see myself forgetting and not unchecking that glyph. 

I believe if this is left as default your going to end up seeing a lot of bug reports from people that don't notice it... 

Apr 21, 2010 at 8:24 PM
Edited Apr 21, 2010 at 8:49 PM

Thanks for this good info and insight.  I'll remove it.

Apr 22, 2010 at 3:44 AM

I upload my character and it shows my dps should be like 2700, lolwtf

Apr 22, 2010 at 7:13 AM

wow, could you be any less helpful roflicer? it might be a good idea to list specifics like what you expect your DPS to be, and also what spec you are playing. If it's Demo, it's not fully modeled yet. Also, did you go set up your rotations, etc? If you didn't then you should.

Further, if you are not Demo, have set up your rotations and buffs, then you need to save your character.xml file, and create an issue and post your file. "lolwtf" will not get anything resolved.

Apr 23, 2010 at 7:31 AM

Woah buddy I was told If I downloaded it all I had to do was upload character and Rawr did everything else. No the guy is affliction, i expect it to be over 9000, and it already has the rotation set up.

Apr 23, 2010 at 6:20 PM

Firstly, the Warlock model has been in development (this version, for a little over a month now, and has come a long way) and is not quite 100% yet so the DPS calculations are bound to be off some (but not 2k dps verses 9k). You'll notice that your pet's DPS is showing up as 0, if it's like the Destruction Imp, that accounts for ~600DPS or more, that's not being added to your DPS. 

Second, I suspect your 9000DPS is raid buffed? quite possibly 25m raid buffed? Did you go to the buff tab and select all the buffs you are expecting to have during your raid? That will make a big difference in your DPS.

If you get this setup, and your still seeing a extreme difference I'd suggest posting a issue with your character file, that will get you the best result for getting help. Keep in mind though, that pets, and execute phase are not currently in Rawr and will make some difference to your over all DPS.

Apr 23, 2010 at 6:54 PM
"some" difference. Depending on gear and buffs, it can be off by anywhere from 3 to 7k DPS, and that's for Affliction (ie, the spec with the least important pet now that LT has been buffed). The Demo model is currently practically worthless, the Destruction model is mostly good but probably has an incorrect value for crit and overvalues haste. [Demo really, REALLY needs pets/execute, and Destro needs pets - they get a 100% crit buff when the pet crits] Please note that I'm not actually meaning to complain - the devs are doing a great job of fixing things, it's just taking a while. The affliction rankings are pretty close to accurate, with a few VERY significant exceptions (NMIC, for example). Unfortunately, my life has gotten insane, so I wasn't able to do any of the help I mentioned higher in this thread.
Apr 23, 2010 at 8:21 PM
Edited Apr 23, 2010 at 8:23 PM

Roflicer - it is not true that you just load your character from the armory and Rawr does everything else.  As bugmenot said, you must select your buffs & set up your rotation just to get your baseline.  Then to actually USE Rawr for anything you'll need to select other gear you have available or set up filters, all of which is explained in the documentation (link at the top of this page).

Karindra - I wouldn't mind seeing a character file for an aff. lock that's off by 7K dps.  Could you open an issue and attach it?  2.3.15 has a bug that *severly* mis-calculates the crit chance of corruption, but I don't expect that explains a full 7K dps.

Apr 23, 2010 at 11:58 PM

You should set up defaults for buffs and rotations. It shouldn't be perfect, but it should be a baseline to ease the configuration for users.

Apr 27, 2010 at 6:20 PM

I'm looking for opinions about handling pet buffs.  One option is to add in all the melee buffs to the normal buffs tab and assume you & your pet get the same buffs.  Another option is to create a whole other tab to set up exactly which buffs your pet gets, similar to the hunter model.  I can see benefits & drawbacks to both methods.  Any input?


Apr 27, 2010 at 7:11 PM

Personally I would go with the separate tab but specifically lable the tab as pet buffs or whatever. Also to have a standard set of buffs and debuffs with the pet (Intellect, Might, etc)

Apr 27, 2010 at 8:42 PM

Why is that?  The drawback I see for using a single tab is that user may not realize s/he should be selecting melee buffs for his/her pet.  The drawback I see for using two tabs is that user has to sift through all the buffs twice.

Right now I'm leaning toward having a single tab.  I can't think of a situation, off the top of my head, were one would have a buff that the other shouldn't (aside from potions, elixirs & set bonuses, but that's easy enough to special-case).  Having extra attack power won't hurt the warlock, and having extra spell haste won't hurt the felguard.  I CAN see inconsistancies arising from having two separate tabs, though, where a raid-wide buff is only selected for either the warlock or his pet.

Apr 27, 2010 at 9:18 PM

Since Hunter is the only other model that has this, look at it. Hunter uses a Pet Buffs tab in Options. We keep this stuff separate because it doesn't migrate well from parent and Pets aren't affected by buffs the same way. There's also all the internal changes where a parent has x * y * z BonusAttackPower multipliers and pet has Q * x * y. It just doesn't line up like you would want it to.

Apr 27, 2010 at 10:16 PM

I do not play a warlock but I do have a Hunter and often I have a different buff than a given pet depending on situation and group make-up. I see the warlocks as wanting Blessing of Kings while their Felguard has Blessing of Might or Imp has Blessing of Wisdom. Having different setups for toon vs pet allows the user to tinker with the buffs to see which is best in a given situation.

Apr 27, 2010 at 11:42 PM

Do pally buffs have to be a pain in the butt not only to the pallies who maintain them, but now to me also?!

Apr 28, 2010 at 12:00 AM

sorry, Xemonsyst, but I have to agree with brituck.  When I am on my Pally dungeon and raid members are always asking for different buffs depending on the pet, just as brituck mentioned.

also I dont give them 30 min version, just the 10 (not going to use a reagent on a pet)

Apr 28, 2010 at 9:09 AM
fyre wrote:

sorry, Xemonsyst, but I have to agree with brituck.  When I am on my Pally dungeon and raid members are always asking for different buffs depending on the pet, just as brituck mentioned.

also I dont give them 30 min version, just the 10 (not going to use a reagent on a pet)

 30min blessings on pets wouldn't even work because they're 'classed' and a greater blessing would also replace the greater blessing on the players of that class. So pets need to have regular blessings so they can have different/independant ones.


xemnosyst wrote:

Do pally buffs have to be a pain in the butt not only to the pallies who maintain them, but now to me also?!

 YES!   Bend over ! ;-)

Apr 28, 2010 at 11:07 AM

Warlock minions do not work in the same way as hunter pets.  Warlock minions get the same buffs as their master, so cannot be seperately buffed with Pali buffs.  This is why, with enough Palis in the raid, I also like to have Might - no use to me, but I have to have it for my Felpup to get it.

Apr 28, 2010 at 7:49 PM
xemnosyst wrote:

Karindra - I wouldn't mind seeing a character file for an aff. lock that's off by 7K dps.  Could you open an issue and attach it?  2.3.15 has a bug that *severly* mis-calculates the crit chance of corruption, but I don't expect that explains a full 7K dps.


The 7k difference is a fight-specific one actually (BQL) ; I realized I should have said that in my comment.  You might be surprised what a huge difference properly-buffed and rolled Corruption can make (with NMIC + 2-pot Potion of WM + lucky procs of other things that buff crit).  I know I was; for me, the difference between a rolled crit and unrolled crit is approximately 11k vs. 8k 25-man buffed, higher with fight-specific buffs like BQL's.  (Hell, we wiped pre-execute one time I got the buff, and I still had 13k DPS..)

As for pets getting buffs - with at least one and possibly three exceptions - get warlock-based buffs.  Felpups, Imps, Succubus and Voidwalker count as Warlocks.  Felguards count as *Warriors*, which frequently prompts people questioning why Warriors have Wisdom (at least in Pugs my paladin is in that have other paladins handling might/kings/sanc), and I don't know which classes the other ones count as.

On a side note, Hunter pets IIRC count as Hunters, except (unless this has been changed?) Ferocity pets (which are warriors).  DK ghouls are rogues of all things.

Apr 28, 2010 at 11:28 PM

This just in: for the short term minions will get the same buffs as the warlock, as selected in the existing buffs tab.  Because of the transition to Rawr3 I have been told that any effort on Rawr2 options tabs is wasted, and I don't feel like wasting my time!

Apr 29, 2010 at 12:43 AM
xemnosyst wrote:

This just in: for the short term minions will get the same buffs as the warlock, as selected in the existing buffs tab.  Because of the transition to Rawr3 I have been told that any effort on Rawr2 options tabs is wasted, and I don't feel like wasting my time!

Honestly, even as a long term solution that's probably fine.  Aside from a few anal-retentive warlocks I've run with (including, at times, myself), 99% of raids won't know or care about making sure pet buffs are properly set up.  The only exception I can see is the Food buff - there's several treats available that can buff the pets.


May 12, 2010 at 1:46 AM
Can someone point me to the formulae used to calculate average melee damage? Some quick testing with the felguard showed me that its "white" hits can glance, but it's "yellow" hits cannot. "Yellow" can be blocked, and I certainly assume the white can, too. I'm not used to theorycrafting melee. I checked out the code for cat & rogue, but it was a little hard for me to understand and I'm sure much more complicated than I need, since warlock pets will never be crit capped.
May 12, 2010 at 4:08 AM
Edited May 12, 2010 at 6:31 AM

general melee crit calculations against a lvl 83 boss mob are as such

white: 100% - 24% glancing - hit/expertise + 4.8% crit reduction

yellow: 100% - hit/expertise + 4.8% crit reduction

So basically 24% of all white attacks will glance (no matter what) but yellow attacks do not glance.

In the case of warlocks, you would not have to worry about expertise. But for hit, I know that pets are affected by base hit that is show on their stat sheet in game. However, I don't think it's affect by say Misery or Imp FF. I could be wrong about that though.

For RAWR, don't bother with block mechanics. Just assume that your felguard will be behind the boss at all times.

What I would do is take the attack speed of the felgaurd (I'm not sure if a felguard's attack speed is decreased by haste or not), divide that by the length of the fight. then use the above white formula.

May 12, 2010 at 6:29 AM
I'm having some trouble turning what you wrote into formulae for average damage. Why subtract hit/expertise? And you just get a 4.8% damage bonus from something called a "crit reduction"? Also, if 24% of your hits glance that turns into less than a 24% reduction in damage.
May 12, 2010 at 6:44 AM

Look at the StatConversion class in Base, you should find methods to build the combat table. That's what you need.

May 12, 2010 at 6:45 AM

Ok this is basically for Crits but the same applies to hits.

Say as an example you have 60% crit on you Felguard raid buffed(hypothetically speaking) and you have 0% your attacks avoided(the "-hit/expertise" = 0%).

Hits = 100 - 24 - 0 - 60 = 16% of all the white attacks would hit

Crits = 60%

May 13, 2010 at 1:39 AM
I'm gaining on it. Wowwiki says that the damage reduction from a glancing blow averages 10% per level difference. Is there a function/constant already defined for that I should be using? I see .7 is just hard-coded into the Cat model.
May 17, 2010 at 8:09 AM
I notice the glyph for Felguard isn't listed. Considering the support for pets so far, I can understand this. What I'm really missing is having Soul Fire buffed by Decimation in my rotation. Considering that SimulationCraft shows that it's almost 20% of my dps, that seems important. I will attempt to do research to give you more than just a complaint.
May 17, 2010 at 4:02 PM
xemnosyst wrote:
I'm gaining on it. Wowwiki says that the damage reduction from a glancing blow averages 10% per level difference. Is there a function/constant already defined for that I should be using? I see .7 is just hard-coded into the Cat model.

Sorry for not getting back to you sooner, but yes it is already in RAWR


        public static readonly float[] WHITE_GLANCE_CHANCE_CAP          = new float[] { 0.1000f, 0.1500f, 0.2000f, 0.2400f }; // 25%
        //public static readonly float[] WHITE_GLANCE_CHANCE_CAP_BEHIND   = WHITE_GLANCE_CHANCE_CAP;
        public static readonly float[] YELLOW_GLANCE_CHANCE_CAP         = new float[] { 0.0000f, 0.0000f, 0.0000f, 0.0000f }; //  0% Yellows don't glance
        //public static readonly float[] YELLOW_GLANCE_CHANCE_CAP_BEHIND  = YELLOW_GLANCE_CHANCE_CAP;

May 17, 2010 at 11:09 PM
Edited May 18, 2010 at 6:02 AM
Torin - thank you for the feedback. The felguard is at the top of my list. He'll be modeled at least as well as the other pets soon enough (which is still not perfectly - but that will probably come fairly soon as well). Modeling the execute stage is also on my list (which you can find by clicking on "Documentation" above, then finding the link to "Models", then "Warlock"). Hinalover - I did find that code after following the lead Astylian gave me. That gives the me *chance* for a hit to glance, not the average damage reduction for a hit that *does* glance. Wowwiki says a glancing blow will average 10% damage reduction per level difference. Is that in the common code somewhere?
May 18, 2010 at 2:20 AM

I notice Corruption is in the default Destro rotation.  With the exception of high movement fights, using Corruption is a net DPS loss for Destrolocks, so you might wanna take it out at some point...

May 18, 2010 at 6:00 AM
Edited May 18, 2010 at 6:01 AM
That's interesting, midnight. On my toon, corruption is a net dps gain (or at least, that's what my model is telling me). Are you saying corruption is a loss because Rawr tells you so, because some theorycrafting elsewhere tells you so, or because you've tried it and seen the results?
May 18, 2010 at 1:26 PM
xemnosyst wrote:
Torin - thank you for the feedback. The felguard is at the top of my list. He'll be modeled at least as well as the other pets soon enough (which is still not perfectly - but that will probably come fairly soon as well). Modeling the execute stage is also on my list (which you can find by clicking on "Documentation" above, then finding the link to "Models", then "Warlock"). Hinalover - I did find that code after following the lead Astylian gave me. That gives the me *chance* for a hit to glance, not the average damage reduction for a hit that *does* glance. Wowwiki says a glancing blow will average 10% damage reduction per level difference. Is that in the common code somewhere?

 I think you're misunderstanding some parts in wowwiki (or wowwiki is wrong).

Pre 3.0 glancing blows had 10% chance to occur per level -15%.  So a lvl+3 mob would have 30-15 or 15% glancing chance.  (the same calculation as crushing blows btw).
Post 3.0 this changed, the glance chance table in rawr is correct.  +0: 10%, +1: 15%, +2: 20% and +3: 24%.
This is assuming you have maxed weapon skill and there's no special mechanics in place to change glancing blows happening (iirc, Vezzax has an increased chance at getting glancing blows).

Pre 3.0 the gancing damage was 76% of a normal blow, Post 3.0 it's 70%...
I don't recall the Pre 3.0 situation on this, but currently, glancing blows are now said to be 70% damage, it doesn't matter what level the target is.

I seem to vaguely recall that it's actually not a flat X% reduction, this is only an approximation of how much damage gets reduced to.  Iirc, the Lower end and higher end damage of the weapon get changed (and not to the same proportion, the lower end gets changed more). At least that's the pre 3.0 situation I'm talking about now.  It's possible this is still the case and the difference from Pre 3.0 (76%) and now (70%) are caused by the changed weapon damages.   So it's even possible that with ICC weapons the 70% percentage is no longer entirely true either.  it's not a part of the theory i've really been keeping up to date on tho.

The simple story:
Vs a boss 24% of melee autoattacks (whites) will be glancing blows (70% damage done).  Yellow attacks can't be glancing blowse.
Glancing blows are right after pure avoided attacks on the attack roll. So nomatter what you do, the 24% glancing will always be there.  So after boss avoidance (miss, dodge, parry) and the 24% glancing, that's at most what you can crit. I'm not sure how much crit% warlock pets inherit from their masters and if warlocks can get high enough that it would cause their pet crit to exceed 76%-miss%-dodge% (pet will allways attack from the back so parry is a no factor), I also don't know if warlock pets get dodged.



May 18, 2010 at 5:55 PM

Both my RAWR results and EJ Theorycrafting say Corruption is out for Destros unless you're moving and wanna pop out an instant.

A Destro with points in Improved Corruption might change that up, I'm not sure.

May 19, 2010 at 8:12 AM
Midnight - cool, thank you for the info. Could you post that as a feature request, please, including your character file? I'd like to play with it and find out what circumstances affect it. OReubens - I am now torn. Wowwiki says, "These attacks only do 70% of their normal damage versus a mob that is 3 levels above you. (10% per mob level)." A recent post on says, "When you land a glancing blow, it will deal 30% less damage than normal against a raid-level mob, with the damage reduction being reduced by 10% for every level closer to yours the target is." Those seem to be the best results google is giving me. Where is the info saying that it's 70% no matter the level?
May 19, 2010 at 9:30 AM

It's a major problem with doing much of anything in rawr really... getting factual data and not guestimates.   On top of that, facts change when blizzard changes how things work and this doesn't cause all the webpages out there to get updated.  Bad data gets perpetuated as well so even recent posts can get it wrong.

Like I said, I have not been keeping up to date on that particular aspect of melee damage.  If it is variable for mob level, then this really should be a variable in StatConversions (it should be even if it isn't).  From what I can see at a glance (pun intended) melee models in rawr now have hardcoded 0.7 modifiers for glancing blows (ret has 0.75, and I'm not sure if this is is an old value that didn't get changed or trying to compensate for something).  So either they all assume you'll only ever hit level 83 mobs (then why have a mob level selection) or they're all wrong.

May 25, 2010 at 3:40 PM
Edited May 25, 2010 at 3:41 PM

2.3.18 marks the first version of Rawr that I think might be getting close for Demonology locks.  Could I get some comments, please, saying just how close or far away it really is?  Melee haste effects (i.e. Bloodlust and Demonic Empowerment) are not yet modeled, but I think I've accounted for everything else.

It has been 3 months since I started this project, and I'm finally starting to see light at the end of the tunnel!  My Warlock is an alt, but what finally convinced me to work on this was wanting to spend his frost badges for his own gear anyway.  What a long way to go for that goal!  Lol.  Just a little more effort on pet dps, throw in an execute stage, then I'll feel comfortable calling the model complete.  Then I can add in raid damage buffs to the overall score, THEN I'll be where I wanted to be able to pick my frost gear :).  I'm going to guess 1 more month and then my Warlock will be SWEET.  :)  Then it would be nice to make some performance improvements, and it really should model Judgement of Wisdom, and maybe pet mana usage ...

May 25, 2010 at 9:15 PM

You are a champion, Xemno. :)  I can't express how much this warlock, at least, appreciates all the work you have done.

May 27, 2010 at 7:17 AM
Edited May 27, 2010 at 7:17 AM

Unless I missed it for Demo, (and sorry in advance if I missed it) I didn't see Soul Fire under 35%.

May 27, 2010 at 8:08 AM

You did not miss it.  It has not yet been implemented.


May 27, 2010 at 4:37 PM

Hey, btw not directly related to your lock module, but think you can talk them into adding Demonic Pact to the buff list? Seems to be the most commonly used SP buff, but isn't found in the options... Is it because of the endless variable of the buff that makes it hard to implement? Maybe a check box + fill in the blank for buff value option might work?

May 28, 2010 at 6:58 AM

I don't know if "we" can convince "them", but cast your vote for the existing issue (found by searching issues for "Demonic Pact") and maybe it will become more important for someone to implement :P.

Jun 7, 2010 at 11:37 PM

OReubens - I just took my felguard for a spin on a lvl 83 target dummy: 283 hits @ 960 avg damage vs 112 hits @ 722 avg damage (25% less damage on a glance).  Then I took him to the lvl 81 & 82 elites on the wall between Crystalsong and Icecrown: 265 hits @ 947 avg damage vs 49 hits @ 854 avg damage (10% less damage on a glance).  I'm guessing my sample size is large enough to conclude that lvl difference DOES affect the amount of damage reduced by a glancing blow, and that all Rawr models are wrong.  Also interesting is that my testing lines up with the Retribution number of 75%, not everyone else's number of 70%.

Jun 8, 2010 at 10:20 AM

283+112 (395 hits) is still a small sample size.  Anyone can get a statistical confidence level on that ?

I remember having had a quick look at other melee models, and I could't spot any code to account for level in the glance calculations.  Maybe it is there, but then it's hidden a bit deeper than a casual glance (again, pun intended) revealed.

Something like this is easier to test with a player.  You can equip a weapon with a very narrow damage range (some entry level weapons even have no variance at all) so you can get a pretty accurate value on how much less damage a glancing blow does. Glance chance is still a matter of whacking something long enough to get a decent confidence level.  Might need a new (private) post to get melee models updated on this...

Jun 8, 2010 at 3:14 PM

wowwiki says glancing blows average 10% per level difference, but there are notes that indicate that is possibly obsolete.  It seems reasonable to suspect the 0.7 in various Rawr modules is a leftover from TBC.

If I'm reading their code correctly, Simulationcraft uses damage-delivered for a glancing blow at +3 is 65-85%.  At +2 is 90-99%.

Look at and search for  "if ( result == RESULT_GLANCE )"

Jun 8, 2010 at 5:20 PM

I wouldn't be surprised (or care, really), if glancing calculations were wrong for 81s and 82s. If they're wrong for 83s, (30% vs 25%), lets do more testing to confirm, and get that fixed.

Jun 8, 2010 at 5:32 PM

What you see in StatConversion.cs is correct for the level differences in glancing, that was placed there after a lot of research in various sites and manual testing done by me and a couple others.

Jun 8, 2010 at 5:56 PM
If I'm reading it correctly, StatConversion.cs says how likely a glancing blow is. Most of the theorycraft and reported test results agree with StatConversion.cs and say 24%. I think the last few posts are asking how much damage a glancing blow does. I couldn't find any controlled test results (other than Xemno's, above) but it seems that everyone uses either 75% (Rawr.ret, simulationcraft) or 70% (a few other Rawr modules, askmrrobot, wowwiki, recent article). I didn't notice anything in StatConversion.cs that attempts to answer that question. Perhaps I missed it.
Jun 8, 2010 at 8:06 PM
Edited Jun 8, 2010 at 8:42 PM
Everywhere I read it's 10% for each level above you that reduces the amount of white damage for glancing blows (90% for +1 lvl mobs, 80% for +2 lvl mobs, and 70% for +3 lvl mobs). Even found a rogue article from early 2007 about Glancing blows and they were saying the same thing then.


Found an old EJ thread (dating back to the TBC Beta) That shows that glancing blows were doing about 75% damage

Edit 2:

Ok, I took a looked at a recent Festergut HM attempt from our guild and I'm definetly noticing a most white attacks are glancing for ~75% damage. Even our kitty druid was averaging at 77% glancing damage. So having it at 75% would be correct instead of the 70% mentioned everywhere else. It won't change the overall dps that much, maybe 100-200 dps but still.