From 57a216cb445091812aad3aff7c32f1a0027a324c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 09:45:12 -0400 Subject: [PATCH 01/13] Implemented SE_AStacker, BStacker, CStacker, DStacker Effects are buff stacking blockers. --- changelog.txt | 5 +++++ common/spdat.cpp | 13 +++++++++++++ common/spdat.h | 9 +++++---- zone/bonuses.cpp | 16 ++++++++++++++++ zone/common.h | 4 ++++ zone/mob.h | 2 +- zone/spell_effects.cpp | 4 ++++ zone/spells.cpp | 24 +++++++++++++++++++++--- 8 files changed, 69 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index eabbad6fd..87c9144d4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 06/17/2014 == +Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. +These effects when present in buffs prevent each other from stacking, +Any effect with B prevents A, C prevents B, D prevents C. + == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) Setting se_max to 1 for SkillDamageTaken effects (127) will allow for stackable mitigation/weakness same as quest function ModSkillDmgTaken. diff --git a/common/spdat.cpp b/common/spdat.cpp index 013a917f1..3c4989a67 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1009,6 +1009,19 @@ uint32 GetMorphTrigger(uint32 spell_id) return 0; } +bool IsCastonFadeDurationSpell(uint16 spell_id) +{ + for (int i = 0; i < EFFECT_COUNT; ++i) { + if (spells[spell_id].effectid[i] == SE_ImprovedSpellEffect + || spells[spell_id].effectid[i] == SE_BossSpellTrigger + || spells[spell_id].effectid[i] == SE_CastOnWearoff){ + + return true; + } + } + return false; +} + uint32 GetPartialMeleeRuneReduction(uint32 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) diff --git a/common/spdat.h b/common/spdat.h index ada9e3249..1ef44e15b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -593,10 +593,10 @@ typedef enum { #define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y //#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_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) +#define SE_BStacker 447 // implemented +#define SE_CStacker 448 // implemented +#define SE_DStacker 449 // implemented #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #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 @@ -833,6 +833,7 @@ bool IsBuffSpell(uint16 spell_id); bool IsPersistDeathSpell(uint16 spell_id); bool IsSuspendableSpell(uint16 spell_id); uint32 GetMorphTrigger(uint32 spell_id); +bool IsCastonFadeDurationSpell(uint16 spell_id); uint32 GetPartialMeleeRuneReduction(uint32 spell_id); uint32 GetPartialMagicRuneReduction(uint32 spell_id); uint32 GetPartialMeleeRuneAmount(uint32 spell_id); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index d699cdde2..bdbbe6b4e 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2661,6 +2661,22 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } break; + case SE_AStacker: + newbon->AStacker = true; + break; + + case SE_BStacker: + newbon->BStacker = true; + break; + + case SE_CStacker: + newbon->CStacker = true; + break; + + case SE_DStacker: + newbon->DStacker = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { diff --git a/zone/common.h b/zone/common.h index d5f516f63..dfb500d47 100644 --- a/zone/common.h +++ b/zone/common.h @@ -350,6 +350,10 @@ struct StatBonuses { bool NegateIfCombat; // Bool Drop buff if cast or melee int8 Screech; // -1 = Will be blocked if another Screech is +(1) int16 AlterNPCLevel; // amount of lvls +/- + bool AStacker; // For buff stack blocking + bool BStacker; // For buff stack blocking + bool CStacker; // For buff stack blocking + bool DStacker; // For buff stack blocking // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.h b/zone/mob.h index c3de2b576..4ab9d8a84 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -800,7 +800,7 @@ public: uint16 GetInstrumentMod(uint16 spell_id) const; int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); - virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr); + virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } // HP Event diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 4e10160ed..2c83ef1cd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2886,6 +2886,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitCastTimeMax: case SE_TriggerOnReqCaster: case SE_FrenziedDevastation: + case SE_AStacker: + case SE_BStacker: + case SE_CStacker: + case SE_DStacker: { break; } diff --git a/zone/spells.cpp b/zone/spells.cpp index 54e98613e..21a2fe749 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2542,7 +2542,7 @@ int CalcBuffDuration_formula(int level, int formula, int duration) // -1 if they can't stack and spellid2 should be stopped //currently, a spell will not land if it would overwrite a better spell on any effect //if all effects are better or the same, we overwrite, else we do nothing -int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2) +int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2, int buffslot) { const SPDat_Spell_Struct &sp1 = spells[spellid1]; const SPDat_Spell_Struct &sp2 = spells[spellid2]; @@ -2621,6 +2621,24 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, } } + /*Buff stacking prevention spell effects (446 - 449) works as follows... If B prevent A, if C prevent B, if D prevent C. + Special check is added to make sure the buffs stack properly when applied from fade on duration effect, since the buff + is not fully removed at the time of the trgger*/ + if (spellbonuses.BStacker) { + if ((effect2 == SE_AStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_BStacker))) + return -1; + } + + if (spellbonuses.CStacker) { + if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker))) + return -1; + } + + if (spellbonuses.DStacker) { + if ((effect2 == SE_CStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_DStacker))) + return -1; + } + if(effect2 == SE_StackingCommand_Overwrite) { overwrite_effect = sp2.base[i]; @@ -2901,7 +2919,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (curbuf.spellid != SPELL_UNKNOWN) { // there's a buff in this slot ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spell_id, - caster_level, entity_list.GetMobID(curbuf.casterid), caster); + caster_level, entity_list.GetMobID(curbuf.casterid), caster, buffslot); if (ret == -1) { // stop the spell mlog(SPELLS__BUFFS, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d", spell_id, curbuf.spellid, buffslot, curbuf.casterlevel); @@ -3047,7 +3065,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) return(-1); //do not recast a buff we already have on, we recast fast enough that we dont need to refresh our buffs // there's a buff in this slot - ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level); + ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level, nullptr, nullptr, i); if(ret == 1) { // should overwrite current slot if(iFailIfOverwrite) { From da70a45d22a7eb757de8fdcba0ce008a669466a7 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 15:23:07 -0400 Subject: [PATCH 02/13] Implemented SE_DamageModifier2 --- changelog.txt | 1 + common/spdat.h | 2 +- zone/bonuses.cpp | 29 +++++++++++++++++++++++++++++ zone/common.h | 1 + zone/mob.cpp | 3 +++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 87c9144d4..7002939e6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. +Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 1ef44e15b..7e0367fd7 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -606,7 +606,7 @@ typedef enum { //#define SE_AddHateOverTimePct 456 // not used //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used -//#define SE_DamageModifier2 459 // *not implemented - Modifies melee damage by skill type +#define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type // LAST diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index bdbbe6b4e..03e1d76f6 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1099,6 +1099,15 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += base1; + else + newbon->DamageModifier2[base2] += base1; + break; + } + case SE_SlayUndead: { if(newbon->SlayUndead[1] < base1) @@ -1909,6 +1918,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += effect_value; + else + newbon->DamageModifier2[base2] += effect_value; + break; + } + case SE_MinDamageModifier: { if(base2 == -1) @@ -3454,6 +3472,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) break; } + case SE_DamageModifier2: + { + for(int e = 0; e < HIGHEST_SKILL+1; e++) + { + spellbonuses.DamageModifier2[e] = effect_value; + aabonuses.DamageModifier2[e] = effect_value; + itembonuses.DamageModifier2[e] = effect_value; + } + break; + } + case SE_MinDamageModifier: { for(int e = 0; e < HIGHEST_SKILL+1; e++) diff --git a/zone/common.h b/zone/common.h index dfb500d47..67386d910 100644 --- a/zone/common.h +++ b/zone/common.h @@ -279,6 +279,7 @@ struct StatBonuses { int16 HitChance; //HitChance/15 == % increase i = Accuracy (Item: Accuracy) int16 HitChanceEffect[HIGHEST_SKILL+2]; //Spell effect Chance to Hit, straight percent increase int16 DamageModifier[HIGHEST_SKILL+2]; //i + int16 DamageModifier2[HIGHEST_SKILL+2]; //i int16 MinDamageModifier[HIGHEST_SKILL+2]; //i int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects int16 ProcChanceSPA; // ProcChance from spell effects diff --git a/zone/mob.cpp b/zone/mob.cpp index d5ff23a7d..5faeffa65 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4277,6 +4277,9 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill) dmg_mod += itembonuses.DamageModifier[HIGHEST_SKILL+1] + spellbonuses.DamageModifier[HIGHEST_SKILL+1] + aabonuses.DamageModifier[HIGHEST_SKILL+1] + itembonuses.DamageModifier[skill] + spellbonuses.DamageModifier[skill] + aabonuses.DamageModifier[skill]; + dmg_mod += itembonuses.DamageModifier2[HIGHEST_SKILL+1] + spellbonuses.DamageModifier2[HIGHEST_SKILL+1] + aabonuses.DamageModifier2[HIGHEST_SKILL+1] + + itembonuses.DamageModifier2[skill] + spellbonuses.DamageModifier2[skill] + aabonuses.DamageModifier2[skill]; + if (HasShieldEquiped() && !IsOffHandAtk()) dmg_mod += itembonuses.ShieldEquipDmgMod[0] + spellbonuses.ShieldEquipDmgMod[0] + aabonuses.ShieldEquipDmgMod[0]; From aa6af15cb5cbd06e3054f24721b5f4841eec38df Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 15:49:56 -0400 Subject: [PATCH 03/13] Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) --- changelog.txt | 1 + common/spdat.h | 2 +- zone/spell_effects.cpp | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7002939e6..698d84044 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,7 @@ Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) +Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 7e0367fd7..f03e944c9 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -602,7 +602,7 @@ typedef enum { #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_AddHatePct 455 // implement - Modify total hate by % //#define SE_AddHateOverTimePct 456 // not used //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2c83ef1cd..f78d0e5c5 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2668,6 +2668,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) SlowMitigation(caster); break; + case SE_AddHatePct: + { + if (IsNPC()) + CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100)); + + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: From a34a69b4c48759bffe7fad33928011575d3e8ee2 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 16:08:19 -0400 Subject: [PATCH 04/13] Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) --- changelog.txt | 1 + common/spdat.h | 4 ++-- zone/spell_effects.cpp | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 698d84044..6c87c8534 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,7 @@ These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) +Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index f03e944c9..4edd6543b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -602,8 +602,8 @@ typedef enum { #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 // implement - Modify total hate by % -//#define SE_AddHateOverTimePct 456 // not used +#define SE_AddHatePct 455 // implemented Modify total hate by % +#define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used #define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f78d0e5c5..9a536b832 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3530,6 +3530,14 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste } } + case SE_AddHateOverTimePct: + { + if (IsNPC()) + CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100)); + + break; + } + default: { // do we need to do anyting here? From 70476bfb06b797c1abdb434feb2a2794fd2bebed Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 18 Jun 2014 06:25:14 -0400 Subject: [PATCH 05/13] Implemented SE_DoubleRiposte --- changelog.txt | 1 + common/spdat.h | 2 +- zone/attack.cpp | 4 ++++ zone/bonuses.cpp | 16 ++++++++++++++++ zone/common.h | 1 + 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 6c87c8534..3f4572dce 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) +Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 4edd6543b..ba671acea 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -370,7 +370,7 @@ typedef enum { #define SE_SkillDamageAmount 220 // implemented #define SE_Packrat 221 // implemented as bonus #define SE_BlockBehind 222 // implemented - Chance to block from behind (with our without Shield) -//#define SE_DoubleRiposte 223 // not used +#define SE_DoubleRiposte 223 // implemented - Chance to double riposte [not used on live] #define SE_GiveDoubleRiposte 224 // implemented[AA] #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. #define SE_TwoHandBash 226 // *not implemented as bonus diff --git a/zone/attack.cpp b/zone/attack.cpp index 34a1de47d..a3e5c37cd 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4449,6 +4449,10 @@ void Mob::DoRiposte(Mob* defender) { defender->spellbonuses.GiveDoubleRiposte[0] + defender->itembonuses.GiveDoubleRiposte[0]; + DoubleRipChance = defender->aabonuses.DoubleRiposte + + defender->spellbonuses.DoubleRiposte + + defender->itembonuses.DoubleRiposte; + //Live AA - Double Riposte if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { mlog(COMBAT__ATTACKS, "Preforming a double riposed (%d percent chance)", DoubleRipChance); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 03e1d76f6..c549bdf72 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1116,6 +1116,11 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += base1; + } + case SE_GiveDoubleRiposte: { //0=Regular Riposte 1=Skill Attack Riposte 2=Skill @@ -2571,6 +2576,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += effect_value; + } + case SE_GiveDoubleRiposte: { //Only allow for regular double riposte chance. @@ -3978,6 +3988,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.MasteryofPast = effect_value; break; + case SE_DoubleRiposte: + spellbonuses.DoubleRiposte = effect_value; + itembonuses.DoubleRiposte = effect_value; + aabonuses.DoubleRiposte = effect_value; + break; + case SE_GiveDoubleRiposte: spellbonuses.GiveDoubleRiposte[0] = effect_value; itembonuses.GiveDoubleRiposte[0] = effect_value; diff --git a/zone/common.h b/zone/common.h index 67386d910..a88d8adda 100644 --- a/zone/common.h +++ b/zone/common.h @@ -383,6 +383,7 @@ struct StatBonuses { int16 PetCriticalHit; // Allow pets to critical hit with % value. int16 PetAvoidance; // Pet avoidance chance. int16 CombatStability; // Melee damage mitigation. + int16 DoubleRiposte; // Chance to double riposte int16 GiveDoubleRiposte[3]; // 0=Regular Chance, 1=Skill Attack Chance, 2=Skill uint16 RaiseSkillCap[2]; // Raise a specific skill cap (1 = value, 2=skill) int16 Ambidexterity; // Increase chance to duel wield by adding bonus 'skill'. From 5a14a85f52043199b589af6f13353205a1949db8 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 20 Jun 2014 18:10:29 -0400 Subject: [PATCH 06/13] Implemention for SE_Berserk, SE_Vampirism (These are not used on live) Fix for NPC not receiving spell bonus derived HP regen. --- changelog.txt | 6 +++++- common/spdat.h | 6 +++--- zone/attack.cpp | 20 ++++++++++++-------- zone/bonuses.cpp | 28 ++++++++++++++++++++++++++++ zone/common.h | 4 +++- zone/mob.cpp | 21 +++++++++------------ zone/npc.cpp | 12 ++++++------ zone/npc.h | 1 + 8 files changed, 67 insertions(+), 31 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3f4572dce..58955e931 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,7 +7,11 @@ Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) -Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) +Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) *Not used in any live effects +Kayen: Implemented SE_Berserk (Sets client as 'Berserk' giving chance to crippling blow) *Not used in any live effects +Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used in any live effects +Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. +Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index ba671acea..c0813ea40 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -190,9 +190,9 @@ typedef enum { #define SE_DivineAura 40 // implemented #define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows #define SE_ShadowStep 42 // implemented -//#define SE_Berserk 43 // not used -#define SE_Lycanthropy 44 // implemented -//#define SE_Vampirism 45 // not used +#define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance. +#define SE_Lycanthropy 44 // implemented +#define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee. #define SE_ResistFire 46 // implemented #define SE_ResistCold 47 // implemented #define SE_ResistPoison 48 // implemented diff --git a/zone/attack.cpp b/zone/attack.cpp index a3e5c37cd..074288c3d 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4283,6 +4283,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack float critChance = 0.0f; + bool IsBerskerSPA = false; //1: Try Slay Undead if(defender && defender->GetBodyType() == BT_Undead || defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire){ @@ -4310,12 +4311,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack //are defined you will have an innate chance to hit at Level 1 regardless of bonuses. //Warning: Do not define these rules if you want live like critical hits. critChance += RuleI(Combat, MeleeBaseCritChance); - + if (IsClient()) { - critChance += RuleI(Combat, ClientBaseCritChance); + critChance += RuleI(Combat, ClientBaseCritChance); - if ((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) { - if (IsBerserk()) + if (spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA) + IsBerskerSPA = true; + + if (((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) || IsBerskerSPA) { + if (IsBerserk() || IsBerskerSPA) critChance += RuleI(Combat, BerserkBaseCritChance); else critChance += RuleI(Combat, WarBerBaseCritChance); @@ -4360,15 +4364,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack uint16 critMod = 200; bool crip_success = false; int16 CripplingBlowChance = GetCrippBlowChance(); - + //Crippling Blow Chance: The percent value of the effect is applied //to the your Chance to Critical. (ie You have 10% chance to critical and you //have a 200% Chance to Critical Blow effect, therefore you have a 20% Chance to Critical Blow. - if (CripplingBlowChance || IsBerserk()) { - if (!IsBerserk()) + if (CripplingBlowChance || (IsBerserk() || IsBerskerSPA)) { + if (!IsBerserk() && !IsBerskerSPA) critChance *= float(CripplingBlowChance)/100.0f; - if (IsBerserk() || MakeRandomFloat(0, 1) < critChance) { + if ((IsBerserk() || IsBerskerSPA) || MakeRandomFloat(0, 1) < critChance) { critMod = 400; crip_success = true; } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index c549bdf72..09d7766a7 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1248,6 +1248,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_Vampirism: + newbon->Vampirism += base1; + break; + case SE_FrenziedDevastation: newbon->FrenziedDevastation += base2; break; @@ -1256,6 +1260,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->SpellProcChance += base1; break; + case SE_Berserk: + newbon->BerserkSPA = true; + break; + } } } @@ -1827,6 +1835,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_Vampirism: + newbon->Vampirism += effect_value; + break; + case SE_AllInstrumentMod: { if(effect_value > newbon->singingMod) @@ -2705,6 +2717,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->DStacker = true; break; + case SE_Berserk: + newbon->BerserkSPA = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4094,6 +4110,18 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.AbsorbMagicAtt[0] = effect_value; spellbonuses.AbsorbMagicAtt[1] = -1; break; + + case SE_Berserk: + spellbonuses.BerserkSPA = false; + aabonuses.BerserkSPA = false; + itembonuses.BerserkSPA = false; + break; + + case SE_Vampirism: + spellbonuses.Vampirism = effect_value; + aabonuses.Vampirism = effect_value; + itembonuses.Vampirism = effect_value; + break; } } diff --git a/zone/common.h b/zone/common.h index a88d8adda..67b616248 100644 --- a/zone/common.h +++ b/zone/common.h @@ -290,7 +290,8 @@ struct StatBonuses { int16 FlurryChance; int16 Accuracy[HIGHEST_SKILL+2]; //Accuracy/15 == % increase [Spell Effect: Accuracy) int16 HundredHands; //extra haste, stacks with all other haste i - int8 MeleeLifetap; //i + int16 MeleeLifetap; //i + int16 Vampirism; //i int16 HealRate; // Spell effect that influences effectiveness of heals int32 MaxHPChange; // Spell Effect int16 SkillDmgTaken[HIGHEST_SKILL+2]; // All Skills + -1 @@ -355,6 +356,7 @@ struct StatBonuses { bool BStacker; // For buff stack blocking bool CStacker; // For buff stack blocking bool DStacker; // For buff stack blocking + bool BerserkSPA; // berserk effect // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.cpp b/zone/mob.cpp index 5faeffa65..06dbe4519 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4337,22 +4337,19 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) void Mob::MeleeLifeTap(int32 damage) { - if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap || aabonuses.MeleeLifetap )) - { - int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap; - - if(lifetap_amt > 100) - lifetap_amt = 100; - - else if (lifetap_amt < -99) - lifetap_amt = -99; + int16 lifetap_amt = 0; + lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap + + spellbonuses.Vampirism + itembonuses.Vampirism + aabonuses.Vampirism; + if(lifetap_amt && damage > 0){ lifetap_amt = damage * lifetap_amt / 100; - mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); - //heal self for damage done.. - HealDamage(lifetap_amt); + + if (lifetap_amt > 0) + HealDamage(lifetap_amt); //Heal self for modified damage amount. + else + Damage(this, -lifetap_amt,0, SkillEvocation,false); //Dmg self for modified damage amount. } } diff --git a/zone/npc.cpp b/zone/npc.cpp index 3886d7c66..38989bccb 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -599,19 +599,19 @@ bool NPC::Process() //Lieka Edit:Fixing NPC regen.NPCs should regen to full during a set duration, not based on their HPs.Increase NPC's HPs by % of total HPs / tick. if((GetHP() < GetMaxHP()) && !IsPet()) { if(!IsEngaged()) {//NPC out of combat - if(hp_regen > OOCRegen) - SetHP(GetHP() + hp_regen); + if(GetNPCHPRegen() > OOCRegen) + SetHP(GetHP() + GetNPCHPRegen()); else SetHP(GetHP() + OOCRegen); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); } else if(GetHP() < GetMaxHP() && GetOwnerID() !=0) { if(!IsEngaged()) //pet - SetHP(GetHP()+hp_regen+bonus+(GetLevel()/5)); + SetHP(GetHP()+GetNPCHPRegen()+bonus+(GetLevel()/5)); else - SetHP(GetHP()+hp_regen+bonus); + SetHP(GetHP()+GetNPCHPRegen()+bonus); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); if(GetMana() < GetMaxMana()) { SetMana(GetMana()+mana_regen+bonus); diff --git a/zone/npc.h b/zone/npc.h index ae444c099..07c81e79b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -256,6 +256,7 @@ public: virtual void DoClassAttacks(Mob *target); void CheckSignal(); inline bool IsTargetableWithHotkey() const { return no_target_hotkey; } + int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } //waypoint crap int GetMaxWp() const { return max_wp; } From c20f35b3e8bdf13cab8a40c6368226b68104eff4 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 21 Jun 2014 10:12:24 -0400 Subject: [PATCH 07/13] minor fix --- zone/spell_effects.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 9a536b832..af20d3734 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2897,7 +2897,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AStacker: case SE_BStacker: case SE_CStacker: - case SE_DStacker: + case SE_DStacker: + case SE_DoubleRiposte: + case SE_Berserk: + case SE_Vampirism: { break; } From a4769239fa93859b293eac6f79b60da27226a6f9 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 06:16:34 -0400 Subject: [PATCH 08/13] Fixes and Updates to spell and melee mitigation runes. -Fix for calculation error when rune was to be removed. -Updated to support these spell effect limit values which give a max amount per hit/spell that can be mitigated. -Updated to allow support for these spells effects when the max (rune value) is set to zero, which essentially gives you unlimited mitigation but typically there is a limit value set. --- changelog.txt | 1 + common/spdat.h | 2 +- zone/attack.cpp | 46 +++++++++++++++++++++++++++++++++------------- zone/bonuses.cpp | 6 ++++++ zone/common.h | 6 +++--- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/changelog.txt b/changelog.txt index 58955e931..97e4beb4a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,6 +12,7 @@ Kayen: Implemented SE_Berserk (Sets client as 'Berserk' giving chance to crippli Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used in any live effects Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. +Kayen: Fixes and Updates for melee and spell mitigation runes. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index c0813ea40..3cd4a232a 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -307,7 +307,7 @@ typedef enum { #define SE_SpellDamageShield 157 // implemented - Petrad's Protection #define SE_Reflect 158 // implemented #define SE_AllStats 159 // implemented -#define SE_MakeDrunk 160 // implemented - poorly though, should check against tolerance +//#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance) #define SE_MitigateSpellDamage 161 // implemented - rune with max value #define SE_MitigateMeleeDamage 162 // implemented - rune with max value #define SE_NegateAttacks 163 // implemented diff --git a/zone/attack.cpp b/zone/attack.cpp index 074288c3d..f3cdedc1c 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3188,11 +3188,11 @@ int32 Mob::ReduceDamage(int32 damage) { DisableMeleeRune = true; int damage_to_reduce = damage * spellbonuses.MeleeThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + if(damage_to_reduce >= buffs[slot].melee_rune) { 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; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3212,11 +3212,15 @@ int32 Mob::ReduceDamage(int32 damage) if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateMeleeRune[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + + if (spellbonuses.MitigateMeleeRune[2] && (damage_to_reduce > spellbonuses.MitigateMeleeRune[2])) + damage_to_reduce = spellbonuses.MitigateMeleeRune[2]; + + if(spellbonuses.MitigateMeleeRune[3] && (damage_to_reduce >= buffs[slot].melee_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3224,7 +3228,10 @@ int32 Mob::ReduceDamage(int32 damage) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); - buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + + if (spellbonuses.MitigateMeleeRune[3]) + buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3286,15 +3293,21 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100; - if(damage_to_reduce > buffs[slot].dot_rune) + + if (spellbonuses.MitigateDotRune[2] && (damage_to_reduce > spellbonuses.MitigateDotRune[2])) + damage_to_reduce = spellbonuses.MitigateDotRune[2]; + + if(spellbonuses.MitigateDotRune[3] && (damage_to_reduce >= buffs[slot].dot_rune)) { - damage -= damage_to_reduce; + damage -= buffs[slot].dot_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } else { - buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + if (spellbonuses.MitigateDotRune[3]) + buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3316,9 +3329,9 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { DisableSpellRune = true; int damage_to_reduce = damage * spellbonuses.SpellThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + if(damage_to_reduce >= buffs[slot].magic_rune) { - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3337,11 +3350,15 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateSpellRune[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + + if (spellbonuses.MitigateSpellRune[2] && (damage_to_reduce > spellbonuses.MitigateSpellRune[2])) + damage_to_reduce = spellbonuses.MitigateSpellRune[2]; + + if(spellbonuses.MitigateSpellRune[3] && (damage_to_reduce >= buffs[slot].magic_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateSpellDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].magic_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3349,7 +3366,10 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].magic_rune); - buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + + if (spellbonuses.MitigateSpellRune[3]) + buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + damage -= damage_to_reduce; } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 09d7766a7..ed5be19e7 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2303,6 +2303,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateMeleeRune[0] < effect_value){ newbon->MitigateMeleeRune[0] = effect_value; newbon->MitigateMeleeRune[1] = buffslot; + newbon->MitigateMeleeRune[2] = base2; + newbon->MitigateMeleeRune[3] = max; } break; } @@ -2333,6 +2335,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateSpellRune[0] < effect_value){ newbon->MitigateSpellRune[0] = effect_value; newbon->MitigateSpellRune[1] = buffslot; + newbon->MitigateSpellRune[2] = base2; + newbon->MitigateSpellRune[3] = max; } break; } @@ -2342,6 +2346,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateDotRune[0] < effect_value){ newbon->MitigateDotRune[0] = effect_value; newbon->MitigateDotRune[1] = buffslot; + newbon->MitigateDotRune[2] = base2; + newbon->MitigateDotRune[3] = max; } break; } diff --git a/zone/common.h b/zone/common.h index 67b616248..0cec22336 100644 --- a/zone/common.h +++ b/zone/common.h @@ -329,11 +329,11 @@ struct StatBonuses { bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) 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 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt 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 - uint16 MitigateDotRune[2]; // 0 = Mitigation value 1 = Buff Slot + uint16 MitigateSpellRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per spell 3 = Rune Amt + uint16 MitigateDotRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per tick 3 = Rune Amt 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 From 8ad9ad578c5fb22c9c7f7cc5c158214bb417cc04 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 10:30:18 -0400 Subject: [PATCH 09/13] Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. --- changelog.txt | 1 + zone/attack.cpp | 14 +++++++++++--- zone/bonuses.cpp | 1 + zone/common.h | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 97e4beb4a..e22f02697 100644 --- a/changelog.txt +++ b/changelog.txt @@ -13,6 +13,7 @@ Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used i Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. Kayen: Fixes and Updates for melee and spell mitigation runes. +Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/zone/attack.cpp b/zone/attack.cpp index f3cdedc1c..99682eee5 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3176,7 +3176,11 @@ int32 Mob::ReduceDamage(int32 damage) if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return -6; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return -6; } } @@ -3272,7 +3276,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi int32 slot = -1; // See if we block the spell outright first - if (spellbonuses.NegateAttacks[0]){ + if (!iBuffTic && spellbonuses.NegateAttacks[0]){ slot = spellbonuses.NegateAttacks[1]; if(slot >= 0) { if(--buffs[slot].numhits == 0) { @@ -3280,7 +3284,11 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return 0; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return 0; } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index ed5be19e7..ffb13edd8 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2294,6 +2294,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (!newbon->NegateAttacks[0]){ newbon->NegateAttacks[0] = 1; newbon->NegateAttacks[1] = buffslot; + newbon->NegateAttacks[2] = max; } break; } diff --git a/zone/common.h b/zone/common.h index 0cec22336..b687d07df 100644 --- a/zone/common.h +++ b/zone/common.h @@ -328,7 +328,7 @@ struct StatBonuses { uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) int16 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage - uint16 NegateAttacks[2]; // 0 = bool HasEffect 1 = Buff Slot + uint16 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit uint16 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt 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. From f28a392f71c927fb8171be7adfa216743c4c640d Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 15:55:04 -0400 Subject: [PATCH 10/13] SE_NegateAttacks buff stacking optimized. --- zone/bonuses.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index ffb13edd8..481ec668a 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2291,7 +2291,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_NegateAttacks: { - if (!newbon->NegateAttacks[0]){ + if (!newbon->NegateAttacks[0] || + ((newbon->NegateAttacks[0] && newbon->NegateAttacks[2]) && (newbon->NegateAttacks[2] < max))){ newbon->NegateAttacks[0] = 1; newbon->NegateAttacks[1] = buffslot; newbon->NegateAttacks[2] = max; From 41b190930f9b855b88bba63b12bb1a4b0215f531 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 23:10:29 -0400 Subject: [PATCH 11/13] Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] --- changelog.txt | 1 + common/spdat.h | 2 +- zone/bonuses.cpp | 15 +++++++++++++++ zone/client.cpp | 20 ++++++-------------- zone/common.h | 3 ++- zone/spell_effects.cpp | 1 + 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/changelog.txt b/changelog.txt index e22f02697..f0dd21757 100644 --- a/changelog.txt +++ b/changelog.txt @@ -14,6 +14,7 @@ Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitra Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. Kayen: Fixes and Updates for melee and spell mitigation runes. Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. +Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 3cd4a232a..b302e8314 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -380,7 +380,7 @@ typedef enum { //#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) -//#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism? +#define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. //#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 481ec668a..3ce6becca 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1264,6 +1264,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->BerserkSPA = true; break; + case SE_Metabolism: + newbon->Metabolism += base1; + break; + } } } @@ -2729,6 +2733,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->BerserkSPA = true; break; + + case SE_Metabolism: + newbon->Metabolism += effect_value; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4130,6 +4139,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.Vampirism = effect_value; itembonuses.Vampirism = effect_value; break; + + case SE_Metabolism: + spellbonuses.Metabolism = effect_value; + aabonuses.Metabolism = effect_value; + itembonuses.Metabolism = effect_value; + break; } } diff --git a/zone/client.cpp b/zone/client.cpp index 7aa7bd748..2ce193346 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8134,20 +8134,12 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ uint16 cons_mod = 180; - switch(GetAA(aaInnateMetabolism)){ - case 1: - cons_mod = cons_mod * 110 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 2: - cons_mod = cons_mod * 125 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 3: - cons_mod = cons_mod * 150 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - default: - cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; - break; - } + int16 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; + + if (metabolism_bonus) + cons_mod = cons_mod * metabolism_bonus* RuleI(Character, ConsumptionMultiplier) / 10000; + else + cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; if(type == ItemTypeFood) { diff --git a/zone/common.h b/zone/common.h index b687d07df..f94962ee1 100644 --- a/zone/common.h +++ b/zone/common.h @@ -356,7 +356,8 @@ struct StatBonuses { bool BStacker; // For buff stack blocking bool CStacker; // For buff stack blocking bool DStacker; // For buff stack blocking - bool BerserkSPA; // berserk effect + bool BerserkSPA; // berserk effect + int16 Metabolism; // Food/drink consumption rates. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index af20d3734..b46f34a6e 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2901,6 +2901,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_DoubleRiposte: case SE_Berserk: case SE_Vampirism: + case SE_Metabolism: { break; } From 58175a54426c04a1a540ec747e5737f32b73ca45 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 23 Jun 2014 08:37:23 -0400 Subject: [PATCH 12/13] Update to SE_BalanaceMana, SE_BalanceHP to support limit value which caps max mana/hp that can be taken per player. --- changelog.txt | 1 + zone/client.cpp | 2 +- zone/groups.cpp | 26 ++++++++++++++++++++------ zone/groups.h | 4 ++-- zone/raids.cpp | 23 +++++++++++++++++------ zone/raids.h | 4 ++-- zone/spell_effects.cpp | 8 ++++---- 7 files changed, 47 insertions(+), 21 deletions(-) diff --git a/changelog.txt b/changelog.txt index f0dd21757..c4fa6cecf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,7 @@ Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived Kayen: Fixes and Updates for melee and spell mitigation runes. Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] +Kayen: Update to SE_BalanaceMana, SE_BalanceHP to support limit value which caps max mana/hp that can be taken per player. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/zone/client.cpp b/zone/client.cpp index 2ce193346..4ec3ce2d7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8137,7 +8137,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ int16 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; if (metabolism_bonus) - cons_mod = cons_mod * metabolism_bonus* RuleI(Character, ConsumptionMultiplier) / 10000; + cons_mod = cons_mod * metabolism_bonus * RuleI(Character, ConsumptionMultiplier) / 10000; else cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; diff --git a/zone/groups.cpp b/zone/groups.cpp index aa50ba2c9..245765c32 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1095,7 +1095,7 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range) } -void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) +void Group::BalanceHP(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1103,7 +1103,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; float distance; float range2 = range*range; @@ -1114,7 +1114,12 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if(members[gi]){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - dmgtaken += (members[gi]->GetMaxHP() - members[gi]->GetHP()); + + dmgtaken_tmp = members[gi]->GetMaxHP() - members[gi]->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -1140,7 +1145,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) } } -void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) +void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1151,14 +1156,19 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - manataken += (members[gi]->GetMaxMana() - members[gi]->GetMana()); + + manataken_tmp = members[gi]->GetMaxMana() - members[gi]->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); numMem += 1; } } @@ -1166,6 +1176,10 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + + if (limit && (manataken > limit)) + manataken = limit; + for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ diff --git a/zone/groups.h b/zone/groups.h index c5a3f8ab1..fe21ff3a4 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -86,8 +86,8 @@ public: uint16 GetAvgLevel(); bool LearnMembers(); void VerifyGroup(); - void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, int32 range = 0); inline void SetGroupAAs(GroupLeadershipAA_Struct *From) { memcpy(&LeaderAbilities, From, sizeof(GroupLeadershipAA_Struct)); } inline void GetGroupAAs(GroupLeadershipAA_Struct *Into) { memcpy(Into, &LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); } diff --git a/zone/raids.cpp b/zone/raids.cpp index bf6f76d5c..be0b697db 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -504,7 +504,7 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range) } -void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -512,7 +512,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; int gi = 0; float distance; @@ -525,7 +525,12 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) { distance = caster->DistNoRoot(*members[gi].member); if(distance <= range2){ - dmgtaken += (members[gi].member->GetMaxHP() - members[gi].member->GetHP()); + + dmgtaken_tmp = members[gi].member->GetMaxHP() - members[gi].member->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -555,7 +560,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) } } -void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -566,7 +571,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; int gi = 0; for(; gi < MAX_RAID_MEMBERS; gi++) { @@ -575,7 +580,12 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) { distance = caster->DistNoRoot(*members[gi].member); if(distance <= range2){ - manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana()); + + manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); numMem += 1; } } @@ -584,6 +594,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + for(gi = 0; gi < MAX_RAID_MEMBERS; gi++) { if(members[gi].member){ diff --git a/zone/raids.h b/zone/raids.h index c8c2f61e4..be12788e6 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -147,8 +147,8 @@ public: void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid); void SplitExp(uint32 exp, Mob* other); uint32 GetTotalRaidDamage(Mob* other); - void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range = 0); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b46f34a6e..b846e0058 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2393,7 +2393,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceHP(spell.base[i], gid, spell.range, caster); + r->BalanceHP(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2403,7 +2403,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceHP(spell.base[i], spell.range, caster); + g->BalanceHP(spell.base[i], spell.range, caster, spell.base2[i]); break; } @@ -2421,7 +2421,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceMana(spell.base[i], gid, spell.range, caster); + r->BalanceMana(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2431,7 +2431,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceMana(spell.base[i], spell.range, caster); + g->BalanceMana(spell.base[i], spell.range, caster, spell.base2[i]); break; } From 660db94607d0b11924b6b9968d933df00c689144 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 24 Jun 2014 08:24:11 -0400 Subject: [PATCH 13/13] Fix to SE_BlanaceMana to only check classes in group that have mana. --- zone/groups.cpp | 2 +- zone/raids.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/zone/groups.cpp b/zone/groups.cpp index 1af5cc34e..6aee5f38b 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1160,7 +1160,7 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit) unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { - if(members[gi]){ + if(members[gi] && (members[gi]->GetMaxMana() > 0)){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ diff --git a/zone/raids.cpp b/zone/raids.cpp index be0b697db..c712fc4bd 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -578,15 +578,17 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int3 if(members[gi].member){ if(members[gi].GroupNumber == gid) { - distance = caster->DistNoRoot(*members[gi].member); - if(distance <= range2){ + if (members[gi].member->GetMaxMana() > 0) { + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ - manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); - if (limit && (manataken_tmp > limit)) - manataken_tmp = limit; + manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; - manataken += (manataken_tmp); - numMem += 1; + manataken += (manataken_tmp); + numMem += 1; + } } } }