Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #16  
Old 09-04-2015, 03:28 PM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 61
Default

Stumbled upon this post from Prathun which I think is worth including here.

Quote:
Originally Posted by Prathun
There are various ways that an NPC can be assigned a spell to cast: a script call, spell innate, contact innate, auto memorization, or a spell list. The last one, the spell list, allows us to override the spell's natural resist mod. This isn't data that you can parse, (the spell data file is an anomaly as far as pushing EverQuest's nuts and bolts out to the client), since the spell list and NPC aren't player facing. In this case, the NPC in question is probably using spell list 11, which has a -740 resist mod for Clawing Darkness.
I'm guessing 'spell innates' are things like dragon AoEs, and 'contact innates' are NPC procs. It also seems Sony/Daybreak does have the option to set a resist adjust override in spell lists after all, even if the examples I thought I found were actually caused by a different feature.

It's interesting to note that Sony separates 'spell innates' from spell lists, which is not what EQEmu does-- we just have lists. I've actually run into a problem for TAKP, in that some NPC abilities need to fire immediately after the cooldown expires, but the spell AI has random delays for any spell in the spell list that cannot be disabled via database. Cazic Touch for example fires every 45 seconds on Live like clockwork, but eqemu will add an additional delay. Also, spell priorities have to be set in a way such that the spells that should be 'innates' always have priority, else common spells like roots and heals could get chosen over more important abilities like DTs and AoEs.

I neglected to mention previously in this thread that I've also discovered that innate NPC spell procs have a special logic to them. They seem to disregard certain spell data fields and forcibly hit the NPC's target and only that target. Zlandicar, Thall Xundraux Diabo, Kaas Thox Xi Aten Ha Ra, shiverbacks, and spirited harpies all proc spells that are flagged as AoEs but only hit their targets. Sony could either toggle procs to be single target only, or they are all hardcoded that way. Also spells like scareling shadowstep and test dummy complete heals are flagged beneficial but hit the target instead of the NPC caster. For TAKP I made innate NPC procs always hit the target and only the target until I find an example otherwise.
Reply With Quote
  #17  
Old 12-07-2016, 01:25 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 61
Default

I've discovered a very serious balance issue with the spell code logic. IsPartialCapableSpell() is not accurate.

While I was parsing Luclin bosses for AC/ATK, I noticed that some spells were hitting me even beyond the expected 200 scale. It became clear to me that these spells were using the 600/partial scale even though the spells had effects like AC debuffs and stuns.

Interestingly, I did some searches through old logs and discovered that Anarchy (the enchanter DD) used to follow the 200/all-or-nothing scale back in Velious, but sometime around Luclin's launch, it began to partial hit. Apparently Sony changed the spell logic to allow them to create spells that could partial hit and also have debuffs in them around that time, then implemented the NO_PARTIAL_SAVE field to flag spells like necro snares to still use the 200 resist scale.

The fix is simple:

Code:
bool IsPartialCapableSpell(uint16 spell_id)
{
	if (spells[spell_id].no_partial_resist)
		return false;
	
	// spell uses 600 (partial) scale if first effect is damage, else it uses 200 scale.
	// this includes DoTs.  no_partial_resist excludes spells like necro snares
	for (int o = 0; o < EFFECT_COUNT; o++)
	{
		uint16 tid = spells[spell_id].effectid[o];

		if (IsBlankSpellEffect(spell_id, o))
			continue;

		if ((tid == SE_CurrentHPOnce || tid == SE_CurrentHP) && spells[spell_id].base[o] < 0)
			return true;

		return false;
	}

	return false;
}
DDs that partial hit have damage in the first slot, then stuns in the second. Stuns with a damage component (cleric, wizard stuns) have a stun in the first slot, damage in the second; those spells are all-or-nothing. Furthermore, all raid boss spells that I've found that used the 600 scale had damage as the first effect. Spells that used the 200 scale and had damage as the first effect all ended up having NO_PARTIAL_SAVE=1. Druid magic DoTs and necro fire DoTs did not have the NO_PARTIAL_SAVE flag and they in fact use the 600 scale, which makes these spells even easier to land than DDs.

I'm not 100% certain this logic is correct, but it fits all the spells I've verified the resist scales for. Certainly the current EQEmu code is incorrect and making raid bosses in Luclin and beyond much easier than intended. Peer review is welcome as always.
Reply With Quote
  #18  
Old 07-12-2018, 02:05 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 61
Default

From what I can tell, typical common NPC resists are these:

If NPC level < 25 then MR and FR and CR = 25
If NPC level >= 25 then MR and FR and CR = 35
DR and PR = 15
Reply With Quote
  #19  
Old 07-30-2021, 01:08 AM
Torven
Sarnak
 
Join Date: Aug 2014
Posts: 61
Default

I have recently done more research into EQ's resist logic and I will outline it here.

First I want to preface this with a reminder that EQ supposedly had three 'resist eras' where the resist logic behaved differently. The resist logic had an overhaul just prior to PoP's launch, then again (supposedly) in 2006 when Rashere modified it. The current Live resist logic is the same as outlined by Prathun in a 2010 post, so presumabely this is the result of Rashere's modifications.

I have gigs of Al'Kabor logs to pull data from, so this is data from a server that uses code from the second era.

First, I was able to verify that the level difference resist modifier (levelDiff^2/2) matched AK data. I AoEd a lot of NPCs in fungus grove on AK, and I parsed these on Live servers to get their resists. Resist values on Live for most common NPCs in classic through Luclin was 35 points and the FG mobs also were. When AoEing level 51 NPCs on level 59 characters on AK, I got very few resists, then got zero resists at level 60. This matches the Prathun logic. (35 - (8*8/2) = 3 resist value; 35 - (9*9/2) = -5 resist value)

Second, I was able to verify that Prathun's partial resist logic also matched AK data. I know this because my level 59 character AoEing level 51 NPCs would always do half damage when the spell partial hit. When this character was level 58, meaning the effective resist value was now 11 (35-(7*7/2)=11), the partial damages were always one of 7 values. This matched the output of Prathun's formula of: ((150 * (resist chance - roll)) / resist chance).

I was also able to verify that AK used the 600 scale for partial hits by checking raid boss AoEs on players.

So, I'm having a really hard time finding differences between AK and Prathun's resist logic. Which is strange because Rashere went at considerable length to outline how he was modifying the resist system in 2006. But I also happened to find this:

https://www.shamanscrucible.com/foru...php?f=6&t=3083

Quote:
Originally Posted by Rashere
We're going to hold onto the resist changes for a bit longer. I really want to release them along with the ability to remove the resist cap, which we weren't able to get done during this cycle. There are some resist tweaks that will stay in place, mainly some of the NPC specific changes we made, but otherwise we're going to use the old resist system for now and then get this up on test where it can bake a bit more and be released along with the removal of the caps.
Quote:
Originally Posted by Rashere
The resist system we know and "love" is going to stay for launch. The NPC specific changes I'm talking about are tweaks we made to the resist values of specific NPCs that were gaining a bit of resists under the new system due to how it makes those with low resists able to resist spells a bit more often. I didn't want that affecting NPCs, just PCs (PCs with low resists get a boost under the new system), so we lowered their resists a bit to compensate. That's staying in put, which is a bit of an issue since it means they'll resist spells a bit less than they did before and when we do put the new system in, they'll be back where they should be...which of course wil be seen as a nerf. But its the lesser of two evils here.
So seemingly two days after telling the userbase that large modifications were coming to the resist system, he reverted it, said he would put it in later, then didn't. I also want to mention that I found considerable differences in the resist rates on Planes of Power NPCs on Live vs. what I see in AK logs. I can calculate a resist estimate using logs where AoE spells were employed (PBAoEs or wizards quadding) which provide a reasonable sample size. Mobs that have 50 resist on Live seemed to have about 65 resist on AK. I also found mobs that have 65 MR on Live having about 80-85 on AK. (e.g. PoFire flameheads) BoT minibosses (the level 65 ones) also resisted slow A LOT on AK, and their current 155 MR on Live is just too low to match AK logs. I had also done some crude MR tests on Diaku ogres on AK to find the best charm pet, and the results indicated higher MR on AK. (except for one which was oddly lower) Just about every mob I could check from AK logs showed higher resists on PoP NPCs, but I can only check a handful of NPCs because large samples are required. These NPCs could have been modified by Rashere in 2006.

Another thing I wanted to verify was Prathun's 200 roll. His Pseudocode says this:

Quote:
Originally Posted by Prathun
Roll a random number between 0 and 200.
If the roll is greater than the resist chance, spell lands.
If the roll is not greater than the resist chance and the spell does not allow partial resists, resist spell.
Is this roll 0-200? 1-200? 0-199? > or >=? This has sigifnicant implications for charm and root which I will outline in another post, so I wanted to know for sure.

Testing for this on Live servers is somewhat straightforward. Find mobs around 1 and 199 resist then do long parses on them, then compare to simulations.

Here is a level 65 wizard casting on level 61 NPCs which have 50 base MR, with Tashanian on them, resulting in an effective MR of 1:

Code:
A Crystalline Arachnae (level 61) : All-Or-Nothing resist mod: -8;  DD resist mod: -8

Lower Element I - 3801 casts
Full Hits: 3785 (99.5%)  Full Resists: 16 (0.4%)

Project Lightning - 1797 casts (53 critical)
Full Hits: 1797 (100%)  Hits: 1797 (100%)  Full Resists: 0 (0%)

----------------------------------------------------------------------
A Crystalline Crawler (level 61) : All-Or-Nothing resist mod: -8;  DD resist mod: -8

Project Lightning - 1310 casts (42 critical)
Full Hits: 1310 (100%)  Hits: 1310 (100%)  Full Resists: 0 (0%)

Now the same mobs with Wind of Tashanian, resulting in an effective MR of 2:

Code:
A Crystalline Arachnae (level 61) : All-Or-Nothing resist mod: -8;  DD resist mod: -8

Project Lightning - 1841 casts (60 critical)
Full Hits: 1833 (99.5%)  Hits: 1841 (100%)  Full Resists: 0 (0%)

----------------------------------------------------------------------
A Crystalline Crawler (level 61) : All-Or-Nothing resist mod: -8;  DD resist mod: -8

Project Lightning - 1315 casts (34 critical)
Full Hits: 1311 (99.6%)  Hits: 1315 (100%)  Full Resists: 0 (0%)

To produce those results, you have to roll 1 to X and use a >. That's the only way it works. If you try using a roll of 0 and a >=, it won't produce those results. (X being 200 or 199) Furthermore the partial resist formula doesn't work with zeros for the roll and resist value and you end up with a zero divided by zero if you use a greater-than operator. That can be easily handled in various ways but it's not mentioned in the Prathun pseudocode.

I do however have strong evidence to suggest that AK used a 0 to X roll instead of 1 to X. The charm data I have from AK logs is somewhat shorter in average duration than Live for starters. (I will outline that in another thread) But I also have that data from a level 59 cleric on AK casting AoE spells on level 51 NPCs that I mentioned previously; these NPCs having an effective resist value of 3 against the cleric. The cleric got 31 full resists and 12 partial hits in that level, with something like 2300 casts on level 51s. On Live servers which use a 1 roll, at 3 resist, the partials and full resists should both be 0.5% each at 3 resist value. If however you change the logic to roll from 0 instead of 1, the full resist rate goes to 1% while partials stay at 0.5%, as rolls of 0 and 1 result in full resists and a roll of 2 results in 50% damage. (this requires accounting for the divide by zero issue)

Incidentally I do recall wizards complaining in 1999 that Ice Comet could be fully resisted by a level 1 NPC. This actually makes sense if the following is true:

- The resist roll started at 0 and used a >
- The NPC's effective resist was prevented from going negative (seemingly no longer the case post Luclin)
- A zero roll results in a full resist vs. a target with 0 effective resist value like AK might have


Now, what about X? Is it 199 or 200? I can answer that for Live at least.

I parsed an Honorable Protector in HoHB, which likely has 235 MR. Then I parsed it twice:

Code:
Level 65 Wizard vs. An Honorable Protector (level 64) debuffed with Wind of Wind of Tashanian (-40 MR); effective MR = 195
Lower Element I - 20648 casts
Full Hits: 501 (2.4%)  Full Resists: 20147 (97.5%)


Level 66 Wizard vs. An Honorable Protector (level 64) debuffed with Mala (-35); effective MR = 198
Lower Element I - 16180 casts
Full Hits: 162 (1%)  Full Resists: 16018 (98.9%)
The results indicate X is 200 on Live. That's enough casts to rule out margin of error. Its MR could be 234 but I really doubt it.

TL;DR

- Live's resist roll is 1-200 and uses a > (extremely likely)
- AK's resist roll was either 0-200 or 0-199 and uses a > (very likely)
- Rashere's supposed resist changes in 2006 were very minor or non-existent and Prathun's pseudocode almost entirely applies to PoP era
- PoP NPCs (and perhaps GoD through Prophecy) had their resists modified at some point, probably in 2006 by Rashere
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 01:59 AM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3