diff --git a/changelog.txt b/changelog.txt index 0be0e4687..2d53f202c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,22 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 01/13/2014 == +Kayen: Numerous minor fixes to spell effects. +Kayen: Changed SE_ArcheryDoubleAttack -> SE_DoubleRangedAttack (now works with throwing ect) +Kayen: Changed SE_IncreaseHitDmgTaken -> SE_TriggerMeleeThreshold (now only works on melee) +Kayen: Changed SE_MitigateMeleeDamageSP -> SE_MeleeThresholdGuard +Kayen: Implemented SE_SpellThresholdGuard (Partial Spell Rune that only is lowered if spell hits are over X amount of damage) +Kayen: Implemented SE_TriggerSpellThreshold (implemented Trigger effect on X amount of spell damage taken) +Kayen: Changed SE_ReduceHealing -> SE_FcHealAmtIncoming (focus limited Add/Remove amount of healing on target by X amount) +Kayen: Change SE_CriticalHealChance2 -> SE_CriticalHealDecay +Kayen: Change SE_CriticalHealOverTime2 -> SE_CriticalRegenDecay +Kayen: Implemented SE_CriticalDotDecay +Note: 'Decay' effects means the chance to critical decays based on the level of the spell using the effect (like focus decay) +Kayen: Implemented SE_FfLimitUseMin (focus limit to require a min amount of numhits value) +Kayen: Implemented SE_FcLimitUse (focus to increases numhits count by percent) +Kayen: Implemented SE_LimitRace (Limits to spells cast by a certain race) +Kayen: Implemented SE_FcMute (silences casting of spells that contain specific spell effects) ie silence only heals + == 01/09/2014 == demonstar55: Add pet size preservation like live (zone, camp, etc) diff --git a/common/spdat.h b/common/spdat.h index 0dfc202db..e39ea22c2 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -493,7 +493,7 @@ typedef enum { #define SE_ChannelChanceItems 344 // implemented[AA] - chance to not have ITEM effects interrupted when you take damage. #define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill #define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill -#define SE_ArcheryDoubleAttack 347 // implemented - chance at an additional archery attack (consumes arrow) +#define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow) #define SE_LimitManaCost 348 // implemented #define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield. #define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana. @@ -503,7 +503,7 @@ typedef enum { //#define SE_DeactivateAllTraps 354 // *not implemented - looks to be some type of invulnerability? Test DAT (8757) //#define SE_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758) //#define SE_ChangeTriggerType 356 // not used -#define SE_InhibitSpellCasting 357 // *not implemented - (Stunted Growth 31160) Unlcear what this effect does? silence? +#define SE_FcMute 357 // implemented - silences casting of spells that contain specific spell effects (focus limited) #define SE_CurrentManaOnce 358 // implemented #define SE_Invulnerabilty 359 // *not implemented - Invulnerability (Brell's Blessing) #define SE_SpellOnKill 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level @@ -540,7 +540,7 @@ typedef enum { #define SE_IncreaseHitDmgTaken 391 // implemented - Most likely a simple negative mitigation modifier (Warlords fury: 23528) #define SE_AdditionalHeal2 392 // implemented - Adds or removes healing from spells #define SE_HealRate2 393 // implemented - HealRate with focus restrictions. -#define SE_ReduceHeal 394 // implemented - Reduces amount of healing on target by X value with foucs restrictions. +#define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. #define SE_CriticalHealRate 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] #define SE_AdditionalHeal 396 // implemented - Adds a direct healing amount to spells #define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. @@ -549,7 +549,7 @@ typedef enum { #define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained #define SE_ManaDrainWithDmg 401 // implemented - Deals damage based on the amount of mana drained #define SE_EndDrainWithDmg 402 // implemented - Deals damage for the amount of endurance drained -#define SE_TriggerOnCast2 403 // *not implemented - trigger a spell with percent chance, focus limited. +#define SE_Ff_SpellClass 403 // *not implemented - #define SE_LimitExcludeSkill 404 // implemented - Limit a focus to exclude spells cast using a specific skill. #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted @@ -558,7 +558,7 @@ typedef enum { #define SE_LimitManaPercent 409 // implemented - limited to a certain percent of your mana #define SE_LimitEndPercent 410 // implemented - limited to a certain percent of your end #define SE_LimitClass 411 // implemented - Limits to spells of a certain class (Note: The class value in dbase is +1 in relation to item class value) -//#define SE_FfRace 412 // not used +#define SE_LimitRace 412 // implemented - Limits to spells cast by a certain race (Note: not used in any known live spells) #define SE_IncreaseSpellPower 413 // implemented - Increases the power of bard songs, skill attacks, runes, bard allowed foci, damage/heal #define SE_LimitSpellSkill 414 // implemented - Limit a focus to include spells cast using a specific skill. //#define SE_FFItemClass 415 // not used @@ -566,10 +566,10 @@ typedef enum { #define SE_ManaRegen_v2 417 // implemented - New mana regen effect #define SE_SkillDamageAmount2 418 // implemented - adds skill damage directly to certain attacks #define SE_AddMeleeProc 419 // implemented - Adds a proc -//#define SE_FcLimitUse 420 // *not used +#define SE_FcLimitUse 420 // implemented - increases numhits count by percent (Note: not used in any known live spells) #define SE_IncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus) -//#define SE_FfLimitUseMin 422 // not used - Seen in Lasting Bravery[AA] likely a focus limit -//#define SE_FfLimitUseType 423 // not used - Seen in Lasting Bravery[AA] likely a focus limit +#define SE_FfLimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) +//#define SE_FfLimitUseType 423 // not used - limit a focus to require a certain numhits type (Field in spells table 175) #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace #define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) #define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window @@ -579,28 +579,28 @@ typedef enum { //#define SE_PostEffect 430 // *not implemented - Fear of the Dark(27641) - Alters vision //#define SE_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision //#define SE_ExpandMaxActiveTrophyBen 432 // not used -//#define SE_CriticalDotDecay 433 // not used (12266 | Placeholder - Test - New Dot Only) -#define SE_CriticalHealChance2 434 // implemented - increase critical heal chance -#define SE_CriticalHealOverTime2 435 // implemented - increase critical heal over time chance +#define SE_CriticalDotDecay 433 // implemented - increase critical dot chance, effect decays based on level of spell it effects. (12266) +#define SE_CriticalHealDecay 434 // implemented - increase critical heal chance, effect decays based on level of spell it effects. +#define SE_CriticalRegenDecay 435 // implemented - increase critical heal over time chance, effect decays based on level of spell it effects. //#define SE_BeneficialCountDownHold 436 // not used ( 23491 | ABTest Buff Hold) -#define SE_Anchor 437 // *not implemented - Teleport Guild Hall Anchor(33099) -#define SE_Anchor2 438 // *not implemented - Translocate Primary Anchor (27750) +#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099) +#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750) #define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination #define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC #define SE_CancleIfMoved 441 // *not implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. #define SE_TriggerOnValueAmount 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_TriggerIfMovement 443 // *not implemented - Trigger a spell if you move (37846 | Chopping Block) -#define SE_AggroLock 444 // *not implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% up to level Z -#define SE_AdditionalMercenary 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. +#define SE_ImprovedTaunt 444 // *not implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% up to level Z +#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. //#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch) //#define SE_BStacker 447 // *not implemented //#define SE_CStacker 448 // *not implemented //#define SE_DStacker 449 // *not implemented //#define SE_DotGuard 450 // *not implemented -#define SE_MitigateMeleeDamageSP 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage -//#define SE_SpellThresholdGuard 452 // *not implemented -#define SE_SpellOnAmtDmgTaken 453 // implemented Trigger effect on X amount of damage taken -//#define SE_DoomSpellThreshold 454 // not used +#define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage +#define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage +#define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken +#define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken //#define SE_AddHatePct 455 // not used //#define SE_AddHateOverTimePct 456 // not used //#define SE_ResourceTap 457 // not used @@ -694,7 +694,7 @@ struct SPDat_Spell_Struct /* 169 */ /* 173 */ int HateAdded; /* 174 */ int EndurUpkeep; -/* 175 */ +/* 175 */ //numhitstype; // defines which type of behavior will tick down the numhit counter. /* 176 */ int numhits; /* 177 */ int pvpresistbase; /* 178 */ int pvpresistcalc; diff --git a/zone/attack.cpp b/zone/attack.cpp index 7f17d5fc3..aa30557be 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3116,29 +3116,6 @@ int Mob::GetMonkHandToHandDelay(void) } } -int32 Mob::ReduceAllDamage(int32 damage) -{ - if(damage <= 0) - return damage; - - int32 slot = -1; - - if (spellbonuses.SpellOnAmtDmgTaken[2]){ - slot = spellbonuses.SpellOnAmtDmgTaken[1]; - - if (slot >= 0) { - if(damage > buffs[slot].melee_rune) { - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot); - } - else{ - buffs[slot].melee_rune = (buffs[slot].melee_rune - damage); - CheckHitsRemaining(slot); - } - } - } - return(damage); -} int32 Mob::ReduceDamage(int32 damage) { @@ -3157,16 +3134,16 @@ int32 Mob::ReduceDamage(int32 damage) } //Only mitigate if damage is above the minimium specified. - if (spellbonuses.MitigateMeleeRuneSP[0]){ - slot = spellbonuses.MitigateMeleeRuneSP[1]; + if (spellbonuses.MeleeThresholdGuard[0]){ + slot = spellbonuses.MeleeThresholdGuard[1]; - if (slot >= 0 && (damage > spellbonuses.MitigateMeleeRuneSP[2])) + if (slot >= 0 && (damage > spellbonuses.MeleeThresholdGuard[2])) { DisableMeleeRune = true; - int damage_to_reduce = damage * spellbonuses.MitigateMeleeRuneSP[0] / 100; + int damage_to_reduce = damage * spellbonuses.MeleeThresholdGuard[0] / 100; if(damage_to_reduce > buffs[slot].melee_rune) { - mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamageSP %d damage negated, %d" + mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MeleeThresholdGuard %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); damage -= damage_to_reduce; if(!TryFadeEffect(slot)) @@ -3175,7 +3152,7 @@ int32 Mob::ReduceDamage(int32 damage) } else { - mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamageSP %d damage negated, %d" + mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MeleeThresholdGuard %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); damage -= damage_to_reduce; @@ -3211,6 +3188,21 @@ int32 Mob::ReduceDamage(int32 damage) } } + if (spellbonuses.TriggerMeleeThreshold[2]){ + slot = spellbonuses.TriggerMeleeThreshold[1]; + + if (slot >= 0) { + if(damage > buffs[slot].melee_rune) { + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); + } + else{ + buffs[slot].melee_rune = (buffs[slot].melee_rune - damage); + CheckHitsRemaining(slot); + } + } + } + if(damage < 1) return -6; @@ -3238,6 +3230,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(damage <= 0) return damage; + bool DisableSpellRune = false; int32 slot = -1; // See if we block the spell outright first @@ -3259,8 +3252,34 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi // Reduce damage by the Spell Shielding first so that the runes don't take the raw damage. damage -= (damage * itembonuses.SpellShield / 100); + + //Only mitigate if damage is above the minimium specified. + if (spellbonuses.SpellThresholdGuard[0]){ + slot = spellbonuses.SpellThresholdGuard[1]; + + if (slot >= 0 && (damage > spellbonuses.MeleeThresholdGuard[2])) + { + DisableSpellRune = true; + int damage_to_reduce = damage * spellbonuses.SpellThresholdGuard[0] / 100; + if(damage_to_reduce > buffs[slot].magic_rune) + { + damage -= damage_to_reduce; + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); + //UpdateRuneFlags(); + } + else + { + buffs[slot].melee_rune = (buffs[slot].magic_rune - damage_to_reduce); + damage -= damage_to_reduce; + CheckHitsRemaining(slot); + } + } + } + + // Do runes now. - if (spellbonuses.MitigateSpellRune[0]){ + if (spellbonuses.MitigateSpellRune[0] && !DisableSpellRune){ slot = spellbonuses.MitigateSpellRune[1]; if(slot >= 0) { @@ -3286,6 +3305,21 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi } } + if (spellbonuses.TriggerSpellThreshold[2]){ + slot = spellbonuses.TriggerSpellThreshold[1]; + + if (slot >= 0) { + if(damage > buffs[slot].magic_rune) { + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); + } + else{ + buffs[slot].melee_rune = (buffs[slot].magic_rune - damage); + CheckHitsRemaining(slot); + } + } + } + if(damage < 1) return 0; @@ -3378,9 +3412,9 @@ bool Client::CheckDoubleAttack(bool tripleAttack) { return false; } -bool Client::CheckArcheryDoubleAttack() { +bool Client::CheckDoubleRangedAttack() { - int16 chance = spellbonuses.ArcheryDoubleAttack + itembonuses.ArcheryDoubleAttack + aabonuses.ArcheryDoubleAttack; + int16 chance = spellbonuses.DoubleRangedAttack + itembonuses.DoubleRangedAttack + aabonuses.DoubleRangedAttack; if(chance && (MakeRandomInt(0, 100) < chance)) return true; @@ -3493,7 +3527,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } //final damage has been determined. - ReduceAllDamage(damage); SetHP(GetHP() - damage); if(HasDied()) { diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 7bf88a215..bbb55f989 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -851,8 +851,8 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_ArcheryDamageModifier: newbon->ArcheryDamageModifier += base1; break; - case SE_ArcheryDoubleAttack: - newbon->ArcheryDoubleAttack += base1; + case SE_DoubleRangedAttack: + newbon->DoubleRangedAttack += base1; break; case SE_DamageShield: newbon->DamageShield += base1; @@ -1982,16 +1982,26 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->DotCritDmgIncrease += effect_value; break; - case SE_CriticalHealChance2: case SE_CriticalHealChance: newbon->CriticalHealChance += effect_value; break; - case SE_CriticalHealOverTime2: case SE_CriticalHealOverTime: newbon->CriticalHealOverTime += effect_value; break; + case SE_CriticalHealDecay: + newbon->CriticalHealDecay = true; + break; + + case SE_CriticalRegenDecay: + newbon->CriticalRegenDecay = true; + break; + + case SE_CriticalDotDecay: + newbon->CriticalDotDecay = true; + break; + case SE_MitigateDamageShield: { if (effect_value < 0) @@ -2173,12 +2183,22 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } - case SE_MitigateMeleeDamageSP: + case SE_MeleeThresholdGuard: { - if (newbon->MitigateMeleeRuneSP[0] < effect_value){ - newbon->MitigateMeleeRuneSP[0] = effect_value; - newbon->MitigateMeleeRuneSP[1] = buffslot; - newbon->MitigateMeleeRuneSP[2] = spells[spell_id].base2[i]; + if (newbon->MeleeThresholdGuard[0] < effect_value){ + newbon->MeleeThresholdGuard[0] = effect_value; + newbon->MeleeThresholdGuard[1] = buffslot; + newbon->MeleeThresholdGuard[2] = spells[spell_id].base2[i]; + } + break; + } + + case SE_SpellThresholdGuard: + { + if (newbon->SpellThresholdGuard[0] < effect_value){ + newbon->SpellThresholdGuard[0] = effect_value; + newbon->SpellThresholdGuard[1] = buffslot; + newbon->SpellThresholdGuard[2] = spells[spell_id].base2[i]; } break; } @@ -2201,12 +2221,22 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } - case SE_SpellOnAmtDmgTaken: + case SE_TriggerMeleeThreshold: { - if (newbon->SpellOnAmtDmgTaken[2] < spells[spell_id].base2[i]){ - newbon->SpellOnAmtDmgTaken[0] = effect_value; - newbon->SpellOnAmtDmgTaken[1] = buffslot; - newbon->SpellOnAmtDmgTaken[2] = spells[spell_id].base2[i]; + if (newbon->TriggerMeleeThreshold[2] < spells[spell_id].base2[i]){ + newbon->TriggerMeleeThreshold[0] = effect_value; + newbon->TriggerMeleeThreshold[1] = buffslot; + newbon->TriggerMeleeThreshold[2] = spells[spell_id].base2[i]; + } + break; + } + + case SE_TriggerSpellThreshold: + { + if (newbon->TriggerSpellThreshold[2] < spells[spell_id].base2[i]){ + newbon->TriggerSpellThreshold[0] = effect_value; + newbon->TriggerSpellThreshold[1] = buffslot; + newbon->TriggerSpellThreshold[2] = spells[spell_id].base2[i]; } break; } @@ -2285,8 +2315,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->ArcheryDamageModifier += effect_value; break; - case SE_ArcheryDoubleAttack: - newbon->ArcheryDoubleAttack += effect_value; + case SE_DoubleRangedAttack: + newbon->DoubleRangedAttack += effect_value; break; case SE_SecondaryDmgInc: @@ -2732,14 +2762,18 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff return focusImprovedDamage2; case SE_Empathy: return focusAdditionalDamage; - case SE_ReduceHeal: - return focusReduceHeal; + case SE_FcHealAmtIncoming: + return focusFcHealAmtIncoming; case SE_HealRate2: return focusHealRate; case SE_IncreaseSpellPower: return focusSpellEffectiveness; case SE_IncreaseNumHits: return focusIncreaseNumHits; + case SE_FcLimitUse: + return focusFcLimitUse; + case SE_FcMute: + return focusFcMute; case SE_CriticalHealRate: return focusCriticalHealRate; case SE_AdditionalHeal2: @@ -3318,14 +3352,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.DotCritDmgIncrease = effect_value; break; - case SE_CriticalHealChance2: case SE_CriticalHealChance: spellbonuses.CriticalHealChance = effect_value; aabonuses.CriticalHealChance = effect_value; itembonuses.CriticalHealChance = effect_value; break; - case SE_CriticalHealOverTime2: case SE_CriticalHealOverTime: spellbonuses.CriticalHealOverTime = effect_value; aabonuses.CriticalHealOverTime = effect_value; @@ -3458,10 +3490,16 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.MitigateMeleeRune[1] = -1; break; - case SE_MitigateMeleeDamageSP: - spellbonuses.MitigateMeleeRuneSP[0] = effect_value; - spellbonuses.MitigateMeleeRuneSP[1] = -1; - spellbonuses.MitigateMeleeRuneSP[1] = effect_value; + case SE_MeleeThresholdGuard: + spellbonuses.MeleeThresholdGuard[0] = effect_value; + spellbonuses.MeleeThresholdGuard[1] = -1; + spellbonuses.MeleeThresholdGuard[1] = effect_value; + break; + + case SE_SpellThresholdGuard: + spellbonuses.SpellThresholdGuard[0] = effect_value; + spellbonuses.SpellThresholdGuard[1] = -1; + spellbonuses.SpellThresholdGuard[1] = effect_value; break; case SE_MitigateSpellDamage: @@ -3698,10 +3736,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.SlayUndead[1] = effect_value; break; - case SE_ArcheryDoubleAttack: - spellbonuses.ArcheryDoubleAttack = effect_value; - aabonuses.ArcheryDoubleAttack = effect_value; - itembonuses.ArcheryDoubleAttack = effect_value; + case SE_DoubleRangedAttack: + spellbonuses.DoubleRangedAttack = effect_value; + aabonuses.DoubleRangedAttack = effect_value; + itembonuses.DoubleRangedAttack = effect_value; break; case SE_ShieldEquipHateMod: @@ -3718,6 +3756,19 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.ShieldEquipDmgMod[0] = effect_value; itembonuses.ShieldEquipDmgMod[1] = effect_value; break; + + case SE_TriggerMeleeThreshold: + spellbonuses.TriggerMeleeThreshold[0] = effect_value; + spellbonuses.TriggerMeleeThreshold[1] = effect_value; + spellbonuses.TriggerMeleeThreshold[2] = effect_value; + break; + + case SE_TriggerSpellThreshold: + spellbonuses.TriggerSpellThreshold[0] = effect_value; + spellbonuses.TriggerSpellThreshold[1] = effect_value; + spellbonuses.TriggerSpellThreshold[2] = effect_value; + break; + } } } diff --git a/zone/client.h b/zone/client.h index 9d28d77a2..b26987eec 100644 --- a/zone/client.h +++ b/zone/client.h @@ -819,7 +819,7 @@ public: void LinkDead(); void Insight(uint32 t_id); bool CheckDoubleAttack(bool tripleAttack = false); - bool CheckArcheryDoubleAttack(); + bool CheckDoubleRangedAttack(); //remove charges/multiple objects from inventory: //bool DecreaseByType(uint32 type, uint8 amt); @@ -830,7 +830,7 @@ public: void RemoveDuplicateLore(bool client_update = true); void MoveSlotNotAllowed(bool client_update = true); virtual void RangedAttack(Mob* other, bool CanDoubleAttack = false); - virtual void ThrowingAttack(Mob* other); + virtual void ThrowingAttack(Mob* other, bool CanDoubleAttack = false); void DoClassAttacks(Mob *ca_target, uint16 skill = -1, bool IsRiposte=false); void SetZoneFlag(uint32 zone_id); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 4934ab19e..4a8de6146 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -303,7 +303,7 @@ bool Client::Process() { if(CheckLosFN(GetTarget())){ //client has built in los check, but auto fire does not.. done last. RangedAttack(GetTarget()); - if (CheckArcheryDoubleAttack()) + if (CheckDoubleRangedAttack()) RangedAttack(GetTarget(), true); } else diff --git a/zone/common.h b/zone/common.h index be9ce79f4..4dfb229d7 100644 --- a/zone/common.h +++ b/zone/common.h @@ -73,9 +73,11 @@ typedef enum { //focus types focusBlockNextSpell, focusHealRate, focusAdditionalDamage, - focusReduceHeal, + focusFcHealAmtIncoming, focusSpellEffectiveness, focusIncreaseNumHits, + focusFcLimitUse, + focusFcMute, focusCriticalHealRate, focusAdditionalHeal2, focusAdditionalHeal, @@ -251,7 +253,7 @@ struct StatBonuses { int16 DualWieldChance; //i int16 DoubleAttackChance; //i int16 TripleAttackChance; //i - int16 ArcheryDoubleAttack; //i + int16 DoubleRangedAttack; //i int16 ResistSpellChance; //i int16 ResistFearChance; //i bool Fearless; //i @@ -310,12 +312,17 @@ struct StatBonuses { int16 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage uint16 NegateAttacks[2]; // 0 = bool HasEffect 1 = Buff Slot uint16 MitigateMeleeRune[2]; // 0 = Mitigation value 1 = Buff Slot - uint16 MitigateMeleeRuneSP[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. + uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. + uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 MitigateSpellRune[2]; // 0 = Mitigation value 1 = Buff Slot - uint32 SpellOnAmtDmgTaken[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger + uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger + uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot int16 ShieldBlock; // Chance to Shield Block int16 BlockBehind; // Chance to Block Behind (with our without shield) + bool CriticalRegenDecay; // increase critical regen chance, decays based on spell level cast + bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast + bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast //bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect //bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect diff --git a/zone/effects.cpp b/zone/effects.cpp index 6760bef05..87b8f3742 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -205,6 +205,9 @@ int32 Client::GetActDoTDamage(uint16 spell_id, int32 value) { if (GetClass() == NECROMANCER && critChance > 0) critChance += 5; + if (spellbonuses.CriticalDotDecay) + critChance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); + if (critChance > 0){ if (MakeRandomInt(0, 99) < critChance){ modifier += modifier*ratio/100; @@ -237,7 +240,7 @@ int32 Client::Additional_Heal(uint16 spell_id) heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt -= GetFocusEffect(focusReduceHeal, spell_id); + heal_amt -= GetFocusEffect(focusFcHealAmtIncoming, spell_id); if (heal_amt){ int duration = CalcBuffDuration(this, this, spell_id); @@ -275,6 +278,9 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) { //Live AA - Healing Gift, Theft of Life chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); if(MakeRandomInt(0,99) < chance) { entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2)); @@ -286,7 +292,11 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) { } // Hots else { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + chance += itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + if (spellbonuses.CriticalRegenDecay) + chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + if(MakeRandomInt(0,99) < chance) return ((value * modifier / 50) + heal_amt*2); } diff --git a/zone/merc.cpp b/zone/merc.cpp index e9e56b64d..82b4c7894 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -2868,7 +2868,7 @@ int32 Merc::Additional_Heal(uint16 spell_id) heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id); heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id); - heal_amt -= GetFocusEffect(focusReduceHeal, spell_id); + heal_amt += GetFocusEffect(focusFcHealAmtIncoming, spell_id); if (heal_amt){ int duration = CalcBuffDuration(this, this, spell_id); diff --git a/zone/mob.cpp b/zone/mob.cpp index d0c12586b..01146a4a2 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3458,7 +3458,7 @@ bool Mob::TryFadeEffect(int slot) for(int i = 0; i < EFFECT_COUNT; i++) { if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnWearoff || spells[buffs[slot].spellid].effectid[i] == SE_EffectOnFade - || spells[buffs[slot].spellid].effectid[i] == SE_SpellOnAmtDmgTaken) + || spells[buffs[slot].spellid].effectid[i] == SE_TriggerMeleeThreshold) { uint16 spell_id = spells[buffs[slot].spellid].base[i]; BuffFadeBySlot(slot); @@ -4611,10 +4611,10 @@ int Mob::SlowMitigation(bool slow_msg, Mob *caster, int slow_value) if ((int_slow_mitigation > 0.0f) && (int_slow_mitigation < 26.0f)) caster->Message(262, "Your spell was mostly successful"); - else if ((int_slow_mitigation > 26.0f) && (int_slow_mitigation < 74.0f)) + else if ((int_slow_mitigation >= 26.0f) && (int_slow_mitigation < 74.0f)) caster->Message(262, "Your spell was partially successful"); - else if ((int_slow_mitigation > 74.0f) && (int_slow_mitigation < 101.0f)) + else if ((int_slow_mitigation >= 74.0f) && (int_slow_mitigation < 101.0f)) caster->Message(262, "Your spell was slightly successful"); } return 0; @@ -4657,9 +4657,6 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) { if (!IsValidSpell(spell_id)) return false; - if (!IsEffectInSpell(spell_id, SE_LimitToSkill)) - return false; - for (int i = 0; i < EFFECT_COUNT; i++) { if (spells[spell_id].effectid[i] == SE_LimitToSkill){ if (spells[spell_id].base[i] == skill){ @@ -4670,6 +4667,44 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) { return false; } +int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { + + if (!IsValidSpell(spell_id)) + return false; + + int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; + int effect_value = 0; + int lvlModifier = 100; + + int buff_count = GetMaxTotalSlots(); + for (int slot = 0; slot < buff_count; slot++){ + if (IsValidSpell(buffs[slot].spellid)){ + for (int i = 0; i < EFFECT_COUNT; i++){ + if(spells[buffs[slot].spellid].effectid[i] == spelleffect) { + + int critchance = spells[buffs[slot].spellid].base[i]; + int decay = spells[buffs[slot].spellid].base2[i]; + int lvldiff = spell_level - spells[buffs[slot].spellid].max[i]; + + if(lvldiff > 0 && decay > 0) + { + lvlModifier -= decay*lvldiff; + if (lvlModifier > 0){ + critchance = (critchance*lvlModifier)/100; + effect_value += critchance; + } + } + + else + effect_value += critchance; + } + } + } + } + + return effect_value; +} + // Faction Mods for Alliance type spells void Mob::AddFactionBonus(uint32 pFactionID,int32 bonus) { std::map :: const_iterator faction_bonus; diff --git a/zone/mob.h b/zone/mob.h index f6010a3d3..66246cd6b 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -570,6 +570,7 @@ public: bool CanBlockSpell() const { return(spellbonuses.BlockNextSpell); } bool DoHPToManaCovert(uint16 mana_cost = 0); int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false); + int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); @@ -655,7 +656,6 @@ public: int32 ReduceDamage(int32 damage); int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker); - int32 ReduceAllDamage(int32 damage); virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false); virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index a8200ead3..226f61c98 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -197,14 +197,15 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if (ca_atk->m_skill == SkillThrowing) { SetAttackTimer(); ThrowingAttack(GetTarget()); + if (CheckDoubleRangedAttack()) + RangedAttack(GetTarget(), true); return; } //ranged attack (archery) if (ca_atk->m_skill == SkillArchery) { SetAttackTimer(); RangedAttack(GetTarget()); - bool test = CheckArcheryDoubleAttack(); - if (CheckArcheryDoubleAttack()) + if (CheckDoubleRangedAttack()) RangedAttack(GetTarget(), true); return; } @@ -1119,12 +1120,12 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) return MaxDmg; } -void Client::ThrowingAttack(Mob* other) { //old was 51 +void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 //conditions to use an attack checked before we are called //make sure the attack and ranged timers are up //if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow - if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())) { + if((!CanDoubleAttack && (attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) { mlog(COMBAT__RANGED, "Throwing attack canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime()); // The server and client timers are not exact matches currently, so this would spam too often if enabled //Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime()); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 78efc0079..1068667a3 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -178,8 +178,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) int numhit = spells[spell_id].numhits; - if (caster && caster->IsClient()) + if (caster && caster->IsClient()){ + numhit += numhit*caster->CastToClient()->GetFocusEffect(focusFcLimitUse, spell_id)/100; numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id); + } buffs[buffslot].numhits = numhit; } @@ -1364,12 +1366,18 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_MitigateMeleeDamageSP: + case SE_MeleeThresholdGuard: { buffs[buffslot].melee_rune = spells[spell_id].max[i]; break; } + case SE_SpellThresholdGuard: + { + buffs[buffslot].magic_rune = spells[spell_id].max[i]; + break; + } + case SE_MitigateSpellDamage: { buffs[buffslot].magic_rune = GetPartialMagicRuneAmount(spell_id); @@ -1377,12 +1385,18 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - //Using the melee_rune variable, however it will be calculated for both spell and melee. - case SE_SpellOnAmtDmgTaken: + case SE_TriggerMeleeThreshold: { buffs[buffslot].melee_rune = spells[spell_id].base2[i]; break; } + + case SE_TriggerSpellThreshold: + { + buffs[buffslot].magic_rune = spells[spell_id].base2[i]; + break; + } + case SE_Levitate: { @@ -2859,8 +2873,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ImprovedDamage2: case SE_AdditionalHeal2: case SE_HealRate2: - case SE_CriticalHealChance2: - case SE_CriticalHealOverTime2: + case SE_CriticalHealDecay: + case SE_CriticalRegenDecay: case SE_Empathy: case SE_LimitSpellSkill: case SE_MitigateDamageShield: @@ -2904,12 +2918,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_CriticalHealRate: case SE_IncreaseNumHits: case SE_CastonFocusEffect: - case SE_ReduceHeal: + case SE_FcHealAmtIncoming: case SE_IncreaseHitDmgTaken: - case SE_ArcheryDoubleAttack: + case SE_DoubleRangedAttack: case SE_ShieldEquipHateMod: case SE_ShieldEquipDmgMod: case SE_TriggerOnValueAmount: + case SE_LimitRace: + case SE_FcLimitUse: + case SE_FcMute: { break; } @@ -3931,6 +3948,8 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) int lvldiff = 0; bool LimitSpellSkill = false; bool SpellSkill_Found = false; + bool LimitSpellEffect = false; + bool SpellEffect_Found = false; uint32 effect = 0; int32 base1 = 0; int32 base2 = 0; @@ -3963,6 +3982,10 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) if (LimitFound){ value = 0; LimitFound = false; + LimitSpellSkill = false; + SpellSkill_Found = false; + LimitSpellEffect = false; + SpellEffect_Found = false; } else{ @@ -4036,11 +4059,14 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) if(IsEffectInSpell(spell_id,(base1*-1))) LimitFound = true; } - else { - // Include effect(only this) - if(!IsEffectInSpell(spell_id,base1)) - LimitFound = true; + + + else if(base1 >= 0){ + LimitSpellEffect = true; + if (IsEffectInSpell(spell_id,base1)) + SpellEffect_Found = true; } + break; case SE_LimitSpellType: switch(base1) @@ -4110,6 +4136,15 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) LimitFound = true; break; + case SE_LimitRace: + if (base1 != GetRace()) + LimitFound = true; + break; + + case SE_FfLimitUseMin: + if (base1 > spell.numhits) + LimitFound = true; + break; //Handle Focus Effects case SE_ImprovedDamage: @@ -4284,9 +4319,9 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; } - case SE_ReduceHeal: + case SE_FcHealAmtIncoming: { - if(type == focusReduceHeal) + if(type == focusFcHealAmtIncoming) value = base1; break; @@ -4347,17 +4382,36 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; } - //Check for spell skill limits. - if ((LimitSpellSkill) && (!SpellSkill_Found)) - return 0; + + case SE_FcLimitUse: + { + if(type == focusFcLimitUse) + value = base1; + + break; + } + + + case SE_FcMute: + { + if(type == focusFcMute) + value = base1; + + break; + } } } - if (LimitFound){ - return 0; - } + if (LimitSpellSkill && !SpellSkill_Found) + LimitFound = true; + if (LimitSpellEffect && !SpellEffect_Found) + LimitFound = true; + + if (LimitFound) + return 0; + return(value*lvlModifier/100); } @@ -4368,6 +4422,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo if(!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) return 0; + const SPDat_Spell_Struct &focus_spell = spells[focus_id]; const SPDat_Spell_Struct &spell = spells[spell_id]; @@ -4377,6 +4432,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo int lvldiff = 0; bool LimitSpellSkill = false; bool SpellSkill_Found = false; + bool LimitSpellEffect = false; + bool SpellEffect_Found = false; uint32 Caston_spell_id = 0; for (int i = 0; i < EFFECT_COUNT; i++) { @@ -4385,7 +4442,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_Blank: break; //check limits - + case SE_LimitResist:{ if(focus_spell.base[i]){ if(spell.resisttype != focus_spell.base[i]) @@ -4465,10 +4522,17 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo return 0; } } - else if(!IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, must have - return 0; - } + //else if(!SpellEffect_Found && (!IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, must have + // return 0; + //} } + + if(focus_spell.base[i] >= 0){ + LimitSpellEffect = true; + if (IsEffectInSpell(spell_id,focus_spell.base[i])) + SpellEffect_Found = true; + } + break; @@ -4538,11 +4602,22 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo return 0; break; + case SE_LimitRace: + if (focus_spell.base[i] != GetRace()) + return 0; + break; + + case SE_FfLimitUseMin: + if (focus_spell.base[i] > spell.numhits) + return 0; + break; + case SE_CastonFocusEffect: if (focus_spell.base[i] > 0) Caston_spell_id = focus_spell.base[i]; break; + //handle effects case SE_ImprovedDamage: // No Spell used this, its handled by different spell effect IDs. @@ -4764,9 +4839,9 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; } - case SE_ReduceHeal: + case SE_FcHealAmtIncoming: { - if(type == focusReduceHeal) + if(type == focusFcHealAmtIncoming) value = focus_spell.base[i]; break; @@ -4827,6 +4902,23 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; } + + case SE_FcLimitUse: + { + if(type == focusFcLimitUse) + value = focus_spell.base[i]; + + break; + } + + case SE_FcMute: + { + if(type == focusFcMute) + value = focus_spell.base[i]; + + break; + } + #if EQDEBUG >= 6 //this spits up a lot of garbage when calculating spell focuses //since they have all kinds of extra effects on them. @@ -4836,9 +4928,12 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo } } //Check for spell skill limits. - if ((LimitSpellSkill) && (!SpellSkill_Found)) + if (LimitSpellSkill && !SpellSkill_Found) return 0; + if (LimitSpellEffect && !SpellEffect_Found) + return 0; + if (Caston_spell_id){ if(IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) SpellFinished(Caston_spell_id, this, 10, 0, -1, spells[Caston_spell_id].ResistDiff); @@ -5180,6 +5275,23 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { bool Mob::CheckHitsRemaining(uint32 buff_slot, bool when_spell_done, bool negate, uint16 type, uint16 spell_id,bool use_skill,uint16 skill) { + + /* + TO DO: Rewrite code so it checks for numhits by type not after each specified spell effect is triggered... + Field 175 = numhits type + 1: [Incoming Hit Attempts] (323=SE_DefensiveProc, 172=SE_AvoidMeleeChance, 1=SE_ArmorClass, 40=SE_DivineAura) + 2: [Outgoing Hit Attempts] (184=SE_DamageModifer, 185=SE_HitChance) + 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_SpellVulnerability) + 4: NONE + 5: [Outgoing Hit Successes] (196=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnWearoff) + 6: [Incoming Hit Successes] (59=SE_DamageShield, 197=SE_SkillDamageTaken, 162=define SE_MitigateMeleeDamage) + 7: [Matching Spells] *When focus is triggered (focus effects) + 8: [Incoming Hits or Spells] (329=SE_ManaAbsorbPercentDamage) + 9: [Reflected Spells] + 10: [Defensive Procs] + 11: [Melee Procs] + */ + bool bDepleted = false; //Effects: Cast: SE_ResistSpellChance, SE_Reflect, SE_SpellDamageShield //Effects: Attack: SE_MeleeLifetap : SE_DamageShield, SE_AvoidMeleeChance, SE_SkillProc diff --git a/zone/spells.cpp b/zone/spells.cpp index 9a99a70ad..4fad23e5b 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -193,6 +193,17 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, return(false); } + if(IsClient()){ + int chance = CastToClient()->GetFocusEffect(focusFcMute, spell_id); + + if (MakeRandomInt(0,99) < chance){ + Message_StringID(13, SILENCED_STRING); + if(IsClient()) + CastToClient()->SendSpellBarEnable(spell_id); + return(false); + } + } + if(IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()){ Message_StringID(13, SPELL_WOULDNT_HOLD); if(IsClient())