From 615f4a53042ed739af11864597c7d4aa59516299 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 15 Feb 2022 08:58:10 -0500 Subject: [PATCH] [API] Apply spells with custom buff durations and adjust existing spell buff durations. (#1997) * working * Update spell_effects.cpp * updates * disable_buff_overwrite * revert * update * working * update * updates * Update spells.cpp * getbuffstat done * Update perl_mob.cpp * [API] Apply spells with custom buff durations and adjust existing spell buff durations. * [API] Apply spells with custom buff durations and adjust existing spell buff durations. * [API] Apply spells with custom buff durations and adjust existing spell buff durations. * [API] Apply spells with custom buff durations and adjust existing spell buff durations. * https://github.com/EQEmu/Server/pull/1997 Lua added, thanks kinglykrab --- common/spdat.h | 5 +- zone/lua_mob.cpp | 36 +++++++++++++ zone/lua_mob.h | 6 +++ zone/mob.h | 10 ++-- zone/perl_mob.cpp | 84 +++++++++++++++++++++++++++++ zone/spell_effects.cpp | 120 +++++++++++++++++++++++++++++++++++++++-- zone/spells.cpp | 14 ++--- 7 files changed, 258 insertions(+), 17 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index b544c2b80..3a0d1636a 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -1264,8 +1264,9 @@ typedef enum { // LAST -#define DF_Permanent 50 -#define DF_Aura 51 +#define DF_Permanent 50 +#define DF_Aura 51 +#define PERMANENT_BUFF_DURATION -1000 //this is arbitrary used when overriding spells regular buff duration to set it as permenant // note this struct is historical, we don't actually need it to be // aligned to anything, but for maintaining it it is kept in the order that diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 4cbf0227c..ad8d365d3 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -2448,6 +2448,36 @@ void Lua_Mob::SetSeeInvisibleUndeadLevel(uint8 invisible_level) self->SetSeeInvisibleUndead(invisible_level); } +void Lua_Mob::ApplySpellBuff(int spell_id) { + Lua_Safe_Call_Void(); + self->ApplySpellBuff(spell_id, 0); +} + +void Lua_Mob::ApplySpellBuff(int spell_id, int duration) { + Lua_Safe_Call_Void(); + self->ApplySpellBuff(spell_id, duration); +} + +int Lua_Mob::GetBuffStatValueBySlot(uint8 slot, const char* identifier) { + Lua_Safe_Call_Int(); + return self->GetBuffStatValueBySlot(slot, identifier); +} + +int Lua_Mob::GetBuffStatValueBySpell(int spell_id, const char* identifier) { + Lua_Safe_Call_Int(); + return self->GetBuffStatValueBySpell(spell_id, identifier); +} + +void Lua_Mob::SetBuffDuration(int spell_id) { + Lua_Safe_Call_Void(); + self->SetBuffDuration(spell_id, 0); +} + +void Lua_Mob::SetBuffDuration(int spell_id, int duration) { + Lua_Safe_Call_Void(); + self->SetBuffDuration(spell_id, duration); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -2458,6 +2488,8 @@ luabind::scope lua_register_mob() { .def("AddToHateList", (void(Lua_Mob::*)(Lua_Mob,int,int,bool))&Lua_Mob::AddToHateList) .def("AddToHateList", (void(Lua_Mob::*)(Lua_Mob,int,int,bool,bool))&Lua_Mob::AddToHateList) .def("AddToHateList", (void(Lua_Mob::*)(Lua_Mob,int,int,bool,bool,bool))&Lua_Mob::AddToHateList) + .def("ApplySpellBuff", (void(Lua_Mob::*)(int))&Lua_Mob::ApplySpellBuff) + .def("ApplySpellBuff", (void(Lua_Mob::*)(int, int))&Lua_Mob::ApplySpellBuff) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool))&Lua_Mob::Attack) @@ -2595,6 +2627,8 @@ luabind::scope lua_register_mob() { .def("GetBucketKey", (std::string(Lua_Mob::*)(void))&Lua_Mob::GetBucketKey) .def("GetBucketRemaining", (std::string(Lua_Mob::*)(std::string))&Lua_Mob::GetBucketRemaining) .def("GetBuffSlotFromType", &Lua_Mob::GetBuffSlotFromType) + .def("GetBuffStatValueBySlot", (void(Lua_Mob::*)(uint8, const char*))& Lua_Mob::GetBuffStatValueBySlot) + .def("GetBuffStatValueBySpell", (void(Lua_Mob::*)(int, const char*))&Lua_Mob::GetBuffStatValueBySpell) .def("GetCHA", &Lua_Mob::GetCHA) .def("GetCR", &Lua_Mob::GetCR) .def("GetCasterLevel", &Lua_Mob::GetCasterLevel) @@ -2810,6 +2844,8 @@ luabind::scope lua_register_mob() { .def("SetBodyType", (void(Lua_Mob::*)(int,bool))&Lua_Mob::SetBodyType) .def("SetBucket", (void(Lua_Mob::*)(std::string,std::string))&Lua_Mob::SetBucket) .def("SetBucket", (void(Lua_Mob::*)(std::string,std::string,std::string))&Lua_Mob::SetBucket) + .def("SetBuffDuration", (void(Lua_Mob::*)(int))&Lua_Mob::SetBuffDuration) + .def("SetBuffDuration", (void(Lua_Mob::*)(int, int))&Lua_Mob::SetBuffDuration) .def("SetCurrentWP", &Lua_Mob::SetCurrentWP) .def("SetDestructibleObject", (void(Lua_Mob::*)(bool))&Lua_Mob::SetDestructibleObject) .def("SetDisableMelee", (void(Lua_Mob::*)(bool))&Lua_Mob::SetDisableMelee) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index fdcecce55..17b0dc4fb 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -457,6 +457,12 @@ public: bool IsHorse(); bool CanClassEquipItem(uint32 item_id); bool CanRaceEquipItem(uint32 item_id); + void ApplySpellBuff(int spell_id); + void ApplySpellBuff(int spell_id, int duration); + int GetBuffStatValueBySlot(uint8 slot, const char* identifier); + int GetBuffStatValueBySpell(int spell_id, const char* identifier); + void SetBuffDuration(int spell_id); + void SetBuffDuration(int spell_id, int duration); }; #endif diff --git a/zone/mob.h b/zone/mob.h index d676cc046..155a98f47 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -349,8 +349,8 @@ public: uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, bool from_casted_spell = false, uint32 aa_id = 0); void SendBeginCast(uint16 spell_id, uint32 casttime); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0, - bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0); - virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1, int reflect_effectiveness = 0, int32 duration_override = 0); + bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0, bool disable_buff_overrwrite = false); + virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1, int reflect_effectiveness = 0, int32 duration_override = 0, bool disable_buff_overrwrite = false); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQ::spells::CastingSlot slot, bool isproc = false); bool DoCastingChecksOnCaster(int32 spell_id); @@ -406,7 +406,7 @@ public: bool IsAffectedByBuff(uint16 spell_id); bool IsAffectedByBuffByGlobalGroup(GlobalGroup group); void BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration); - int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1); + int AddBuff(Mob *caster, const uint16 spell_id, int duration = 0, int32 level_override = -1, bool disable_buff_overrwrite = false); int CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite = false); int CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caster_level_override = -1); void SendPetBuffsToClient(); @@ -461,6 +461,10 @@ public: void GetAppearenceEffects(); void ClearAppearenceEffects(); void SendSavedAppearenceEffects(Client *receiver); + void SetBuffDuration(int32 spell_id, int32 duration); + void ApplySpellBuff(int32 spell_id, int32 duration); + int GetBuffStatValueBySpell(int32 spell_id, const char* stat_identifier); + int GetBuffStatValueBySlot(uint8 slot, const char* stat_identifier); //Basic Stats/Inventory virtual void SetLevel(uint8 in_level, bool command = false) { level = in_level; } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index fba859354..7e9ed5eab 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -5662,6 +5662,46 @@ XS(XS_Mob_GetSpellStat) { XSRETURN(1); } +XS(XS_Mob_GetBuffStatValueBySpell); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetBuffStatValueBySpell) { + dXSARGS; + if (items != 3) + Perl_croak(aTHX_ "Usage: Mob::GetBuffStatValueBySpell(THIS, int32 spell_id, string stat)"); // @categories Spells and Disciplines + { + Mob *THIS; + int32 RETVAL; + int32 spellid = (int32)SvIV(ST(1)); + Const_char *stat = (Const_char *)SvPV_nolen(ST(2)); + dXSTARG; + VALIDATE_THIS_IS_MOB; + + RETVAL = THIS->GetBuffStatValueBySpell(spellid, stat); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetBuffStatValueBySlot); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetBuffStatValueBySlot) { + dXSARGS; + if (items != 3) + Perl_croak(aTHX_ "Usage: Mob::GetBuffStatValueBySlot(THIS, uint8 slot, string stat)"); // @categories Script Utility, Spells and Disciplines + { + Mob *THIS; + int32 RETVAL; + uint8 slot = (uint8)SvUV(ST(1)); + Const_char *stat = (Const_char *)SvPV_nolen(ST(2)); + dXSTARG; + VALIDATE_THIS_IS_MOB; + + RETVAL = THIS->GetBuffStatValueBySlot(slot, stat); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + XS(XS_Mob_GetSpecialAbility); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_GetSpecialAbility) { dXSARGS; @@ -6567,6 +6607,46 @@ XS(XS_Mob_GetHateRandomNPC) { XSRETURN(1); } +XS(XS_Mob_SetBuffDuration); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_SetBuffDuration) { + dXSARGS; + if (items < 2 || items > 3) + Perl_croak(aTHX_ "Usage: Mob::SetBuffDuration(THIS, spell_id, [int duration = 0])"); // @categories Script Utility, Spells and Disciplines + { + Mob *THIS; + int spell_id = (int)SvIV(ST(1)); + int duration = 0; + VALIDATE_THIS_IS_MOB; + + if (items == 3) { + duration = (int)SvIV(ST(2)); + } + + THIS->SetBuffDuration(spell_id, duration); + } + XSRETURN_EMPTY; +} + +XS(XS_Mob_ApplySpellBuff); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_ApplySpellBuff) { + dXSARGS; + if (items < 2 || items > 3) + Perl_croak(aTHX_ "Usage: Mob::ApplySpellBuff(THIS, spell_id, [int duration = 0])"); // @categories Script Utility, Spells and Disciplines + { + Mob *THIS; + int spell_id = (int)SvIV(ST(1)); + int duration = 0; + VALIDATE_THIS_IS_MOB; + + if (items == 3) { + duration = (int)SvIV(ST(2)); + } + + THIS->ApplySpellBuff(spell_id, duration); + } + XSRETURN_EMPTY; +} + #ifdef BOTS XS(XS_Mob_CastToBot); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_CastToBot) @@ -6622,6 +6702,7 @@ XS(boot_Mob) { newXSproto(strcpy(buf, "AddFeignMemory"), XS_Mob_AddFeignMemory, file, "$$"); newXSproto(strcpy(buf, "AddNimbusEffect"), XS_Mob_AddNimbusEffect, file, "$$"); newXSproto(strcpy(buf, "AddToHateList"), XS_Mob_AddToHateList, file, "$$;$$$$$"); + newXSproto(strcpy(buf, "ApplySpellBuff"), XS_Mob_ApplySpellBuff, file, "$$;$"); newXSproto(strcpy(buf, "Attack"), XS_Mob_Attack, file, "$$;$$"); newXSproto(strcpy(buf, "BehindMob"), XS_Mob_BehindMob, file, "$;$$$"); newXSproto(strcpy(buf, "BuffCount"), XS_Mob_BuffCount, file, "$"); @@ -6712,6 +6793,8 @@ XS(boot_Mob) { newXSproto(strcpy(buf, "GetBucketKey"), XS_Mob_GetBucketKey, file, "$"); newXSproto(strcpy(buf, "GetBucketRemaining"), XS_Mob_GetBucketRemaining, file, "$$"); newXSproto(strcpy(buf, "GetBuffSlotFromType"), XS_Mob_GetBuffSlotFromType, file, "$$"); + newXSproto(strcpy(buf, "GetBuffStatValueBySpell"), XS_Mob_GetBuffStatValueBySpell, file, "$$$"); + newXSproto(strcpy(buf, "GetBuffStatValueBySlot"), XS_Mob_GetBuffStatValueBySlot, file, "$$$"); newXSproto(strcpy(buf, "GetCHA"), XS_Mob_GetCHA, file, "$"); newXSproto(strcpy(buf, "GetCR"), XS_Mob_GetCR, file, "$"); newXSproto(strcpy(buf, "GetCasterLevel"), XS_Mob_GetCasterLevel, file, "$$"); @@ -6917,6 +7000,7 @@ XS(boot_Mob) { newXSproto(strcpy(buf, "SetAppearance"), XS_Mob_SetAppearance, file, "$$;$"); newXSproto(strcpy(buf, "SetBodyType"), XS_Mob_SetBodyType, file, "$$;$"); newXSproto(strcpy(buf, "SetBucket"), XS_Mob_SetBucket, file, "$$$;$"); + newXSproto(strcpy(buf, "SetBuffDuration"), XS_Mob_SetBuffDuration, file, "$$;$"); newXSproto(strcpy(buf, "SetCurrentWP"), XS_Mob_SetCurrentWP, file, "$$"); newXSproto(strcpy(buf, "SetDeltas"), XS_Mob_SetDeltas, file, "$$$$$"); newXSproto(strcpy(buf, "SetDisableMelee"), XS_Mob_SetDisableMelee, file, "$$"); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f69d3fc32..1a5da0a7a 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -46,7 +46,7 @@ extern WorldServer worldserver; // the spell can still fail here, if the buff can't stack // in this case false will be returned, true otherwise -bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_override, int reflect_effectiveness, int32 duration_override) +bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_override, int reflect_effectiveness, int32 duration_override, bool disable_buff_overrwrite) { int caster_level, buffslot, effect, effect_value, i; EQ::ItemInstance *SummonedItem=nullptr; @@ -119,7 +119,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove } else { - buffslot = AddBuff(caster, spell_id, duration_override); + buffslot = AddBuff(caster, spell_id, duration_override, -1, disable_buff_overrwrite); } if(buffslot == -1) // stacking failure return false; @@ -3662,7 +3662,8 @@ void Mob::BuffProcess() // DF_Permanent uses -1 DF_Aura uses -4 but we need to check negatives for some spells for some reason? if (spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Permanent && - spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Aura) { + spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Aura && + buffs[buffs_i].ticsremaining != PERMANENT_BUFF_DURATION) { if(!zone->BuffTimersSuspended() || !IsSuspendableSpell(buffs[buffs_i].spellid)) { --buffs[buffs_i].ticsremaining; @@ -10204,3 +10205,116 @@ bool Mob::HasPersistDeathIllusion(int32 spell_id) { } return false; } + +void Mob::SetBuffDuration(int32 spell_id, int32 duration) { + + /* + Will refresh the buff with specified spell_id to the specified duration + If spell is -1, then all spells will be set to the specified duration + If duration 0, then will set duration to buffs normal max duration. + */ + + bool adjust_all_buffs = false; + + if (spell_id == -1) { + adjust_all_buffs = true; + } + + if (!adjust_all_buffs && !IsValidSpell(spell_id)){ + return; + } + + if (duration < -1) { + duration = PERMANENT_BUFF_DURATION; + } + + int buff_count = GetMaxBuffSlots(); + for (int slot = 0; slot < buff_count; slot++) { + + if (!adjust_all_buffs) { + if (buffs[slot].spellid != SPELL_UNKNOWN && buffs[slot].spellid == spell_id) { + SpellOnTarget(buffs[slot].spellid, this, 0, false, 0, false, -1, duration, true); + return; + } + } + else { + if (buffs[slot].spellid != SPELL_UNKNOWN) { + SpellOnTarget(buffs[slot].spellid, this, 0, false, 0, false, -1, duration, true); + } + } + } +} + +void Mob::ApplySpellBuff(int32 spell_id, int32 duration) +{ + /* + Used for quest command to apply a new buff with custom duration. + Duration set to 0 will apply with normal duration. + */ + if (!IsValidSpell(spell_id)) { + return; + } + if (!spells[spell_id].buff_duration) { + return; + } + + if (duration < -1) { + duration = PERMANENT_BUFF_DURATION; + } + + SpellOnTarget(spell_id, this, 0, false, 0, false, -1, duration); +} + +int Mob::GetBuffStatValueBySpell(int32 spell_id, const char* stat_identifier) +{ + if (!IsValidSpell(spell_id)) { + return 0; + } + + if (!stat_identifier) { + return 0; + } + + std::string id = str_tolower(stat_identifier); + + int buff_count = GetMaxBuffSlots(); + for (int slot = 0; slot < buff_count; slot++) { + if (buffs[slot].spellid != SPELL_UNKNOWN && buffs[slot].spellid == spell_id) { + return GetBuffStatValueBySlot(slot, stat_identifier); + } + } + return 0; +} + +int Mob::GetBuffStatValueBySlot(uint8 slot, const char* stat_identifier) +{ + if (slot > GetMaxBuffSlots()) { + return 0; + } + + if (!stat_identifier) { + return 0; + } + + std::string id = str_tolower(stat_identifier); + + if (id == "caster_level") { return buffs[slot].casterlevel; } + else if (id == "spell_id") { return buffs[slot].spellid; } + else if (id == "caster_id") { return buffs[slot].spellid;; } + else if (id == "ticsremaining") { return buffs[slot].ticsremaining; } + else if (id == "counters") { return buffs[slot].counters; } + else if (id == "hit_number") { return buffs[slot].hit_number; } + else if (id == "melee_rune") { return buffs[slot].melee_rune; } + else if (id == "magic_rune") { return buffs[slot].magic_rune; } + else if (id == "dot_rune") { return buffs[slot].dot_rune; } + else if (id == "caston_x") { return buffs[slot].caston_x; } + else if (id == "caston_y") { return buffs[slot].caston_y; } + else if (id == "caston_z") { return buffs[slot].caston_z; } + else if (id == "instrument_mod") { return buffs[slot].instrument_mod; } + else if (id == "persistant_buff") { return buffs[slot].persistant_buff; } + else if (id == "client") { return buffs[slot].client; } + else if (id == "extra_di_chance") { return buffs[slot].ExtraDIChance; } + else if (id == "root_break_chance") { return buffs[slot].RootBreakChance; } + else if (id == "virus_spread_time") { return buffs[slot].virus_spread_time; } + return 0; +} diff --git a/zone/spells.cpp b/zone/spells.cpp index ab0fff31a..eba811ed3 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3200,9 +3200,8 @@ bool Mob::HasDiscBuff() // stacking problems, and -2 if this is not a buff // if caster is null, the buff will be added with the caster level being // the level of the mob -int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_override) +int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_override, bool disable_buff_overrwrite) { - int buffslot, ret, caster_level, emptyslot = -1; bool will_overwrite = false; std::vector overwrite_slots; @@ -3223,7 +3222,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid LogSpells("Buff [{}] failed to add because its duration came back as 0", spell_id); return -2; // no duration? this isn't a buff } - + LogSpells("Trying to add buff [{}] cast by [{}] (cast level [{}]) with duration [{}]", spell_id, caster?caster->GetName():"UNKNOWN", caster_level, duration); @@ -3297,7 +3296,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid // at this point we know that this buff will stick, but we have // to remove some other buffs already worn if will_overwrite is true - if (will_overwrite) { + if (will_overwrite && !disable_buff_overrwrite) { std::vector::iterator cur, end; cur = overwrite_slots.begin(); end = overwrite_slots.end(); @@ -3314,9 +3313,6 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid } } - // now add buff at emptyslot - assert(buffs[emptyslot].spellid == SPELL_UNKNOWN); // sanity check - buffs[emptyslot].spellid = spell_id; buffs[emptyslot].casterlevel = caster_level; if (caster && !caster->IsAura()) // maybe some other things we don't want to ... @@ -3446,7 +3442,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) // break stuff // bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectiveness, bool use_resist_adjust, int16 resist_adjust, - bool isproc, int level_override, int32 duration_override) + bool isproc, int level_override, int32 duration_override, bool disable_buff_overrwrite) { // well we can't cast a spell on target without a target if(!spelltar) @@ -3994,7 +3990,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectivenes } // cause the effects to the target - if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override, reflect_effectiveness, duration_override)) + if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override, reflect_effectiveness, duration_override, disable_buff_overrwrite)) { // if SpellEffect returned false there's a problem applying the // spell. It's most likely a buff that can't stack.