diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/server/game/Spells/SpellMgr.cpp | 221 | ||||
-rwxr-xr-x | src/server/game/Spells/SpellMgr.h | 251 | ||||
-rwxr-xr-x | src/server/game/World/World.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_reload.cpp | 10 |
4 files changed, 383 insertions, 102 deletions
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0023cbf597e..f1879099a0a 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -1338,46 +1338,6 @@ void SpellMgr::LoadSpellProcEvents() sLog->outString(); } -void SpellMgr::LoadSpellBonusess() -{ - uint32 oldMSTime = getMSTime(); - - mSpellBonusMap.clear(); // need for reload case - uint32 count = 0; - // 0 1 2 3 4 - QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data"); - if (!result) - { - sLog->outString(">> Loaded %u spell bonus data", count); - sLog->outString(); - return; - } - - do - { - Field *fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - - const SpellEntry *spell = sSpellStore.LookupEntry(entry); - if (!spell) - { - sLog->outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry); - continue; - } - - SpellBonusEntry& sbe = mSpellBonusMap[entry]; - sbe.direct_damage = fields[1].GetFloat(); - sbe.dot_damage = fields[2].GetFloat(); - sbe.ap_bonus = fields[3].GetFloat(); - sbe.ap_dot_bonus = fields[4].GetFloat(); - - ++count; - } while (result->NextRow()); - - sLog->outString(">> Loaded %u extra spell bonus data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - sLog->outString(); -} - bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const* procSpell, uint32 procFlags, uint32 procExtra, bool active) { // No extra req need @@ -1507,6 +1467,187 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr return false; } +void SpellMgr::LoadSpellProcs() +{ + uint32 oldMSTime = getMSTime(); + + mSpellProcMap.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc"); + if (!result) + { + sLog->outString(">> Loaded %u spell proc conditions and data", count); + sLog->outString(); + return; + } + + do + { + Field* fields = result->Fetch(); + + int32 spellId = fields[0].GetInt32(); + + bool allRanks = false; + if (spellId <=0) + { + allRanks = true; + spellId = -spellId; + } + + SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId); + if (!spellEntry) + { + sLog->outErrorDb("Spell %u listed in `spell_proc` does not exist", spellId); + continue; + } + + if (allRanks) + { + if (sSpellMgr->GetFirstSpellInChain(spellId) != uint32(spellId)) + { + sLog->outErrorDb("Spell %u listed in `spell_proc` is not first rank of spell.", fields[0].GetInt32()); + continue; + } + } + + SpellProcEntry baseProcEntry; + + baseProcEntry.schoolMask = fields[1].GetUInt32(); + baseProcEntry.spellFamilyName = fields[2].GetUInt32(); + baseProcEntry.spellFamilyMask[0] = fields[3].GetUInt32(); + baseProcEntry.spellFamilyMask[1] = fields[4].GetUInt32(); + baseProcEntry.spellFamilyMask[2] = fields[5].GetUInt32(); + baseProcEntry.typeMask = fields[6].GetUInt32(); + baseProcEntry.spellTypeMask = fields[7].GetUInt32(); + baseProcEntry.spellPhaseMask = fields[8].GetUInt32(); + baseProcEntry.hitMask = fields[9].GetUInt32(); + baseProcEntry.attributesMask = fields[10].GetUInt32(); + baseProcEntry.ratePerMinute = fields[11].GetFloat(); + baseProcEntry.chance = fields[12].GetFloat(); + baseProcEntry.cooldown = fields[13].GetFloat(); + baseProcEntry.charges = fields[14].GetUInt32(); + + while(true) + { + if (mSpellProcMap.find(spellId) != mSpellProcMap.end()) + { + sLog->outErrorDb("Spell %u listed in `spell_proc` has duplicate entry in the table", spellId); + break; + } + SpellProcEntry procEntry = SpellProcEntry(baseProcEntry); + + // take defaults from dbcs + if (!procEntry.typeMask) + procEntry.typeMask = spellEntry->procFlags; + if (!procEntry.charges) + procEntry.charges = spellEntry->procCharges; + if (!procEntry.chance && !procEntry.ratePerMinute) + procEntry.chance = float(spellEntry->procChance); + + // validate data + if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `schoolMask` set: %u", spellId, procEntry.schoolMask); + if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16)) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u", spellId, procEntry.spellFamilyName); + if (procEntry.chance < 0) + { + sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `chance` field", spellId); + procEntry.chance = 0; + } + if (procEntry.ratePerMinute < 0) + { + sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field", spellId); + procEntry.ratePerMinute = 0; + } + if (procEntry.cooldown < 0) + { + sLog->outErrorDb("`spell_proc` table entry for spellId %u has negative value in `cooldown` field", spellId); + procEntry.cooldown = 0; + } + if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) + sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellId); + if (procEntry.charges > 99) + { + sLog->outErrorDb("`spell_proc` table entry for spellId %u has too big value in `charges` field", spellId); + procEntry.charges = 99; + } + if (!procEntry.typeMask) + sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered", spellId); + if (procEntry.spellTypeMask & ~PROC_SPELL_PHASE_MASK_ALL) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellId, procEntry.spellTypeMask); + if (procEntry.spellTypeMask && !(procEntry.typeMask & SPELL_PROC_FLAG_MASK)) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellId); + if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) + sLog->outErrorDb("`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellId); + if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellId, procEntry.spellPhaseMask); + if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellId); + if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellId, procEntry.hitMask); + if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) + sLog->outErrorDb("`spell_proc` table entry for spellId %u has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellId); + + mSpellProcMap[spellId] = procEntry; + + if (allRanks) + { + spellId = sSpellMgr->GetNextSpellInChain(spellId); + spellEntry = sSpellStore.LookupEntry(spellId); + } + else + break; + } + ++count; + } while (result->NextRow()); + + sLog->outString(">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); +} + +void SpellMgr::LoadSpellBonusess() +{ + uint32 oldMSTime = getMSTime(); + + mSpellBonusMap.clear(); // need for reload case + uint32 count = 0; + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data"); + if (!result) + { + sLog->outString(">> Loaded %u spell bonus data", count); + sLog->outString(); + return; + } + + do + { + Field *fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + + const SpellEntry *spell = sSpellStore.LookupEntry(entry); + if (!spell) + { + sLog->outErrorDb("Spell %u listed in `spell_bonus_data` does not exist", entry); + continue; + } + + SpellBonusEntry& sbe = mSpellBonusMap[entry]; + sbe.direct_damage = fields[1].GetFloat(); + sbe.dot_damage = fields[2].GetFloat(); + sbe.ap_bonus = fields[3].GetFloat(); + sbe.ap_dot_bonus = fields[4].GetFloat(); + + ++count; + } while (result->NextRow()); + + sLog->outString(">> Loaded %u extra spell bonus data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); +} + void SpellMgr::LoadSpellGroups() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index c824d6f2334..4c2ce3741c0 100755 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -553,45 +553,45 @@ int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry cons // Spell proc event related declarations (accessed using SpellMgr functions) enum ProcFlags { - PROC_FLAG_NONE = 0x00000000, + PROC_FLAG_NONE = 0x00000000, - PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor - not sure about this flag - PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward) + PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor - not sure about this flag + PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward) - PROC_FLAG_DONE_MELEE_AUTO_ATTACK = 0x00000004, // 02 Done melee auto attack - PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK = 0x00000008, // 03 Taken melee auto attack + PROC_FLAG_DONE_MELEE_AUTO_ATTACK = 0x00000004, // 02 Done melee auto attack + PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK = 0x00000008, // 03 Taken melee auto attack - PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS = 0x00000010, // 04 Done attack by Spell that has dmg class melee - PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS = 0x00000020, // 05 Taken attack by Spell that has dmg class melee + PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS = 0x00000010, // 04 Done attack by Spell that has dmg class melee + PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS = 0x00000020, // 05 Taken attack by Spell that has dmg class melee - PROC_FLAG_DONE_RANGED_AUTO_ATTACK = 0x00000040, // 06 Done ranged auto attack - PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK = 0x00000080, // 07 Taken ranged auto attack + PROC_FLAG_DONE_RANGED_AUTO_ATTACK = 0x00000040, // 06 Done ranged auto attack + PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK = 0x00000080, // 07 Taken ranged auto attack - PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS = 0x00000100, // 08 Done attack by Spell that has dmg class ranged - PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS = 0x00000200, // 09 Taken attack by Spell that has dmg class ranged + PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS = 0x00000100, // 08 Done attack by Spell that has dmg class ranged + PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS = 0x00000200, // 09 Taken attack by Spell that has dmg class ranged - PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS = 0x00000400, // 10 Done positive spell that has dmg class none - PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS = 0x00000800, // 11 Taken positive spell that has dmg class none + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS = 0x00000400, // 10 Done positive spell that has dmg class none + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS = 0x00000800, // 11 Taken positive spell that has dmg class none - PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG = 0x00001000, // 12 Done negative spell that has dmg class none - PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG = 0x00002000, // 13 Taken negative spell that has dmg class none + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG = 0x00001000, // 12 Done negative spell that has dmg class none + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG = 0x00002000, // 13 Taken negative spell that has dmg class none - PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS = 0x00004000, // 14 Done positive spell that has dmg class magic - PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS = 0x00008000, // 15 Taken positive spell that has dmg class magic + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS = 0x00004000, // 14 Done positive spell that has dmg class magic + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS = 0x00008000, // 15 Taken positive spell that has dmg class magic - PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG = 0x00010000, // 16 Done negative spell that has dmg class magic - PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG = 0x00020000, // 17 Taken negative spell that has dmg class magic + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG = 0x00010000, // 16 Done negative spell that has dmg class magic + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG = 0x00020000, // 17 Taken negative spell that has dmg class magic - PROC_FLAG_DONE_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing) - PROC_FLAG_TAKEN_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing) + PROC_FLAG_DONE_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing) + PROC_FLAG_TAKEN_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing) - PROC_FLAG_TAKEN_DAMAGE = 0x00100000, // 20 Taken any damage - PROC_FLAG_DONE_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation (possibly needs name change to ON_GAMEOBJECT_CAST or USE) + PROC_FLAG_TAKEN_DAMAGE = 0x00100000, // 20 Taken any damage + PROC_FLAG_DONE_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation (possibly needs name change to ON_GAMEOBJECT_CAST or USE) - PROC_FLAG_DONE_MAINHAND_ATTACK = 0x00400000, // 22 Done main-hand melee attacks (spell and autoattack) - PROC_FLAG_DONE_OFFHAND_ATTACK = 0x00800000, // 23 Done off-hand melee attacks (spell and autoattack) + PROC_FLAG_DONE_MAINHAND_ATTACK = 0x00400000, // 22 Done main-hand melee attacks (spell and autoattack) + PROC_FLAG_DONE_OFFHAND_ATTACK = 0x00800000, // 23 Done off-hand melee attacks (spell and autoattack) - PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way + PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way }; #define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_DONE_MELEE_AUTO_ATTACK | \ @@ -603,35 +603,98 @@ enum ProcFlags PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS) -enum ProcFlagsEx -{ - PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag) - PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells) - PROC_EX_CRITICAL_HIT = 0x0000002, - PROC_EX_MISS = 0x0000004, - PROC_EX_RESIST = 0x0000008, - PROC_EX_DODGE = 0x0000010, - PROC_EX_PARRY = 0x0000020, - PROC_EX_BLOCK = 0x0000040, - PROC_EX_EVADE = 0x0000080, - PROC_EX_IMMUNE = 0x0000100, - PROC_EX_DEFLECT = 0x0000200, - PROC_EX_ABSORB = 0x0000400, - PROC_EX_REFLECT = 0x0000800, - PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) - PROC_EX_FULL_BLOCK = 0x0002000, // block al attack damage - PROC_EX_RESERVED2 = 0x0004000, - PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc - PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result - PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet) - PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc - - // Flags for internal use - do not use these in db! - PROC_EX_INTERNAL_CANT_PROC = 0x0800000, - PROC_EX_INTERNAL_DOT = 0x1000000, - PROC_EX_INTERNAL_HOT = 0x2000000, - PROC_EX_INTERNAL_TRIGGERED = 0x4000000, - PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 +// flag masks +#define AUTO_ATTACK_PROC_FLAG_MASK (PROC_FLAG_DONE_MELEE_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | \ + PROC_FLAG_DONE_RANGED_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK) + +#define MELEE_PROC_FLAG_MASK (PROC_FLAG_DONE_MELEE_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | \ + PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_DONE_MAINHAND_ATTACK | \ + PROC_FLAG_DONE_OFFHAND_ATTACK) + +#define RANGED_PROC_FLAG_MASK (PROC_FLAG_DONE_RANGED_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | \ + PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS) + +#define SPELL_PROC_FLAG_MASK (PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS | \ + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | \ + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS | \ + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | \ + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG | \ + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | \ + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | \ + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | \ + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG) + +#define SPELL_CAST_PROC_FLAG_MASK (SPELL_PROC_FLAG_MASK | \ + PROC_FLAG_DONE_TRAP_ACTIVATION | \ + RANGED_PROC_FLAG_MASK) + +#define PERIODIC_PROC_FLAG_MASK (PROC_FLAG_DONE_PERIODIC | \ + PROC_FLAG_TAKEN_PERIODIC) + +#define DONE_HIT_PROC_FLAG_MASK (PROC_FLAG_DONE_MELEE_AUTO_ATTACK | \ + PROC_FLAG_DONE_RANGED_AUTO_ATTACK | \ + PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS | \ + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS | \ + PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG | \ + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | \ + PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG | \ + PROC_FLAG_DONE_PERIODIC | \ + PROC_FLAG_DONE_MAINHAND_ATTACK | \ + PROC_FLAG_DONE_OFFHAND_ATTACK ) + +#define TAKEN_HIT_PROC_FLAG_MASK (PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK | \ + PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS | \ + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS | \ + PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG | \ + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS | \ + PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG | \ + PROC_FLAG_TAKEN_PERIODIC | \ + PROC_FLAG_TAKEN_DAMAGE) + +#define REQ_SPELL_PHASE_PROC_FLAG_MASK (SPELL_PROC_FLAG_MASK & DONE_HIT_PROC_FLAG_MASK) + +enum ProcFlagsExLegacy +{ + PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag) + PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells) + PROC_EX_CRITICAL_HIT = 0x0000002, + PROC_EX_MISS = 0x0000004, + PROC_EX_RESIST = 0x0000008, + PROC_EX_DODGE = 0x0000010, + PROC_EX_PARRY = 0x0000020, + PROC_EX_BLOCK = 0x0000040, + PROC_EX_EVADE = 0x0000080, + PROC_EX_IMMUNE = 0x0000100, + PROC_EX_DEFLECT = 0x0000200, + PROC_EX_ABSORB = 0x0000400, + PROC_EX_REFLECT = 0x0000800, + PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) + PROC_EX_FULL_BLOCK = 0x0002000, // block al attack damage + PROC_EX_RESERVED2 = 0x0004000, + PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc + PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result + PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet) + PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc + + // Flags for internal use - do not use these in db! + PROC_EX_INTERNAL_CANT_PROC = 0x0800000, + PROC_EX_INTERNAL_DOT = 0x1000000, + PROC_EX_INTERNAL_HOT = 0x2000000, + PROC_EX_INTERNAL_TRIGGERED = 0x4000000, + PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 }; #define AURA_SPELL_PROC_EX_MASK \ @@ -640,6 +703,49 @@ enum ProcFlagsEx PROC_EX_EVADE | PROC_EX_IMMUNE | PROC_EX_DEFLECT | \ PROC_EX_ABSORB | PROC_EX_REFLECT | PROC_EX_INTERRUPT) +enum ProcFlagsSpellType +{ + PROC_SPELL_TYPE_NONE = 0x0000000, + PROC_SPELL_TYPE_DAMAGE = 0x0000001, // damage type of spell + PROC_SPELL_TYPE_HEAL = 0x0000002, // heal type of spell + PROC_SPELL_TYPE_NO_DMG_HEAL = 0x0000004, // other spells + PROC_SPELL_TYPE_MASK_ALL = PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_HEAL | PROC_SPELL_TYPE_NO_DMG_HEAL +}; + +enum ProcFlagsSpellPhase +{ + PROC_SPELL_PHASE_NONE = 0x0000000, + PROC_SPELL_PHASE_CAST = 0x0000001, + PROC_SPELL_PHASE_HIT = 0x0000002, + PROC_SPELL_PHASE_FINISH = 0x0000004, + PROC_SPELL_PHASE_MASK_ALL = PROC_SPELL_PHASE_CAST | PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH +}; + +enum ProcFlagsHit +{ + PROC_HIT_NONE = 0x0000000, // no value - PROC_HIT_NORMAL | PROC_HIT_CRITICAL for TAKEN proc type, PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB + PROC_HIT_NORMAL = 0x0000001, // non-critical hits + PROC_HIT_CRITICAL = 0x0000002, + PROC_HIT_MISS = 0x0000004, + PROC_HIT_FULL_RESIST = 0x0000008, + PROC_HIT_DODGE = 0x0000010, + PROC_HIT_PARRY = 0x0000020, + PROC_HIT_BLOCK = 0x0000040, // partial or full block + PROC_HIT_EVADE = 0x0000080, + PROC_HIT_IMMUNE = 0x0000100, + PROC_HIT_DEFLECT = 0x0000200, + PROC_HIT_ABSORB = 0x0000400, // partial or full absorb + PROC_HIT_REFLECT = 0x0000800, + PROC_HIT_INTERRUPT = 0x0001000, // (not used atm) + PROC_HIT_FULL_BLOCK = 0x0002000, + PROC_HIT_MASK_ALL = 0x2FFF, +}; + +enum ProcAttributes +{ + PROC_ATTR_REQ_EXP_OR_HONOR = 0x0000010, +}; + struct SpellProcEventEntry { uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2 @@ -652,15 +758,25 @@ struct SpellProcEventEntry uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_ }; -struct SpellBonusEntry -{ - float direct_damage; - float dot_damage; - float ap_bonus; - float ap_dot_bonus; +typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap; + +struct SpellProcEntry +{ + uint32 schoolMask; // if nonzero - bitmask for matching proc condition based on spell's school + uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName + flag96 spellFamilyMask; // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags + uint32 typeMask; // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags + uint32 spellTypeMask; // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType + uint32 spellPhaseMask; // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase + uint32 hitMask; // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit + uint32 attributesMask; + float ratePerMinute; // if nonzero - chance to proc is equal to value * weapon speed / 60 + float chance; // if nonzero - owerwrite procChance field for given Spell.dbc entry, defines chance of proc to occur, not used if perMinuteRate set + float cooldown; // if nonzero - cooldown in secs for aura proc, applied to aura + uint32 charges; // if nonzero - owerwrite procCharges field for given Spell.dbc entry, defines how many times proc can occur before aura remove, 0 - infinite }; -typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap; +typedef UNORDERED_MAP<uint32, SpellProcEntry> SpellProcMap; struct SpellEnchantProcEntry { @@ -670,6 +786,15 @@ struct SpellEnchantProcEntry }; typedef UNORDERED_MAP<uint32, SpellEnchantProcEntry> SpellEnchantProcEventMap; + +struct SpellBonusEntry +{ + float direct_damage; + float dot_damage; + float ap_bonus; + float ap_dot_bonus; +}; + typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap; enum SpellGroup @@ -1405,6 +1530,7 @@ class SpellMgr void LoadSpellLearnSpells(); void LoadSpellGroups(); void LoadSpellProcEvents(); + void LoadSpellProcs(); void LoadSpellBonusess(); void LoadSpellTargetPositions(); void LoadSpellThreats(); @@ -1433,6 +1559,7 @@ class SpellMgr SpellGroupSpellMap mSpellGroupSpell; SpellThreatMap mSpellThreatMap; SpellProcEventMap mSpellProcEventMap; + SpellProcMap mSpellProcMap; SpellBonusMap mSpellBonusMap; SkillLineAbilityMap mSkillLineAbilityMap; SpellPetAuraMap mSpellPetAuraMap; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 494908b848f..976e8ba660e 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1307,6 +1307,9 @@ void World::SetInitialWorldSettings() sLog->outString("Loading Spell Proc Event conditions..."); sSpellMgr->LoadSpellProcEvents(); + sLog->outString("Loading Spell Proc conditions and data..."); + sSpellMgr->LoadSpellProcs(); + sLog->outString("Loading Spell Bonus Data..."); sSpellMgr->LoadSpellBonusess(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index c51e148bcae..214e624fb22 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -144,6 +144,7 @@ public: { "spell_linked_spell", SEC_ADMINISTRATOR, true, &HandleReloadSpellLinkedSpellCommand, "", NULL }, { "spell_pet_auras", SEC_ADMINISTRATOR, true, &HandleReloadSpellPetAurasCommand, "", NULL }, { "spell_proc_event", SEC_ADMINISTRATOR, true, &HandleReloadSpellProcEventCommand, "", NULL }, + { "spell_proc", SEC_ADMINISTRATOR, true, &HandleReloadSpellProcsCommand, "", NULL }, { "spell_scripts", SEC_ADMINISTRATOR, true, &HandleReloadSpellScriptsCommand, "", NULL }, { "spell_target_position", SEC_ADMINISTRATOR, true, &HandleReloadSpellTargetPositionCommand, "", NULL }, { "spell_threats", SEC_ADMINISTRATOR, true, &HandleReloadSpellThreatsCommand, "", NULL }, @@ -284,6 +285,7 @@ public: HandleReloadSpellLearnSpellCommand(handler, "a"); HandleReloadSpellLinkedSpellCommand(handler, "a"); HandleReloadSpellProcEventCommand(handler, "a"); + HandleReloadSpellProcsCommand(handler, "a"); HandleReloadSpellBonusesCommand(handler, "a"); HandleReloadSpellTargetPositionCommand(handler, "a"); HandleReloadSpellThreatsCommand(handler, "a"); @@ -852,6 +854,14 @@ public: return true; } + static bool HandleReloadSpellProcsCommand(ChatHandler* handler, const char* /*args*/) + { + sLog->outString("Re-Loading Spell Proc conditions and data..."); + sSpellMgr->LoadSpellProcs(); + handler->SendGlobalGMSysMessage("DB table `spell_proc` (spell proc conditions and data) reloaded."); + return true; + } + static bool HandleReloadSpellBonusesCommand(ChatHandler* handler, const char* /*args*/) { sLog->outString("Re-Loading Spell Bonus Data..."); |