Spell effect updates

This commit is contained in:
KayenEQ 2014-01-13 05:03:21 -05:00
parent f4e085c121
commit 32359da1cc
14 changed files with 406 additions and 129 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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()) {

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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 <uint32, int32> :: const_iterator faction_bonus;

View File

@ -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);

View File

@ -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());

View File

@ -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

View File

@ -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())