From 57a216cb445091812aad3aff7c32f1a0027a324c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 09:45:12 -0400 Subject: [PATCH] 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) {