PDA

View Full Version : Combat Table Analysis



Satrina
10-05-2007, 05:46 PM
Background
What we're really doing here is proving that WoW doesn't use a short-circuit (multiplicative) evaluation, then providing evidence for a table based (additive) combat system. Instead of going into a bunch of math theory and talking about Bayes' Theorem, we'll just talk a little math and then let the numbers speak for themselves. Here are our two methods, the first is the short-circuit evaluation, the second is a table:



- Random to see if your attack misses {random(100) <= 5}
- Random to see if your attack is dodged {random(100) <= 10}
- Random to see if your attack is parried {random(100) <= 10}
- Random to see if your attack is blocked {random(100) <= 10}
- Random to see if your attack is a critical hit {random(100) <= 15}
- If you get here, your attack is a normal hit



- 000-049 = Miss (5%)
- 050-149 = Dodge (10%)
- 150-249 = Parry (10%)
- 250-349 = Block (10%)
- 350-499 = Critical Hit (15%)
- 500-999 = Hit (50%)

The fundamental difference between these two methods is that the first is conditional, and the second one is not. In the first method, you cannot possibly determine if an attack is dodged until you have determined that it didn't miss. You cannot determine it is a hit until you have determined that it dodn't miss, wasn't dodged, wasn't parried, wasn't blocked, and was not a critical hit. This is the key point -] none of the events are mutually exclusive. What does that mean? It's a variation on the classic coin flip problem. If I flip a penny, the chance of it being heads or tails is 50%. If I flip it twice, the chance of getting two heads in a row is 25%. You can't get two heads in a row if the first flip comes up tails; the chance of getting two heads in a row is conditional on the first flip's result. That is exactly what will happen here, following short-circuit evaluation. Let's see how and why.


Results of a Non-Mutually Exclusive System
To illustrate, I wrote up a simple little program. It's written in Lua, and if you copy and paste it then run it using Lua interpreter (lua-users wiki: Lua Binaries (http://lua-users.org/wiki/LuaBinaries)), it will give you similar results to what I present here:


local miss,dodge,parry,block,crit,hit = 0,0,0,0,0,0
math.randomseed(os.time())

for i=1,1000000 do
if (math.random(1,100) <= 5) then
miss = miss + 1
elseif (math.random(1,100) <= 10) then
dodge = dodge + 1
elseif (math.random(1,100) <= 10) then
parry = parry + 1
elseif (math.random(1,100) <= 10) then
block = block + 1
elseif (math.random(1,100) <= 15) then
crit = crit + 1
else
hit = hit + 1
end
end

print("miss: "..miss.." "..miss/1000000)
print("dodge: "..dodge.." "..dodge/1000000)
print("parry: "..parry.." "..parry/1000000)
print("block: "..block.." "..block/1000000)
print("crit: "..crit.." "..crit/1000000)
print("hit: "..hit.." "..hit/1000000)

What this does is determine the result of a combat action following the short-circuit evaluation method, one million times, then print the results. It checks the 5% chance of a miss, then the 10% chance for a dodge, then 10% for a parry, then 15% for a crit, and then calls it a regular hit if none of the previous conditions are met. It gives the number of misses, dodges, parries, blocks, crits, and hits, as well as the percentage of total attacks that each one makes as printed results. Here are the results of one run:



Count Percentage
Misses 50215 5.0215%
Dodges 95482 9.5482%
Parries 85364 8.5364%
Blocks 76712 7.6712%
Crits 104321 10.4321%
Hits 587906 58.7906%

We see here that using this method, we get 104321 critical hits on 1000000 attacks. That's 10.4%, not 15%. Where did the other 4.6% go? The problem isn't that we lost 4.6% crits, it is that the conditional method "loses" attacks as it progresses through the series of evaluations. If we look at the number of dodges, we see it is 9.6%, which is close to the 10% we said our dodge rate. But, we did a million iterations. It should be a lot closer to 10% exactly. How do we find the missing dodges then? Remember, we can't check to see if we dodged unless the attack was not a miss. There is no independence of events. That means the 50215 misses in our million attacks had no chance to be a dodge - so they don't count. Look at this: 95482/(1000000 - 50215) = 0.10053. We find the missing 0.4% by discounting the attacks that were misses and could not possibly have been dodges.

This holds true all the way up the list. We can now find the missing 4.6% critical hits here:
104321/(1000000 - 50215 - 95482 - 85364 -76712) = 0.15070

