diff --git a/changelog.txt b/changelog.txt index ab4ef1edd..1d46228f5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,14 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 03/04/2014 == +Kayen: Revision to root code to be consistent with live based on extensive personal parsing. +*ROOT has a 40% chance to do a resist check to break each buff tick. +*If multiple roots on target. Root in first slot will always and only be check to break from nukes. +*If multiple roots on target and broken by spell. Roots are removed ONE at a time in order of buff slot. +*Roots on beneficial spells can not be broken by spell damage. + +Optional SQL: utils/sql/git/optional/2014_03_04_RootRule.sql + == 03/03/2014 == demonstar55: Implemented deadly strikes and gave rogues higher innate throwing crit chance diff --git a/common/ruletypes.h b/common/ruletypes.h index 3b1e5ca44..83324d533 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -300,6 +300,7 @@ RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amou RULE_BOOL ( Spells, AdditiveBonusValues, false) //Allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. (ie Add together all Cleave Effects) RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this? RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live +RULE_INT ( Spells, RootBreakCheckChance, 40) //Determines chance for a root break check to occur each buff tick. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/common/spdat.cpp b/common/spdat.cpp index 04af27424..0f4387b83 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -390,8 +390,7 @@ bool IsPartialCapableSpell(uint16 spell_id) if (spells[spell_id].no_partial_resist) return false; - if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id) || - IsEffectInSpell(spell_id, SE_Root)) + if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id)) return true; return false; diff --git a/zone/attack.cpp b/zone/attack.cpp index 3316c3eb3..594961c7c 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3685,29 +3685,8 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons if(spell_id != SPELL_UNKNOWN && !iBuffTic) { //see if root will break - if (IsRooted() && !FromDamageShield) { // neotoyko: only spells cancel root - - /*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443 - The Viscid Roots AA does the following: Reduces the chance for root to break by X percent. - There is no distinction of any kind between the caster inflicted damage, or anyone - else's damage. There is also no distinction between Direct and DOT damage in the root code. - There is however, a provision that if the damage inflicted is greater than 500 per hit, the - chance to break root is increased. My guess is when this code was put in place, the devs at - the time couldn't imagine DOT damage getting that high. - */ - int BreakChance = RuleI(Spells, RootBreakFromSpells); - BreakChance -= BreakChance*rooted_mod/100; - - if (BreakChance < 1) - BreakChance = 1; - - if (MakeRandomInt(0, 99) < BreakChance) { - mlog(COMBAT__HITS, "Spell broke root! BreakChance percent chance"); - BuffFadeByEffect(SE_Root, buffslot); // buff slot is passed through so a root w/ dam doesnt cancel itself - } else { - mlog(COMBAT__HITS, "Spell did not break root. BreakChance percent chance"); - } - } + if (IsRooted() && !FromDamageShield) // neotoyko: only spells cancel root + TryRootFadeByDamage(buffslot); } else if(spell_id == SPELL_UNKNOWN) { @@ -4575,6 +4554,50 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) } } +bool Mob::TryRootFadeByDamage(int buffslot) +{ + /*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443 + The Viscid Roots AA does the following: Reduces the chance for root to break by X percent. + There is no distinction of any kind between the caster inflicted damage, or anyone + else's damage. There is also no distinction between Direct and DOT damage in the root code. + There is however, a provision that if the damage inflicted is greater than 500 per hit, the + chance to break root is increased. My guess is when this code was put in place, the devs at + the time couldn't imagine DOT damage getting that high. + */ + + int BreakChance = RuleI(Spells, RootBreakFromSpells); + + BreakChance -= BreakChance*rooted_mod/100; + + if (BreakChance < 1) + BreakChance = 1; + + if (MakeRandomInt(0, 99) < BreakChance) { + + /* + - Check buffslot to make sure damage from a root does not cancel the root + - If multiple roots on target, always and only checks first root slot and if broken only removes that slots root. + - Only roots on determental spells can be broken by damage. + */ + + uint32 buff_count = GetMaxTotalSlots(); + for(int i = 0; i < buff_count; i++) + { + if(IsValidSpell(buffs[i].spellid) && + (IsEffectInSpell(buffs[i].spellid, SE_Root) && IsDetrimentalSpell(buffs[i].spellid) && i != buffslot)){ + if (!TryFadeEffect(i)) { + BuffFadeBySlot(i); + mlog(COMBAT__HITS, "Spell broke root! BreakChance percent chance"); + return true; + } + } + } + } + + mlog(COMBAT__HITS, "Spell did not break root. BreakChance percent chance"); + return false; +} + int32 Mob::RuneAbsorb(int32 damage, uint16 type) { uint32 buff_max = GetMaxTotalSlots(); diff --git a/zone/mob.h b/zone/mob.h index c9f1aa299..723f868cf 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -600,6 +600,7 @@ public: void MeleeLifeTap(int32 damage); bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true); bool ImprovedTaunt(); + bool TryRootFadeByDamage(int buffslot); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2f73b915c..f01476779 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3322,9 +3322,23 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste } case SE_Root: { - float SpellEffectiveness = ResistSpell(spells[spell_id].resisttype, spell_id, caster); - if(SpellEffectiveness < 25) { - BuffFadeByEffect(SE_Root); + + /* Root formula derived from extensive personal live parses - Kayen + ROOT has a 40% chance to do a resist check to break. + Resist check has NO LOWER bounds. + If multiple roots on target. Root in first slot will be checked first to break from nukes. + If multiple roots on target and broken by spell. Roots are removed ONE at a time in order of buff slot. + */ + + if (MakeRandomInt(0, 99) < RuleI(Spells, RootBreakCheckChance)){ + + float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster); + + if(resist_check == 100) + break; + else + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); } break;