So I wanted to figure out how NPC damage actually works and how the live devs actually define things.
For a long time the basic NPC damage formula was stated to be:
(quick abbreviations: DB = damage bonus, DI = damage interval, DI_roll is the mitigation vs attack roll)
This mostly works but is missing parts including how rounding is done and how the SE_MinDamageModifier works on it (which is implemented incorrectly in our code)
A more complete formula has been used to model PC damage (stolen from a live player's post on the official forums)
Code:
DB + Floor(Heroic_str/10) + C*(Random(1 to 20)*weapon_damage/10 * Random(100 to PC_DAM)/100)
This looks fairly close to the old DB + DI formula people have used for a long time, but with a bit more to it. (live uses the same function after all for PCs and NPCs)
So some parses I chose to do these parses on my BST pet since they have access to a disc with SE_MinDamageModifier that lands a buff on the pet (
http://everquest.allakhazam.com/db/s...tml?spell=8234)
Now let me explain how the MinDamageModifier works. This buff has 2: Increase All Skills Minimum Damage Modifier by 400% (base1 = 400, base2 = -1)
What this does is takes the weapon_damage * 400 / 100 and uses that for a min cap on the damage done. So with a 10 dmg weapon this caps the damage (pre damage bonus) to 40, so every hit that is below 40 is set to 40. This is key to figuring out how the damage is defined.
So, level 70 BST pet with no pet focus, hits for: 23, 26, 30, 33, 37, 41, 44, 48, 51, 55, 59, 62, 66, 69, 73, 77, 80, 84, 87, 91. With the buff going he hits for 163 only.
So, the damage. We can get the "weapon damage"/damage interval doing
Code:
(max hit - min hit) / 19
(91 - 23) / 19 = 3.57895
Now this is where the old way would of stopped, which does give us a decent understanding, but is incomplete. To get this to the same "units" as a weapons base dmg we can multiple by 10 and round to 36.
The damage bonus would just be min hit - DI, so 19.whatever rounded to 19.
So quick python script to verify
Code:
>>> base = 36
>>> bonus = 19
>>> for i in range(1, 21):
... print(bonus + int(round(i * base / 10.0)))
...
23
26
30
33
37
41
44
48
51
55
59
62
66
69
73
77
80
84
87
91
Now we see this perfectly matches the parsed numbers, and we can avoid the floating point math as well (SOE likes to avoid floats a lot so they probably DO)
Code:
>>> for i in range(1, 21):
... print(bonus + (i * base + 5) / 10)
...
23
26
30
33
37
41
44
48
51
55
59
62
66
69
73
77
80
84
87
91
Now, lets go back to the pet with the disc.
Code:
36 * 400 / 100 = 144
With a DB of 19, we get 163. The only number we parsed with the disc up. Now the spell 1: Increase All Skills Damage Modifier by 100% which we have to account for to double check if this all works out
Code:
(20 * 36 + 5) / 10 = 72
72 * (100 + 100) / 100 = 144
Which tells us our max hit with the damage increase at least matches our min damage mod, so that checks out.
What about other pets?
Level 68 BST pet: 21, 25, 28, 32, 35, 38, 42, 45, 49, 52, 55, 59, 62, 66, 69, 72, 76, 79, 83, 86. With disc 154.
Code:
DI = (86 - 21) / 19 = 3.42105 * 10 = 34
DB = 21 - 3.42105 = round(17.57) = 18
Plugging these numbers into python everything checks out. And with the min damage
Code:
34 * 400 / 100 = 136
136 + 18 = 154
I did double check lower level BST pets, but I didn't save the logs. They are actually a bit more interesting since their DI is so low they don't hit for 20 different numbers, but the rounding checks out, even numbers that had more than one DI round to the same number had a bit more favor.
Now I believe this is really how they define NPC damage, rounding checks out and allows us to use a single function for these calculations.
Also the arena combat dummies allow you to change their damage "You may ask me to [increase] or [decrease] [resists], [mitigation], [melee speed], [offense], [min damage], and [base damage]." They call them min damage and base damage, base damage also being what the label on the weapons damage is in the UI.
Doing the math this way nicely avoids floating point math (which SOE tries to do pretty much everywhere) And the old under standing of NPC damage requires floating point math, and didn't jive well with PC damage calculations.
Note: I'm not 100% sure that above damage bonus calc will work 100% of the time ... will need to do more research.
But we should probably move away from defining min dmg and max dmg to defining damage bonus and base damage to avoid any rounding errors from reversing NPC damages on live.
EDIT:
Well, I said I didn't save it, but really I just didn't export the logs as a single fight, but here is the data for the level 8 BST pet: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13. With disc 25
Code:
DI = (13 - 2) / 19 * 10 = 5.78947 = 6
2 - 0.578947 = 1.42105 = 1
Code:
>>> base = 6
>>> bonus = 1
>>> for i in range(1, 21):
... print(bonus + (i * base + 5) / 10)
...
2
2
3
3
4
5
5
6
6
7
8
8
9
9
10
11
11
12
12
13
EDIT:
TL;DR
Base damage = conventional DI * 10 rounded.
Code:
damage bonus + (DI_roll * base damage + 5) / 10