We get 15% critical hits over ONLY those attacks that were not misses, dodged, parried, or blocked. Since we have it from Blizzard that you must get 15% critical hits over all attacks, which would be 150000 critical hits in this example, we prove that combat cannot be resolved by a short-circuit evaluation. Also note that if this was the method in play, you'd be getting short-changed on your dodges, blocks, and parries when something attacks you.


Results of a Mutually Exclusive System
Now we come back to the table based system. We generate one random number and look up what happens in the table. Because of this, any single check can be any result present in the table, with no conditions attached. This is a mutually exclusive system. Here is another little program:


local miss,dodge,parry,block,crit,hit = 0,0,0,0,0,0
math.randomseed(os.time())

for i=1,1000000 do
r = math.random(1,100)
if (r <= 5) then
miss = miss + 1
elseif (r > 5 and r <= 15) then
dodge = dodge + 1
elseif (r > 15 and r <= 25) then
parry = parry + 1
elseif (r > 25 and r <= 35) then
block = block + 1
elseif (r > 35 and r <= 50) then
crit = crit + 1
else
hit = hit + 1
end
end

print("miss: "..miss.." "..miss/1000000)
print("dodge: "..dodge.." "..dodge/1000000)
print("parry: "..parry.." "..parry/1000000)
print("block: "..block.." "..block/1000000)
print("crit: "..crit.." "..crit/1000000)
print("hit: "..hit.." "..hit/1000000)

What this does is determine the result of a combat action by generating a single random number and looking up the result in the table, one million times, then print the results. It gives the number of misses, dodges, parries, blocks, crits, and hits, as well as the percentage of total attacks that each one makes as printed results. Here are the results of one run:



Count Percentage
Misses 49984 4.9984%
Dodges 100113 10.0113%
Parries 99979 9.9979%
Blocks 99951 9.9951%
Crits 150316 15.0316%
Hits 499657 49.9657%

We see here that using this method, we get 150316 critical hits on 1000000 attacks. That's 15%. Similarly, our miss, dodge, parry, and block rates are 5%, 10%, 10%, and 10%. The results here are consistent with what we are told to expect by Blizzard, and are consistent with a table-based (additive) system

pixel001
01-07-2008, 07:45 AM
just a question. :)

are these values (5% miss, 10% dodge, 10% parry, 10% block, 10% crit, 15% hit) just ballpark values or is that the real chance ?

iv'e rewritten this in vb ;)




Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Randomize()

Dim r As New Random
Dim rn As Integer

Dim miss, dodge, parry, block, crit, hit As Integer
For a As Integer = 1 To 1000000
rn = r.Next(1, 100)

If r.Next(1, 100) <= 5 Then
miss += 1

ElseIf r.Next(1, 100) <= 10 Then
dodge += 1
ElseIf r.Next(1, 100) <= 10 Then
parry += 1
ElseIf r.Next(1, 100) <= 10 Then
block += 1

ElseIf r.Next(1, 100) <= 15 Then
crit += 1

Else

hit += 1
End If
Next
TextBox1.Text &= "non-independent hit calculation" & vbCrLf

