diff options
Diffstat (limited to 'src/game/SpellMgr.cpp')
-rw-r--r-- | src/game/SpellMgr.cpp | 261 |
1 files changed, 220 insertions, 41 deletions
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 07a0df04450..2886affc8b6 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -90,6 +90,16 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell) return (castTime > 0) ? uint32(castTime) : 0; } +float GetSpellMinRange(SpellRangeEntry const *range) +{ + if (!range) + return 0; + if (!range->minRange) + if (range->flags==SPELL_RANGE_RANGED) + //return 5.0; + return 2.0;//this is a hack, needs fix + return range->minRange; +} bool IsPassiveSpell(uint32 spellId) { @@ -99,7 +109,7 @@ bool IsPassiveSpell(uint32 spellId) return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0; } -bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2) +/*bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2) { SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1); SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2); @@ -113,7 +123,7 @@ bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_ return false; return true; -} +}*/ int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2) { @@ -135,6 +145,14 @@ SpellSpecific GetSpellSpecific(uint32 spellId) switch(spellInfo->SpellFamilyName) { + case SPELLFAMILY_GENERIC: + { + // this may be a hack + if((spellInfo->AttributesEx2 & SPELL_ATTR_EX2_FOOD) + && !spellInfo->Category) + return SPELL_WELL_FED; + break; + } case SPELLFAMILY_MAGE: { // family flags 18(Molten), 25(Frost/Ice), 28(Mage) @@ -244,14 +262,25 @@ bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2) case SPELL_STING: case SPELL_CURSE: case SPELL_ASPECT: + case SPELL_POSITIVE_SHOUT: + case SPELL_JUDGEMENT: + case SPELL_WARLOCK_CORRUPTION: + return spellSpec1==spellSpec2; + default: + return false; + } +} + +bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1,uint32 spellSpec2) +{ + switch(spellSpec1) + { case SPELL_TRACKER: case SPELL_WARLOCK_ARMOR: case SPELL_MAGE_ARMOR: case SPELL_ELEMENTAL_SHIELD: case SPELL_MAGE_POLYMORPH: - case SPELL_POSITIVE_SHOUT: - case SPELL_JUDGEMENT: - case SPELL_WARLOCK_CORRUPTION: + case SPELL_WELL_FED: return spellSpec1==spellSpec2; case SPELL_BATTLE_ELIXIR: return spellSpec2==SPELL_BATTLE_ELIXIR @@ -537,6 +566,17 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI return false; } +bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId) +{ + SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); + if (!spellproto) return false; + + for (int i = 0; i < 3; i++) + if (spellproto->EffectApplyAuraName[i] == auraType) + return true; + return false; +} + uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) { // talents that learn spells can have stance requirements that need ignore @@ -813,8 +853,8 @@ void SpellMgr::LoadSpellProcEvents() uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 - QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown FROM spell_proc_event"); + // 0 1 2 3 4 5 6 7 8 + QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event"); if( !result ) { @@ -828,7 +868,7 @@ void SpellMgr::LoadSpellProcEvents() } barGoLink bar( result->GetRowCount() ); - + uint32 customProc = 0; do { Field *fields = result->Fetch(); @@ -837,7 +877,8 @@ void SpellMgr::LoadSpellProcEvents() uint16 entry = fields[0].GetUInt16(); - if (!sSpellStore.LookupEntry(entry)) + const SpellEntry *spell = sSpellStore.LookupEntry(entry); + if (!spell) { sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry); continue; @@ -846,23 +887,35 @@ void SpellMgr::LoadSpellProcEvents() SpellProcEventEntry spe; spe.schoolMask = fields[1].GetUInt32(); - spe.category = fields[2].GetUInt32(); - spe.skillId = fields[3].GetUInt32(); - spe.spellFamilyName = fields[4].GetUInt32(); - spe.spellFamilyMask = fields[5].GetUInt64(); - spe.procFlags = fields[6].GetUInt32(); - spe.ppmRate = fields[7].GetFloat(); + spe.spellFamilyName = fields[2].GetUInt32(); + spe.spellFamilyMask = fields[3].GetUInt64(); + spe.procFlags = fields[4].GetUInt32(); + spe.procEx = fields[5].GetUInt32(); + spe.ppmRate = fields[6].GetFloat(); + spe.customChance = fields[7].GetFloat(); spe.cooldown = fields[8].GetUInt32(); mSpellProcEventMap[entry] = spe; + if (spell->procFlags==0) + { + if (spe.procFlags == 0) + { + sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", entry); + continue; + } + customProc++; + } ++count; } while( result->NextRow() ); delete result; sLog.outString(); - sLog.outString( ">> Loaded %u spell proc event conditions", count ); + if (customProc) + sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom", count, customProc ); + else + sLog.outString( ">> Loaded %u spell proc event conditions", count ); /* // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event) @@ -894,6 +947,7 @@ void SpellMgr::LoadSpellProcEvents() */ } +/* bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags ) { if((procFlags & spellProcEvent->procFlags) == 0) @@ -932,6 +986,73 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spell return true; } +*/ + +bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active) +{ + // No extra req need + uint32 procEvent_procEx = PROC_EX_NONE; + + // check prockFlags for condition + if((procFlags & EventProcFlag) == 0) + return false; + + // Always trigger for this + if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL_AND_GET_XP)) + return true; + + if (spellProcEvent) // Exist event data + { + // Store extra req + procEvent_procEx = spellProcEvent->procEx; + + // For melee triggers + if (procSpell == NULL) + { + // Check (if set) for school (melee attack have Normal school) + if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) + return false; + } + else // For spells need check school/spell family/family mask + { + // Check (if set) for school + if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0) + return false; + + // Check (if set) for spellFamilyName + if(spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName)) + return false; + + // spellFamilyName is Ok need check for spellFamilyMask if present + if(spellProcEvent->spellFamilyMask) + { + if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0) + return false; + active = true; // Spell added manualy -> so its active spell + } + } + } + // Check for extra req (if none) and hit/crit + if (procEvent_procEx == PROC_EX_NONE) + { + // No extra req, so can trigger only for active (damage/healing present) and hit/crit + if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active) + return true; + } + else // Passive spells hits here only if resist/reflect/immune/evade + { + // Exist req for PROC_EX_EX_TRIGGER_ALWAYS + if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS) + return true; + // Passive spells can`t trigger if need hit + if ((procEvent_procEx & PROC_EX_NORMAL_HIT) && !active) + return false; + // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other) + if (procEvent_procEx & procExtra) + return true; + } + return false; +} void SpellMgr::LoadSpellElixirs() { @@ -1030,10 +1151,10 @@ bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo) return true; } -bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const +bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool sameCaster) const { - if(spellId_1 == spellId_2) // auras due to the same spell - return false; + //if(spellId_1 == spellId_2) // auras due to the same spell + // return false; SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1); SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2); @@ -1041,22 +1162,82 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons if(!spellInfo_1 || !spellInfo_2) return false; + SpellSpecific spellId_spec_1 = GetSpellSpecific(spellId_1); + SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2); + if (spellId_spec_1 && spellId_spec_2) + if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2) + ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster)) + return true; + if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName) return false; - if(!spellInfo_1->SpellFamilyName) // generic spells + // generic spells + if(!spellInfo_1->SpellFamilyName) { - if(!spellInfo_1->SpellIconID + if(spellInfo_1->Category && spellInfo_1->Category == spellInfo_2->Category) + { + if(spellInfo_1->Category == SPELL_CATEGORY_FOOD || + spellInfo_1->Category == SPELL_CATEGORY_DRINK) + return true; + } + + if(!spellInfo_1->SpellIconID || spellInfo_1->SpellIconID != spellInfo_2->SpellIconID) return false; } - else if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags) - return false; + // if both elixirs are not battle/guardian/potions/flasks then always stack + else if(spellInfo_1->SpellFamilyName == SPELLFAMILY_POTION) + { + if(spellId_spec_1 || spellId_spec_2) + return false; + } + + // check for class spells + else + { + if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags) + return false; + } + + if(!sameCaster) + { + for(uint32 i = 0; i < 3; ++i) + if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA + || spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + // not area auras (shaman totem) + switch(spellInfo_1->EffectApplyAuraName[i]) + { + // DOT or HOT from different casters will stack + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_PERIODIC_TRIGGER_SPELL: + case SPELL_AURA_PERIODIC_ENERGIZE: + case SPELL_AURA_PERIODIC_MANA_LEECH: + case SPELL_AURA_PERIODIC_LEECH: + return false; + default: + break; + } + } + + //not sure if this is correct. maybe some talent buff have same icons? + //maybe some creature spells have same visual and same icon but should stack? + //spells with the same icon (check needed when spell has different effects in other ranks example:Mark of the wild) + //if(spellInfo_1->SpellIconID + // && spellInfo_1->SpellIconID == spellInfo_2->SpellIconID) + // return true; // maybe change this to IsRankSpellDueToSpell? + + if(spellInfo_1->SpellFamilyName && IsRankSpellDueToSpell(spellInfo_1, spellId_2)) + return true; + + //if spells have exactly the same effect they cannot stack for(uint32 i = 0; i < 3; ++i) if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i] - || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]) - return false; + || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i] + || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura + return false; // need itemtype check? need an example to add that check return true; } @@ -1863,6 +2044,11 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z { if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id)) { + if(mask & ELIXIR_BATTLE_MASK) + { + if(spellInfo->Id==45373) // Bloodberry Elixir + return zone_id==4075; + } if(mask & ELIXIR_UNSTABLE_MASK) { // in the Blade's Edge Mountains Plateaus and Gruul's Lair. @@ -1870,9 +2056,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z } if(mask & ELIXIR_SHATTRATH_MASK) { - // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple - // TODO: and the Sunwell Plateau - if(zone_id ==3607 || map_id==534 || map_id==564) + // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau + if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075) return true; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); @@ -1890,8 +2075,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z // special cases zone check (maps checked by multimap common id) switch(spellInfo->Id) { - case 41618: - case 41620: + case 41618: // Bottled Nethergon Energy + case 41620: // Bottled Nethergon Vapor { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if(!mapEntry) @@ -1899,9 +2084,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z return mapEntry->multimap_id==206; } - - case 41617: - case 41619: + case 41617: // Cenarion Mana Salve + case 41619: // Cenarion Healing Salve { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); if(!mapEntry) @@ -1909,14 +2093,9 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z return mapEntry->multimap_id==207; } - // Dragonmaw Illusion - case 40216: - case 42016: - { - if ( area_id != 3759 && area_id != 3966 && area_id != 3939 ) - return false; - break; - } + case 40216: // Dragonmaw Illusion + case 42016: // Dragonmaw Illusion + return area_id == 3759 || area_id == 3966 || area_id == 3939; } return true; |