View Single Post
  #1  
Old 04-10-2016, 10:40 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 52
Default EverQuest Melee Combat Routines Analyzed and Modeled

Hi again. For those that do not know, I am a developer at The Al'Kabor Project. TAKP is an emu that aims to replicate EverQuest's early Planes of Power era.

This document is everything that I've discovered about EverQuest's melee combat mitigation and avoidance rolls. This was the last major piece the emus were missing to really feel like Live, and I've made significant progress in replicating it. I have this already mostly implemented on TAKP, but we've closed the source recently due to a dispute and our public branch only has this half implemented. EQEmu devs know how to contact TAKP devs if they want to look at my implementation.

This work focuses on classic to PoP era NPCs because that's the era for our server. Everything here applies to Live, however NPCs in later expacs are likely to have higher stats than are plotted here.

A significant potion of this work was done by Demonstar55 and hopefully I've noted every instance of his involvement. Much of my work built off of his and could not have been done without his help, so he deserves his due credit.

Note that I use 'Sony' in this document to refer to what could also be called Verant Interactive or Daybreak Games. Daybreak is what they are now, and (Sony owned) VI is what they were when they designed these mechanics, but Sony owned EQ until recently.

I will at times refer to a somewhat large spreadsheet that I made which has the parsed results of my logs and most of the calculations discussed in this document. I produced hundreds (over 2.6 gigs worth) of logs over the last year and parsed them with a custom lua script that I also wrote which output the data in a way that I could easily paste into the spreadsheet. Many of these logs were overnight or even longer. A log generally needs to be several hours long to be useful; obviously the longer it is, the more accurate the estimates that can be derived from it. Note that, for the sake of brevity, some of the formulae I present in this document will not include much in the way of how I came to them. Check the spreadsheet for some of the illustrative math.

The spreadsheet is located here: https://docs.google.com/spreadsheets...cUHju6ii1SezjM

My logs can be found here: https://drive.google.com/open?id=0B9...WVnakdNS3AzRE0

My lua scripts can be found here: https://drive.google.com/open?id=0B9...mxHMW9EQmsyMGs

The scripts that pertain to this document are 'meleedmg.lua' and 'disim.lua'. These scripts must be executed with a command line Lua interpreter. Note that you can redirect the output to a text file by using the '>' operator at the command line.


AC and ATK Component Stats; End Goals

It's long been known that AC and ATK are a combination of two values: avoidance and mitigation for AC, and to-hit and offense for ATK. The first steps in figuring out how EverQuest calculates melee damage and avoidance were to split these stats into their separate component stats.

The emulators were given a great gift in the form of Dzarn's AC breakdown post in April 2014. This really made much of this possible.

ATK doesn't have a developer post about it, so Demonstar55 decompiled a client and managed to figure out how the stat was calculated precisely. Precision is important because player character component stats are the foundation for everything else in this document. They are the known variables.

Specifically, my end goals were to:
  • Develop a high precision model of EQ's mitigation and avoidance routines.
  • Accurately estimate an NPC's avoidance, mitigation, to-hit, and offense when only knowing the PC's stats plus log parsed miss rates and DI distribution.
  • Develop a high precision model of the player character damage multiplier.


Calculating Player Avoidance AC and Mitigation AC

This was straightforward, thanks to Dzarn. Read his post for details. I was able to calculate AC with absolute precision which allows me to calculate sheet AC, worn AC, agility, or defense skill even if I were missing one of the four.