TextBox1.Text &= "5 miss: " & miss & " : " & Math.Round(miss / 1000000 * 100, 2) & " ~ " & Math.Round(miss / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "10 dodge: " & dodge & " : " & Math.Round(dodge / 1000000 * 100, 2) & " ~ " & Math.Round(dodge / (1000000 - miss) * 100, 2) & vbCrLf
TextBox1.Text &= "10 parry: " & parry & " : " & Math.Round(parry / 1000000 * 100, 2) & " ~ " & Math.Round(parry / (1000000 - miss - dodge) * 100, 2) & vbCrLf
TextBox1.Text &= "10 block: " & block & " : " & Math.Round(block / 1000000 * 100, 2) & " ~ " & Math.Round(block / (1000000 - miss - parry - dodge) * 100, 2) & vbCrLf
TextBox1.Text &= "10 crit: " & crit & " : " & Math.Round(crit / 1000000 * 100, 2) & " ~ " & Math.Round(crit / (1000000 - miss - parry - block - dodge) * 100, 2) & vbCrLf
TextBox1.Text &= "15 hit: " & hit & " : " & Math.Round(hit / 1000000 * 100, 2) & " ~ " & Math.Round(hit / (1000000 - miss - parry - block - crit - dodge) * 100, 2) & vbCrLf

TextBox1.Text &= vbCrLf

TextBox1.Text &= "we get " & crit & " critical hits on 1000000 hits, thats " & Math.Round(crit / 1000000 * 100, 2) & vbCrLf

miss = 0
dodge = 0
parry = 0
block = 0
crit = 0
hit = 0

For a As Integer = 1 To 1000000
rn = r.Next(1, 100)


If rn <= 5 Then
miss += 1
ElseIf rn <= (5 + 10) Then '15
dodge += 1
ElseIf rn <= (5 + 10 + 10) Then '25
parry += 1
ElseIf rn <= (5 + 10 + 10 + 10) Then '35
block += 1

ElseIf rn <= (5 + 10 + 10 + 10 + 15) Then '50
crit += 1

Else

hit += 1
End If
Next
TextBox1.Text &= "independent hit calculation" & vbCrLf

TextBox1.Text &= "5 miss: " & miss & " : " & Math.Round(miss / 1000000 * 100, 2) & " ~ " & Math.Round(miss / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "10 dodge: " & dodge & " : " & Math.Round(dodge / 1000000 * 100, 2) & " ~ " & Math.Round(dodge / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "10 parry: " & parry & " : " & Math.Round(parry / 1000000 * 100, 2) & " ~ " & Math.Round(parry / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "10 block: " & block & " : " & Math.Round(block / 1000000 * 100, 2) & " ~ " & Math.Round(block / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "10 crit: " & crit & " : " & Math.Round(crit / 1000000 * 100, 2) & " ~ " & Math.Round(crit / (1000000) * 100, 2) & vbCrLf
TextBox1.Text &= "15 hit: " & hit & " : " & Math.Round(hit / 1000000 * 100, 2) & " ~ " & Math.Round(hit / (1000000) * 100, 2) & vbCrLf

TextBox1.Text &= vbCrLf

TextBox1.Text &= "we get " & crit & " critical hits on 1000000 hits, thats " & Math.Round(crit / 1000000 * 100, 2) & vbCrLf

End Sub

Satrina
01-07-2008, 12:07 PM
They're just pulled out of a hat for illustrating the point. Realistically we know that we have the base 5&#37; chance to miss, and bosses have around 5% dodge and 10-14% parry. Seems the dodge and parry numbers are tweaked by the game designers on a boss by boss basis. (And then because of the 3 level difference, add 0.6% to each of those.)

Arlana
01-07-2008, 12:17 PM
You guys make me feel safe when i go to sleep at night. FYI

edit: ok, so that means that all those people on the forums(wow forums) talking about how things are multiplied, i.e. run speeds, talent point stacks like lethality with deadly deeds (30&#37; crit bonus*lethality*, and the 20% yellow dmg bonus on a target below 35% health*deadly deeds*) are infact wrong because teh combat table is additive?
Just wanna make sure i'm not misunderstanding, and i certainly would like to know the truth behind the matter.

Satrina
01-07-2008, 12:30 PM
A lot of things are multiplicative, the combat table is just not one of them. For example:

Threat multipliers - defensive stance threat (1.3) and 5/5 defiance (1.15) multiply to make each point of damage worth 1.495 (1.3 x 1.15) threat.

Mitigation - 15000 armour (55.6&#37;) and defensive stance (10.0%) combine to make a 10000 point hit actually land for (10000 x 0.444 x 0.9) 3996 damage, or a total of 60.0% mitigation.

I don't play a rogue, but I would expect that lethality and deadly deeds are multiplicative too. The damage done has nothing to do with the combat table; all the combat table would do is tell you whether it was a crit (and trigger lethality). If you hit for 1000 damage, then lethality would make it 1300, and then deadly deeds would take it to 1560.

Kazeyonoma
01-07-2008, 02:05 PM
yeh arlana, we can prove that threat multipliers are multiplicative too, and have. When Satrina, Fame, and Myself were testing for the new devastate threat values, we used 1.495 as the threat modifier and we were able to prove within 1-4 damage the threat caused by devastate. If in fact threat multipliers were not multiplicative our findings would've been much more off.

But glad to see this Satrina, I'm sure someone will point out that you used simulated situations and WoW isn't simulated, blah blah blah, but from a logical standpoint, this makes 100&#37; truth and proves we have a single roll combat table.

Arlana
01-07-2008, 02:19 PM
That isn't exactly how lethality works because it's crit damage not total damage of a critical strike(my fault because i didn't provide full tooltip explanation of it). But thanks for the info, it was very helpful and answered my question ^_^.

egor4
12-06-2011, 12:49 AM
good post