From 02e291d4e878e81611b32827451f50dfa788a8d7 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 20 Mar 2014 00:53:49 -0400 Subject: [PATCH] Further refinements to root, charm, mez and fear behaviors. Updates to a few rule due to new/corrected parse data. All behaviors defined from weeks of extensive live parsing Root Break Chance from DD now will scale based on level difference. Root has a baseline aproximately 6% chance to break per check when target has at 0% chance to resist spells.(ie green cons 60 levels lower with tash). Fear has an approximately 70% chance to trigger a resist check each tick to determine if it will fade early. (no baseline break chance) Charisma less than 100, gives -20 resist mod to intial fear casts Charisma from 100 to 255 will progressively reduce this mod to 0. Charisma DOES NOT effect UNDEAD fears Charmisma less than 75 significantly increase CHARM/MEZ/LULL resist rates. Mez spells will now also use charisma resist check, as they do on live. --- changelog.txt | 6 ++ common/ruletypes.h | 7 +- common/spdat.cpp | 2 +- .../git/optional/2014_03_19_RulesUpdates.sql | 6 ++ zone/aggro.cpp | 2 +- zone/attack.cpp | 63 +++++++++-------- zone/mob.h | 4 +- zone/spell_effects.cpp | 20 +++++- zone/spells.cpp | 67 +++++++++++++++---- 9 files changed, 127 insertions(+), 50 deletions(-) create mode 100644 utils/sql/git/optional/2014_03_19_RulesUpdates.sql diff --git a/changelog.txt b/changelog.txt index 08fc5dd27..e2805115e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +Kayen: Further refinements to root, charm, mez and fear behaviors - See commit message for full details + +New rule for 'Fear' break chance, and updates to default settings of various rules. +Optional SQL: utils/sql/git/optional/2014_03_19_RulesUpdates.sql + + == 03/18/2014 == Uleat: Fixed the name/account discrepancy in the Client::SummonItem() code as well as the origin of the mistake (thanks K_K!) Uleat: Condensed and rearranged certain snippets of code in SummonItem(). Added a 'augslotvisible' check to validation check. diff --git a/common/ruletypes.h b/common/ruletypes.h index 83db6c3f0..fd50d1514 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -290,17 +290,18 @@ RULE_BOOL ( Spells, NPCIgnoreBaseImmunity, true) // Whether or not NPCs get to i RULE_REAL ( Spells, AvgSpellProcsPerMinute, 6.0) //Adjust rate for sympathetic spell procs RULE_INT ( Spells, ResistFalloff, 67) //Max that level that will adjust our resist chance based on level modifiers RULE_INT ( Spells, CharismaEffectiveness, 10) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. -RULE_INT ( Spells, CharismaEffectivenessCap, 200) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. +RULE_INT ( Spells, CharismaEffectivenessCap, 255) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. RULE_BOOL ( Spells, CharismaCharmDuration, false) // Allow CHA resist mod to extend charm duration. RULE_INT ( Spells, CharmBreakCheckChance, 25) //Determines chance for a charm break check to occur each buff tick. RULE_INT ( Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time can be reduced by spell haste -RULE_INT ( Spells, RootBreakFromSpells, 20) //Chance for root to break when cast on. +RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on. RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing. RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount. 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_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick. +RULE_INT ( Spells, FearBreakCheckChance, 70) //Determines chance for a fear break check to occur each buff tick. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/common/spdat.cpp b/common/spdat.cpp index 0f4387b83..c75acc056 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -390,7 +390,7 @@ bool IsPartialCapableSpell(uint16 spell_id) if (spells[spell_id].no_partial_resist) return false; - if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id)) + if (IsPureNukeSpell(spell_id)) return true; return false; diff --git a/utils/sql/git/optional/2014_03_19_RulesUpdates.sql b/utils/sql/git/optional/2014_03_19_RulesUpdates.sql new file mode 100644 index 000000000..d360528e6 --- /dev/null +++ b/utils/sql/git/optional/2014_03_19_RulesUpdates.sql @@ -0,0 +1,6 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:FearBreakCheckChance', '70', 'Chance for fear to do a resist check each tick. Decrease for longer fears.'); + +-- Updates rule value if server is using the OLD DEFAULT values +UPDATE rule_values SET rule_value = 55 WHERE rule_name LIKE 'Spells:RootBreakFromSpells' AND rule_value = 20; +UPDATE rule_values SET rule_value = 70 WHERE rule_name LIKE 'Spells:RootBreakCheckChance' AND rule_value = 40; +UPDATE rule_values SET rule_value = 255 WHERE rule_name LIKE 'Spells:CharismaResistCap' AND rule_value = 200; diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 71956a535..144f7363e 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1398,7 +1398,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { /* Charm formula is correct based on over 50 hours of personal live parsing - Kayen - Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 200 CHA + Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 255 CHA (min ~ 75 CHA) Charisma DOES NOT extend charm durations. Base effect value of charm spells in the spell file DOES NOT effect duration OR resist rate (unclear if does anything) Charm has a lower limit of 5% chance to break per tick, regardless of resist modifiers / level difference. diff --git a/zone/attack.cpp b/zone/attack.cpp index ccbc3a8f8..be099adc6 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3680,7 +3680,7 @@ 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 - TryRootFadeByDamage(buffslot); + TryRootFadeByDamage(buffslot, attacker); } else if(spell_id == SPELL_UNKNOWN) { @@ -4548,34 +4548,43 @@ 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. - */ - - /* General Mechanics - - 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. - */ - - if (!spellbonuses.Root[0] || spellbonuses.Root[1] < 0) - return false; - - if (IsDetrimentalSpell(spellbonuses.Root[1]) && spellbonuses.Root[1] != buffslot){ - - int BreakChance = RuleI(Spells, RootBreakFromSpells); +bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) { + + /*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. + + /* General Mechanics + - 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. + - Root break chance values obtained from live parses. + */ + + if (!attacker || !spellbonuses.Root[0] || spellbonuses.Root[1] < 0) + return false; + + if (IsDetrimentalSpell(spellbonuses.Root[1]) && spellbonuses.Root[1] != buffslot){ + + int BreakChance = RuleI(Spells, RootBreakFromSpells); - BreakChance -= BreakChance*buffs[spellbonuses.Root[1]].RootBreakChance/100; + BreakChance -= BreakChance*buffs[spellbonuses.Root[1]].RootBreakChance/100; + int level_diff = attacker->GetLevel() - GetLevel(); - if (BreakChance < 1) - BreakChance = 1; + //Use baseline if level difference <= 1 (ie. If target is (1) level less than you, or equal or greater level) + + if (level_diff == 2) + BreakChance = (BreakChance * 80) /100; //Decrease by 20%; + + else if (level_diff >= 3 && level_diff <= 20) + BreakChance = (BreakChance * 60) /100; //Decrease by 40%; + + else if (level_diff > 21) + BreakChance = (BreakChance * 20) /100; //Decrease by 80%; + + if (BreakChance < 1) + BreakChance = 1; if (MakeRandomInt(0, 99) < BreakChance) { diff --git a/zone/mob.h b/zone/mob.h index c771d57b7..c8453d301 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -191,7 +191,7 @@ public: virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration){ return duration;} virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false, - int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false); + int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false); uint16 GetSpecializeSkillValue(uint16 spell_id) const; void SendSpellBarDisable(); void SendSpellBarEnable(uint16 spellid); @@ -593,7 +593,7 @@ public: void MeleeLifeTap(int32 damage); bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true); bool ImprovedTaunt(); - bool TryRootFadeByDamage(int buffslot); + bool TryRootFadeByDamage(int buffslot, Mob* attacker); 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 cebd548dd..7fd2f4332 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -830,14 +830,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Fear: %+i", effect_value); #endif - //use resistance value for duration... - buffs[buffslot].ticsremaining = ((buffs[buffslot].ticsremaining * partial) / 100); - if(IsClient()) { if(buffs[buffslot].ticsremaining > RuleI(Character, MaxFearDurationForPlayerCharacter)) buffs[buffslot].ticsremaining = RuleI(Character, MaxFearDurationForPlayerCharacter); } + if(RuleB(Combat, EnableFearPathing)){ if(IsClient()) @@ -3327,6 +3325,22 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste if (MakeRandomInt(0, 99) < RuleI(Spells, RootBreakCheckChance)){ + float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, 0,0,0,0,true); + + if(resist_check == 100) + break; + else + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); + } + + break; + } + + case SE_Fear: + { + if (MakeRandomInt(0, 99) < RuleI(Spells, FearBreakCheckChance)){ + float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster); if(resist_check == 100) diff --git a/zone/spells.cpp b/zone/spells.cpp index 332906883..86d21ea7a 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3409,7 +3409,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r // not all unresistable, so changing this to only check certain spells if(IsResistableSpell(spell_id)) { - if (IsCharmSpell(spell_id)) + if (IsCharmSpell(spell_id) || IsMezSpell(spell_id) || IsFearSpell(spell_id)) spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust,true); else spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust); @@ -4040,7 +4040,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) // pvp_resist_base // pvp_resist_calc // pvp_resist_cap -float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick) +float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot) { if(!caster) @@ -4079,8 +4079,10 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } //Check for fear resist + bool IsFear = false; if(IsFearSpell(spell_id)) { + IsFear = true; int fear_resist_bonuses = CalcFearResistChance(); if(MakeRandomInt(0, 99) < fear_resist_bonuses) { @@ -4089,7 +4091,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } } - if (!CharismaCheck){ + if (!CharmTick){ //Check for Spell Effect specific resistance chances (ie AA Mental Fortitude) int se_resist_bonuses = GetSpellEffectResistChance(spell_id); @@ -4232,15 +4234,38 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if (CharismaCheck) { - //Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 200 CHA - //'Lull' spells only check charisma if inital cast is resisted to see if mob will aggro, same modifier/cap as above. - //Charisma DOES NOT extend charm durations. + /* + Charisma ONLY effects the initial resist check when charm is cast with 10 CHA = -1 Resist mod up to 255 CHA (min ~ 75 cha) + Charisma less than ~ 75 gives a postive modifier to resist checks at approximate ratio of -10 CHA = +6 Resist. + Mez spells do same initial resist check as a above. + Lull spells only check charisma if inital cast is resisted to see if mob will aggro, same modifier/cap as above. + Charisma DOES NOT extend charm durations. + Fear resist chance is given a -20 resist modifier if CHA is < 100, from 100-255 it progressively reduces the negative mod to 0. + Fears verse undead DO NOT apply a charisma modifer. (Note: unknown Base1 values defined in undead fears do not effect duration). + */ int16 charisma = caster->GetCHA(); - if (charisma > RuleI(Spells, CharismaEffectivenessCap)) - charisma = RuleI(Spells, CharismaEffectivenessCap); + if (IsFear && (spells[spell_id].targettype != 10)){ - resist_modifier -= charisma/RuleI(Spells, CharismaEffectiveness); + if (charisma < 100) + resist_modifier -= 20; + + else if (charisma <= 255) + resist_modifier += (charisma - 100)/8; + } + + else { + + if (charisma >= 75){ + + if (charisma > RuleI(Spells, CharismaEffectivenessCap)) + charisma = RuleI(Spells, CharismaEffectivenessCap); + + resist_modifier -= (charisma - 75)/RuleI(Spells, CharismaEffectiveness); + } + else + resist_modifier += ((75 - charisma)/10) * 6; //Increase Resist Chance + } } //Lull spells DO NOT use regular resists on initial cast, instead they use a flat +15 modifier. Live parses confirm this. @@ -4266,10 +4291,26 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use resist_chance = spells[spell_id].MinResist; } - //Charm can not have less than 5% chance to fail. - if (CharmTick && (resist_chance < 10)) - resist_chance = 10; - + //Average charm duration agianst mobs with 0% chance to resist on LIVE is ~ 68 ticks. + //Minimum resist chance should be caclulated factoring in the RuleI(Spells, CharmBreakCheckChance) + if (CharmTick) { + + int min_charmbreakchance = ((100/RuleI(Spells, CharmBreakCheckChance))/66 * 100)*2; + + if (resist_chance < min_charmbreakchance) + resist_chance = min_charmbreakchance; + } + + //Average root duration agianst mobs with 0% chance to resist on LIVE is ~ 22 ticks (6% resist chance). + //Minimum resist chance should be caclulated factoring in the RuleI(Spells, RootBreakCheckChance) + if (IsRoot) { + + int min_rootbreakchance = ((100/RuleI(Spells, RootBreakCheckChance))/22 * 100)*2; + + if (resist_chance < min_rootbreakchance) + resist_chance = min_rootbreakchance; + } + //Finally our roll int roll = MakeRandomInt(0, 200); if(roll > resist_chance)