The values we want in particular are the mitigation AC ('ACSum' in Dzarn's post) and avoidance AC ('ComputedDefense').

Ignoring some important things, like buffs, AAs, and heroic stats, the simplified formulae are these:

MitigationAC = INT(DefenseSkill / 3) + INT(WornAC * 4 / 3) + INT(if Agility > 70 then Agility / 20 else 0)
AvoidanceAC = INT(DefenseSkill * 400 / 225) + INT(8000 * (Agility - 40) / 36000) + AvoidanceStat
SheetAC = INT(1000 * (MitigationAC + AvoidanceAC) / 847)

Note that these are accurate for Live servers. The avoidance bonus calculated from agility is different in TAKP's client, so it's clear that agility's affect on avoidance AC has changed since Planes of Power; otherwise the equations match our client.


Calculating Player Offense, To-Hit and ATK

A player character's offense value (not to be confused with the offense skill, which actually just increases to-hit) is calculated using this algorithm: (again, full credit to Demonstar55 for both of these)

Code:
if WeaponSkill > 0 then
	Offense += WeaponSkill
	
if SkillUsed == ARCHERY or SkillUsed == THROWING then
	StatBonus = Dexterity
else
	StatBonus = Strength
	
if StatBonus >= 75 then
	Offense += (2 * StatBonus - 150) / 3
	
if IsSpellAffectingPC(2434) then	// ST avatar proc
	SpellAtk -= 100
	ItemAtk += 100
end

Offense += SpellAtk
if ItemAtkCap < ItemAtk then
	ItemAtk = ItemAtkCap
	
Offense += ItemAtk
Offense += GetLeadershipBonus()

if Class == RANGER and Level > 54 then
	Offense += Level * 4 - 216;

if Offense > 0
	return Offense
else
	return 1

Player character to-hit is calculated thusly:

Code:
ToHit = OffenseSkill + 7
ToHit += WeaponSkill

if Class == WARRIOR and IsBerserk() then
	toHit += 2 * GetLevel() / 5;

Drunk = Intoxication / 2
if Drunk > 20 then
	Redux = 110 - Drunk
	if Redux > 1
		Redux = 1
	ToHit *= Redux
end

if ToHit > 0 then
	return ToHit
else
	return 1
Types and rounding/truncating left out for simplicity.

The client's sheet ATK is: INT((ToHit + Offense) * 1000 / 744)

AC displayed in the client also has a similar multiplier applied at the end. Server calculations do not appear to do that extra step. Dzarn called it 'obfuscation', so Sony might have done it to hide some of their logic.

You may also notice that the Accuracy stat is not factored into the sheet ATK value. I don't know why that is.

These functions are accurate for Live and also TAKP's Planes of Power era client as far as I can tell.


Player vs. Player Avoidance

The obvious next step at this point is to produce logs of PvP combat with known statistics for the attacker and defender. I generated many multi-hour logs against a target with incremental avoidance AC values at four different to-hit values, using level 1, level 25, level 50, and level 65 warriors. Here are the results plotted on a graph:


http://imgur.com/wmNjeIV


There are three important conclusions we can make from the data:
  • Avoidance AC == To-Hit != 50% hit rate as one might expect. The 50% mark is at To-Hit * 1.2 == Avoidance AC, or To-Hit == Avoidance AC / 1.2.
  • The function is linear before 50% and curved after.
  • The curve when avoidance > to-hit resembles y = 1 / X.

At this point I was left wondering if this 1.2 multiplier applied only to PvP or not. Not having even one example of an NPC with known statistics makes verification difficult. I do however think it likely that it also applies to PvE because:
  • It's clear from parsing pets that pets vs NPCs use the same calculation as PCs vs NPCs.
  • NPC to-hit estimates end up extremely close to the to-hit levels of a player character using the old skill formulas. (level * 5 + 5)
  • SoD mage pets had some of their stats pasted by a dev years ago. These stats don't include what they get from base skills, but they include the extra AC and ATK on top of it. When I parsed the Air pet vs the Fire pet and calculated estimates for their to-hits, the gap between the two was as expected when I accounted for the 1.2 multiplier but not when I excluded it. When I parsed them on an NPC, the gap was as expected when the NPC's avoidance was estimated using the multiplier.

The next step was to develop a model that would produce values that matched all of the parsed log data and accurately predict values at any given to-hit and avoidance rate inputs.

After some trial and error I settled on splitting my model into two functions: one for < 50% hit rate and one for > 50%. Maybe somebody better at math could consolidate them into one function, but this worked well enough that I moved on. Obviously I have no idea if Sony's algorithm is split in half or not.

Here is my model:

Code:
AvoidanceMod = round( (AvoidanceAC - ToHit) / (max(floor(ToHit / 10, 1)) + 1) )
AvoidanceAC -= AvoidanceMod

if (ToHit * 1.2 > AvoidanceAC) then
	
	MissRate = (AvoidanceAC - AvoidanceMod) / (ToHit * 1.2 * 2)
	AvoidanceAC = ToHit * 1.2 * MissRate * 2 + AvoidanceMod
	ToHit = (AvoidanceAC - AvoidanceMod) / MissRate / 2 / 1.2
else
	
	MissRate = 1 - ToHit * 1.2 / ((AvoidanceAC - AvoidanceMod) * 2)
	AvoidanceAC = ToHit * 1.2 / (1 - MissRate) / 2 + AvoidanceMod
	ToHit = (AvoidanceAC - AvoidanceMod) * (1 - MissRate) * 2 / 1.2
end
Not to boast, but this works so well that I don't think it would be possible to tell the difference between this and Sony's code when parsing without making obscenely long logs. The above graph shows the results of this model vs. actual parsed logs.

The 'AvoidanceMod' was something I came up with after noticing that the results did not fit perfectly even after multiplying to-hit by 1.2. This was particularly noticeable at very low levels. It seems Sony's code has a modifier that reduces the impact of a large disparity between to-hit and avoidance.

Note that hit/miss rates must exclude avoidance from combat skills. You can calculate the 'actual' hit and miss rates by doing the following:

Actual hit rate = (DodgeRate + ParryRate + MissRate) * (HitsLanded / (HitsMissed + HitsLanded)) + HitsLanded
Actual miss rate = (DodgeRate + ParryRate + MissRate) * (HitsMissed / (HitsMissed + HitsLanded)) + HitsMissed


Estimating Avoidance from To-Hit and Miss Rate

Once you have a function that can calculate Z from X and Y, it's a matter of simple algebra to come up with functions that can calculate X from Z and Y and Y from Z and X. Since player to-hit is knowable and miss rates are parsable, we have two of the three required to estimate attacking NPC to-hit. (and also NPC avoidance)

Code:
if HitRate > 0.5 then
	AvoidanceMod = (0.5 - HitRate) * 20
else
	AvoidanceMod = 1 / (HitRate / 6.56) - 10
end

if HitRate > 0.5 then
	EstAvoidance = MissRate * ToHit * 1.2 * 2 + AvoidanceMod
else
	EstAvoidance = ToHit / HitRate * 1.2 / 2 + AvoidanceMod
end
AvoidanceMod had to be estimated using an original function from hit/miss rate, since AvoidanceMod in my model requires knowing both avoidance and to-Hit. This produces an imprecise but reasonably close estimate of AvoidanceMod.

Using this simple algorithm, I went around and parsed random NPCs in the game and calculated their avoidance AC estimates. I accomplished that by charming them and casting a high level regen spell on them so I could produce multi-hour logs. I also parsed the Azia dummy in the neighborhood guild hall, which is supposed to have stats similar to classic NPCs.


http://imgur.com/D0FFh1l


PoP NPCs and Arena Dummies typically have higher combat statistics than classic NPCs which is why I split them, ("classic" meaning NPCs up through Luclin) but in the case of avoidance AC, they appear the same except for the late 40s NPCs. Avoidance AC increases linearly up to about level 43 when it stays flat to level 50, then jumps after 50. This pattern is also seen in other stats like to-hit. Azia dummies clearly do not follow the same trend as regular NPCs for avoidance.

It's important to note that even if I'm wrong about the 1.2 multiplier applying in PvE, the resulting avoidance AC and to-hit estimates parsed from NPCs using these algorithms would also end up such that combat in the emu would still mimic Live accurately because the NPC avoidance estimates would be lower.

I also ran some parses with agility debuffs on NPCs to try and see how they would alter the avoidance result. Negative agility does in fact reduce NPC avoidance, and seemingly by the amount it would on a PC, or nearly as much. (-AGI * 0.22222) There did not appear to be a cap on this reduction, either: on very low level NPCs, the reduction was not mitigated even with large agility debuffs. The level 5 Azia dummy went from an estimated 40-44 avoidance to an estimated 2 avoidance with a -187 debuff, and a level 4 kobold went from ~43 to ~15 with a -100 debuff. For PCs with zero agility, the avoidance penalty is capped at either -8 or -9. (depending on how Sony rounds) This would suggest that a great deal of NPC avoidance comes from agility and that NPCs have a lot of agility, or that NPC stats can go negative, or that NPCs use a different calculation. This also unfortunately makes attempting to figure out how much defense skill the NPC has impossible, if they get a defense skill.


Estimating To-Hit from Avoidance and Miss Rate

Code:
if HitRate > 0.5 then
	AvoidanceMod = (0.5 - HitRate) * 20
else
	AvoidanceMod = 1 / (HitRate / 6.56) - 10
end

if HitRate > 0.5 then
	ToHit = (AvoidanceAC - AvoidanceMod) / 1.2 / MissRate / 2
else
	ToHit = (AvoidanceAC - AvoidanceMod) * MissRate / 1.2 * 2
end

http://imgur.com/EPVvcnf


For NPC to-hit, you can also see where the slope becomes almost flat around level 43 to 50 before jumping up at 51 and remaining relatively flat. You can also see a clear difference between classic and PoP+Dummy NPCs.

The two Velious outliers were An Icepaw champion and An icy watcher in Velketor's Labrynth. I surmise that Sony granted some NPCs extra accuracy, like pets also have extra atk. Interestingly Kelorek`Dar in cobalt scar had an unremarkable to-hit. The PoP outlier was a NPC in Solusek's Tower. Check the spreadsheet for the NPC names associated with the data.

The old skillup formula for melee weapon skills (and how it is for TAKP) was level * 5 + 5. Offense skill was the same for warriors, but hybrids did not get the + 5. Current Live sub-51 NPC to-hits actually match almost precisely with old ranger to-hits: rangers (with maxed skills) had a to-hit of level * 10 + 5 + 7 up to level 42, when their offense skill capped. It's clear that live server NPCs are mimicking the old skill caps instead of the current player character skill caps.

The plateaus at 43-50 and 51+ also match very closely to what an old melee class's to-hit would be. An old warrior or ranger capped out at 210 offense skill and 200 weapon skill in classic, which would result in 417 to-hit. The second plateau matches a 60 warrior's to-hit, which was 252+250+7=509. 51+ player characters had their caps raised a few points per level however, not all at level 51.
Reply With Quote