aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Spells')
-rw-r--r--src/server/game/Spells/Auras/SpellAuraDefines.h28
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp26
-rw-r--r--src/server/game/Spells/Spell.cpp37
-rw-r--r--src/server/game/Spells/Spell.h5
-rw-r--r--src/server/game/Spells/SpellEffects.cpp134
-rw-r--r--src/server/game/Spells/SpellHistory.cpp22
-rw-r--r--src/server/game/Spells/SpellHistory.h17
-rw-r--r--src/server/game/Spells/SpellInfo.cpp55
-rw-r--r--src/server/game/Spells/SpellInfo.h5
-rw-r--r--src/server/game/Spells/SpellMgr.cpp100
10 files changed, 311 insertions, 118 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h
index 65021d13140..02460e30622 100644
--- a/src/server/game/Spells/Auras/SpellAuraDefines.h
+++ b/src/server/game/Spells/Auras/SpellAuraDefines.h
@@ -598,10 +598,34 @@ enum AuraType : uint32
SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER = 504,
SPELL_AURA_MOD_PLAYER_CHOICE_REROLLS = 505, // NYI
SPELL_AURA_DISABLE_INERTIA = 506,
- SPELL_AURA_507 = 507,
+ SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_BY_LABEL = 507,
SPELL_AURA_508 = 508,
SPELL_AURA_509 = 509,
- SPELL_AURA_MODIFIED_RAID_INSTANCE = 510, // Related to "Fated" raid affixes
+ SPELL_AURA_MODIFIED_RAID_INSTANCE = 510, // NYI; Related to "Fated" raid affixes
+ SPELL_AURA_APPLY_PROFESSION_EFFECT = 511, // NYI; MiscValue[0] = ProfessionEffectID
+ SPELL_AURA_512 = 512,
+ SPELL_AURA_513 = 513,
+ SPELL_AURA_514 = 514,
+ SPELL_AURA_515 = 515,
+ SPELL_AURA_516 = 516,
+ SPELL_AURA_517 = 517,
+ SPELL_AURA_518 = 518,
+ SPELL_AURA_MOD_COOLDOWN_RECOVERY_RATE_ALL = 519, // NYI; applies to all spells, not filtered by familyflags or label
+ SPELL_AURA_520 = 520,
+ SPELL_AURA_521 = 521,
+ SPELL_AURA_522 = 522,
+ SPELL_AURA_523 = 523,
+ SPELL_AURA_524 = 524,
+ SPELL_AURA_DISPLAY_PROFESSION_EQUIPMENT = 525, // NYI; MiscValue[0] = Profession (enum, not id)
+ SPELL_AURA_526 = 526,
+ SPELL_AURA_527 = 527,
+ SPELL_AURA_ALLOW_BLOCKING_SPELLS = 528, // NYI
+ SPELL_AURA_MOD_SPELL_BLOCK_CHANCE = 529, // NYI
+ SPELL_AURA_530 = 530,
+ SPELL_AURA_531 = 531,
+ SPELL_AURA_532 = 532,
+ SPELL_AURA_DISABLE_NAVIGATION = 533, // disables map pins
+ SPELL_AURA_534 = 534,
TOTAL_AURAS
};
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index e1d291eb857..3ba85fdc262 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -573,10 +573,34 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //504 SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER implemented in Unit::SpellHealingBonusTaken
&AuraEffect::HandleNULL, //505 SPELL_AURA_MOD_PLAYER_CHOICE_REROLLS
&AuraEffect::HandleDisableInertia, //506 SPELL_AURA_DISABLE_INERTIA
- &AuraEffect::HandleNULL, //507
+ &AuraEffect::HandleNoImmediateEffect, //507 SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_BY_LABEL implemented in Unit::SpellDamageBonusTaken
&AuraEffect::HandleNULL, //508
&AuraEffect::HandleNULL, //509
&AuraEffect::HandleNULL, //510 SPELL_AURA_MODIFIED_RAID_INSTANCE
+ &AuraEffect::HandleNULL, //511 SPELL_AURA_APPLY_PROFESSION_EFFECT
+ &AuraEffect::HandleNULL, //512
+ &AuraEffect::HandleNULL, //513
+ &AuraEffect::HandleNULL, //514
+ &AuraEffect::HandleNULL, //515
+ &AuraEffect::HandleNULL, //516
+ &AuraEffect::HandleNULL, //517
+ &AuraEffect::HandleNULL, //518
+ &AuraEffect::HandleNULL, //519 SPELL_AURA_MOD_COOLDOWN_RECOVERY_RATE_ALL
+ &AuraEffect::HandleNULL, //520
+ &AuraEffect::HandleNULL, //521
+ &AuraEffect::HandleNULL, //522
+ &AuraEffect::HandleNULL, //523
+ &AuraEffect::HandleNULL, //524
+ &AuraEffect::HandleNULL, //525 SPELL_AURA_DISPLAY_PROFESSION_EQUIPMENT
+ &AuraEffect::HandleNULL, //526
+ &AuraEffect::HandleNULL, //527
+ &AuraEffect::HandleNULL, //528 SPELL_AURA_ALLOW_BLOCKING_SPELLS
+ &AuraEffect::HandleNULL, //529 SPELL_AURA_MOD_SPELL_BLOCK_CHANCE
+ &AuraEffect::HandleNULL, //530
+ &AuraEffect::HandleNULL, //531
+ &AuraEffect::HandleNULL, //532
+ &AuraEffect::HandleNULL, //533 SPELL_AURA_DISABLE_NAVIGATION
+ &AuraEffect::HandleNULL, //534
};
AuraEffect::AuraEffect(Aura* base, SpellEffectInfo const& spellEfffectInfo, int32 const* baseAmount, Unit* caster) :
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index b045b6473fd..2cd10e0b4e8 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5582,6 +5582,11 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
if (m_spellInfo->ExcludeCasterAuraSpell && unitCaster->HasAura(m_spellInfo->ExcludeCasterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
+ if (m_spellInfo->CasterAuraType && !unitCaster->HasAuraType(m_spellInfo->CasterAuraType))
+ return SPELL_FAILED_CASTER_AURASTATE;
+ if (m_spellInfo->ExcludeCasterAuraType && unitCaster->HasAuraType(m_spellInfo->ExcludeCasterAuraType))
+ return SPELL_FAILED_CASTER_AURASTATE;
+
if (reqCombat && unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat())
return SPELL_FAILED_AFFECTING_COMBAT;
}
@@ -6390,19 +6395,15 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
if (spellEffectInfo.Effect == SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY)
{
- BattlePets::BattlePetBreedQuality quality = BattlePets::BattlePetBreedQuality::Poor;
- switch (spellEffectInfo.BasePoints)
+ auto qualityItr = std::lower_bound(sBattlePetBreedQualityStore.begin(), sBattlePetBreedQualityStore.end(), spellEffectInfo.BasePoints, [](BattlePetBreedQualityEntry const* a1, int32 selector)
{
- case 85:
- quality = BattlePets::BattlePetBreedQuality::Rare;
- break;
- case 75:
- quality = BattlePets::BattlePetBreedQuality::Uncommon;
- break;
- default:
- // Ignore Epic Battle-Stones
- break;
- }
+ return a1->MaxQualityRoll < selector;
+ });
+
+ BattlePets::BattlePetBreedQuality quality = BattlePets::BattlePetBreedQuality::Poor;
+ if (qualityItr != sBattlePetBreedQualityStore.end())
+ quality = BattlePets::BattlePetBreedQuality(qualityItr->QualityEnum);
+
if (battlePet->PacketInfo.Quality >= AsUnderlyingType(quality))
return SPELL_FAILED_CANT_UPGRADE_BATTLE_PET;
}
@@ -6668,7 +6669,7 @@ SpellCastResult Spell::CheckCasterAuras(int32* param1) const
Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
for (AuraEffect const* aurEff : auras)
{
- uint32 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
+ uint64 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
{
foundNotMechanic = true;
@@ -7467,21 +7468,21 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*=
{
Item const* item = m_targets.GetItemTarget();
if (!item)
- return SPELL_FAILED_CANT_BE_DISENCHANTED;
+ return SPELL_FAILED_CANT_BE_SALVAGED;
// prevent disenchanting in trade slot
if (item->GetOwnerGUID() != player->GetGUID())
- return SPELL_FAILED_CANT_BE_DISENCHANTED;
+ return SPELL_FAILED_CANT_BE_SALVAGED;
ItemTemplate const* itemProto = item->GetTemplate();
if (!itemProto)
- return SPELL_FAILED_CANT_BE_DISENCHANTED;
+ return SPELL_FAILED_CANT_BE_SALVAGED;
ItemDisenchantLootEntry const* itemDisenchantLoot = item->GetDisenchantLoot(m_caster->ToPlayer());
if (!itemDisenchantLoot)
- return SPELL_FAILED_CANT_BE_DISENCHANTED;
+ return SPELL_FAILED_CANT_BE_SALVAGED;
if (itemDisenchantLoot->SkillRequired > player->GetSkillValue(SKILL_ENCHANTING))
- return SPELL_FAILED_LOW_CASTLEVEL;
+ return SPELL_FAILED_CANT_BE_SALVAGED_SKILL;
break;
}
case SPELL_EFFECT_PROSPECTING:
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 017a07498b0..e66f4f55ab6 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -403,6 +403,11 @@ class TC_GAME_API Spell
void EffectSendChatMessage();
void EffectGrantBattlePetExperience();
void EffectLearnTransmogIllusion();
+ void EffectModifyAuraStacks();
+ void EffectModifyCooldown();
+ void EffectModifyCooldowns();
+ void EffectModifyCooldownsByCategory();
+ void EffectModifySpellCharges();
typedef std::unordered_set<Aura*> UsedSpellMods;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 6aefb6c38d9..2bde0329e6f 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -371,8 +371,23 @@ NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EF
&Spell::EffectNULL, //285 SPELL_EFFECT_MODIFY_KEYSTONE_2
&Spell::EffectGrantBattlePetExperience, //286 SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE
&Spell::EffectNULL, //287 SPELL_EFFECT_SET_GARRISON_FOLLOWER_LEVEL
- &Spell::EffectUnused, //288 SPELL_EFFECT_288
- &Spell::EffectNULL, //289 SPELL_EFFECT_289
+ &Spell::EffectNULL, //288 SPELL_EFFECT_CRAFT_ITEM
+ &Spell::EffectModifyAuraStacks, //289 SPELL_EFFECT_MODIFY_AURA_STACKS
+ &Spell::EffectModifyCooldown, //290 SPELL_EFFECT_MODIFY_COOLDOWN
+ &Spell::EffectModifyCooldowns, //291 SPELL_EFFECT_MODIFY_COOLDOWNS
+ &Spell::EffectModifyCooldownsByCategory, //292 SPELL_EFFECT_MODIFY_COOLDOWNS_BY_CATEGORY
+ &Spell::EffectModifySpellCharges, //293 SPELL_EFFECT_MODIFY_CHARGES
+ &Spell::EffectNULL, //294 SPELL_EFFECT_CRAFT_LOOT
+ &Spell::EffectNULL, //295 SPELL_EFFECT_SALVAGE_ITEM
+ &Spell::EffectNULL, //296 SPELL_EFFECT_CRAFT_SALVAGE_ITEM
+ &Spell::EffectNULL, //297 SPELL_EFFECT_RECRAFT_ITEM
+ &Spell::EffectNULL, //298 SPELL_EFFECT_CANCEL_ALL_PRIVATE_CONVERSATIONS
+ &Spell::EffectNULL, //299 SPELL_EFFECT_299
+ &Spell::EffectUnused, //300 SPELL_EFFECT_300
+ &Spell::EffectNULL, //301 SPELL_EFFECT_CRAFT_ENCHANT
+ &Spell::EffectNULL, //302 SPELL_EFFECT_GATHERING
+ &Spell::EffectNULL, //303 SPELL_EFFECT_CREATE_TRAIT_TREE_CONFIG
+ &Spell::EffectNULL, //304 SPELL_EFFECT_CHANGE_ACTIVE_COMBAT_TRAIT_CONFIG
};
void Spell::EffectNULL()
@@ -2439,30 +2454,7 @@ void Spell::EffectEnchantItemTmp()
}
// select enchantment duration
- uint32 duration;
-
- // rogue family enchantments exception by duration
- if (m_spellInfo->Id == 38615)
- duration = 1800; // 30 mins
- // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
- else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
- duration = 3600; // 1 hour
- // shaman family enchantments
- else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN)
- duration = 3600; // 30 mins
- // other cases with this SpellVisual already selected
- else if (m_spellInfo->GetSpellVisual() == 215)
- duration = 1800; // 30 mins
- // some fishing pole bonuses except Glow Worm which lasts full hour
- else if (m_spellInfo->GetSpellVisual() == 563 && m_spellInfo->Id != 64401)
- duration = 600; // 10 mins
- else if (m_spellInfo->Id == 29702)
- duration = 300; // 5 mins
- else if (m_spellInfo->Id == 37360)
- duration = 300; // 5 mins
- // default case
- else
- duration = 3600; // 1 hour
+ uint32 duration = pEnchant->Duration;
// item can be in trade slot and have owner diff. from caster
Player* item_owner = itemTarget->GetOwner();
@@ -5385,19 +5377,14 @@ void Spell::EffectChangeBattlePetQuality()
if (!unitTarget || !unitTarget->IsCreature())
return;
- BattlePets::BattlePetBreedQuality quality = BattlePets::BattlePetBreedQuality::Poor;
- switch (damage)
+ auto qualityItr = std::lower_bound(sBattlePetBreedQualityStore.begin(), sBattlePetBreedQualityStore.end(), damage, [](BattlePetBreedQualityEntry const* a1, int32 selector)
{
- case 85:
- quality = BattlePets::BattlePetBreedQuality::Rare;
- break;
- case 75:
- quality = BattlePets::BattlePetBreedQuality::Uncommon;
- break;
- default:
- // Ignore Epic Battle-Stones
- break;
- }
+ return a1->MaxQualityRoll < selector;
+ });
+
+ BattlePets::BattlePetBreedQuality quality = BattlePets::BattlePetBreedQuality::Poor;
+ if (qualityItr != sBattlePetBreedQualityStore.end())
+ quality = BattlePets::BattlePetBreedQuality(qualityItr->QualityEnum);
playerCaster->GetSession()->GetBattlePetMgr()->ChangeBattlePetQuality(unitTarget->GetBattlePetCompanionGUID(), quality);
}
@@ -5815,3 +5802,74 @@ void Spell::EffectLearnTransmogIllusion()
player->GetSession()->GetCollectionMgr()->AddTransmogIllusion(illusionId);
}
+
+void Spell::EffectModifyAuraStacks()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ Aura* targetAura = unitTarget->GetAura(effectInfo->TriggerSpell);
+ if (!targetAura)
+ return;
+
+ switch (effectInfo->MiscValue)
+ {
+ case 0:
+ targetAura->ModStackAmount(damage);
+ break;
+ case 1:
+ targetAura->SetStackAmount(damage);
+ break;
+ default:
+ break;
+ }
+}
+
+void Spell::EffectModifyCooldown()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ unitTarget->GetSpellHistory()->ModifyCooldown(effectInfo->TriggerSpell, Milliseconds(damage));
+}
+
+void Spell::EffectModifyCooldowns()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ unitTarget->GetSpellHistory()->ModifyCoooldowns([this](SpellHistory::CooldownStorageType::iterator itr)
+ {
+ SpellInfo const* spellOnCooldown = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE);
+ if (spellOnCooldown->SpellFamilyName != uint32(effectInfo->MiscValue))
+ return false;
+
+ int32 bitIndex = effectInfo->MiscValueB - 1;
+ if (bitIndex < 0 || uint32(bitIndex) >= sizeof(flag128) * 8)
+ return false;
+
+ flag128 reqFlag;
+ reqFlag[bitIndex / 32] = 1u << (bitIndex % 32);
+ return bool(spellOnCooldown->SpellFamilyFlags & reqFlag);
+ }, Milliseconds(damage));
+}
+
+void Spell::EffectModifyCooldownsByCategory()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ unitTarget->GetSpellHistory()->ModifyCoooldowns([this](SpellHistory::CooldownStorageType::iterator itr)
+ {
+ return sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE)->CategoryId == uint32(effectInfo->MiscValue);
+ }, Milliseconds(damage));
+}
+
+void Spell::EffectModifySpellCharges()
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
+ return;
+
+ for (int32 i = 0; i < damage; ++i)
+ unitTarget->GetSpellHistory()->RestoreCharge(effectInfo->MiscValue);
+}
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index c97b36d0a3a..d3aa6dfdf09 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -568,20 +568,25 @@ void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point
}
}
-void SpellHistory::ModifySpellCooldown(uint32 spellId, Duration offset, bool withoutCategoryCooldown)
+void SpellHistory::ModifySpellCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown)
{
auto itr = _spellCooldowns.find(spellId);
- if (!offset.count() || itr == _spellCooldowns.end())
+ if (!cooldownMod.count() || itr == _spellCooldowns.end())
return;
+ ModifySpellCooldown(itr, cooldownMod, withoutCategoryCooldown);
+}
+
+void SpellHistory::ModifySpellCooldown(CooldownStorageType::iterator& itr, Duration cooldownMod, bool withoutCategoryCooldown)
+{
Clock::time_point now = GameTime::GetTime<Clock>();
- itr->second.CooldownEnd += offset;
+ itr->second.CooldownEnd += cooldownMod;
if (itr->second.CategoryId)
{
if (!withoutCategoryCooldown)
- itr->second.CategoryEnd += offset;
+ itr->second.CategoryEnd += cooldownMod;
// Because category cooldown existence is tied to regular cooldown, we cannot allow a situation where regular cooldown is shorter than category
if (itr->second.CooldownEnd < itr->second.CategoryEnd)
@@ -589,14 +594,14 @@ void SpellHistory::ModifySpellCooldown(uint32 spellId, Duration offset, bool wit
}
if (itr->second.CooldownEnd <= now)
- EraseCooldown(itr);
+ itr = EraseCooldown(itr);
if (Player* playerOwner = GetPlayerOwner())
{
WorldPackets::Spells::ModifyCooldown modifyCooldown;
modifyCooldown.IsPet = _owner != playerOwner;
- modifyCooldown.SpellID = spellId;
- modifyCooldown.DeltaTime = std::chrono::duration_cast<Milliseconds>(offset).count();
+ modifyCooldown.SpellID = itr->second.SpellId;
+ modifyCooldown.DeltaTime = std::chrono::duration_cast<Milliseconds>(cooldownMod).count();
modifyCooldown.WithoutCategoryCooldown = withoutCategoryCooldown;
playerOwner->SendDirectMessage(modifyCooldown.Write());
}
@@ -666,6 +671,9 @@ bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/
if (_spellCooldowns.count(spellInfo->Id) != 0)
return true;
+ if (spellInfo->CooldownAuraSpellId && _owner->HasAura(spellInfo->CooldownAuraSpellId))
+ return true;
+
uint32 category = 0;
GetCooldownDurations(spellInfo, itemId, nullptr, &category, nullptr);
if (!category)
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
index 1a32371153e..f15a51c95c5 100644
--- a/src/server/game/Spells/SpellHistory.h
+++ b/src/server/game/Spells/SpellHistory.h
@@ -113,8 +113,19 @@ public:
void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, uint32 categoryId, Clock::time_point categoryEnd, bool onHold = false);
void ModifyCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown = false);
void ModifyCooldown(SpellInfo const* spellInfo, Duration cooldownMod, bool withoutCategoryCooldown = false);
+ template<typename Predicate>
+ void ModifyCoooldowns(Predicate&& predicate, Duration cooldownMod, bool withoutCategoryCooldown = false)
+ {
+ for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
+ {
+ if (predicate(itr))
+ ModifySpellCooldown(itr, cooldownMod, withoutCategoryCooldown);
+ else
+ ++itr;
+ }
+ }
+
void ResetCooldown(uint32 spellId, bool update = false);
- void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
template<typename Predicate>
void ResetCooldowns(Predicate predicate, bool update = false)
{
@@ -166,7 +177,9 @@ public:
private:
Player* GetPlayerOwner() const;
- void ModifySpellCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown = false);
+ void ModifySpellCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown);
+ void ModifySpellCooldown(CooldownStorageType::iterator& itr, Duration cooldownMod, bool withoutCategoryCooldown);
+ void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
void SendClearCooldowns(std::vector<int32> const& cooldowns) const;
CooldownStorageType::iterator EraseCooldown(CooldownStorageType::iterator itr)
{
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 9317c8d2e73..fa6221427bb 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1096,8 +1096,23 @@ std::array<SpellEffectInfo::StaticData, TOTAL_SPELL_EFFECTS> SpellEffectInfo::_d
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 285 SPELL_EFFECT_MODIFY_KEYSTONE_2
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 286 SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 287 SPELL_EFFECT_SET_GARRISON_FOLLOWER_LEVEL
- {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 288 SPELL_EFFECT_288
- {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 289 SPELL_EFFECT_289
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 288 SPELL_EFFECT_CRAFT_ITEM
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 289 SPELL_EFFECT_MODIFY_AURA_STACKS
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 290 SPELL_EFFECT_MODIFY_COOLDOWN
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 291 SPELL_EFFECT_MODIFY_COOLDOWNS
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 292 SPELL_EFFECT_MODIFY_COOLDOWNS_BY_CATEGORY
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 293 SPELL_EFFECT_MODIFY_CHARGES
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 294 SPELL_EFFECT_CRAFT_LOOT
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_ITEM}, // 295 SPELL_EFFECT_SALVAGE_ITEM
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_ITEM}, // 296 SPELL_EFFECT_CRAFT_SALVAGE_ITEM
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_ITEM}, // 297 SPELL_EFFECT_RECRAFT_ITEM
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 298 SPELL_EFFECT_CANCEL_ALL_PRIVATE_CONVERSATIONS
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 299 SPELL_EFFECT_299
+ {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 300 SPELL_EFFECT_300
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_ITEM}, // 301 SPELL_EFFECT_CRAFT_ENCHANT
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_NONE}, // 302 SPELL_EFFECT_GATHERING
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 303 SPELL_EFFECT_CREATE_TRAIT_TREE_CONFIG
+ {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 304 SPELL_EFFECT_CHANGE_ACTIVE_COMBAT_TRAIT_CONFIG
} };
SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, SpellInfoLoadHelper const& data)
@@ -1184,6 +1199,10 @@ SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, S
TargetAuraSpell = _aura->TargetAuraSpell;
ExcludeCasterAuraSpell = _aura->ExcludeCasterAuraSpell;
ExcludeTargetAuraSpell = _aura->ExcludeTargetAuraSpell;
+ CasterAuraType = AuraType(_aura->CasterAuraType);
+ TargetAuraType = AuraType(_aura->TargetAuraType);
+ ExcludeCasterAuraType = AuraType(_aura->ExcludeCasterAuraType);
+ ExcludeTargetAuraType = AuraType(_aura->ExcludeTargetAuraType);
}
// SpellCastingRequirementsEntry
@@ -1219,6 +1238,7 @@ SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, S
RecoveryTime = _cooldowns->RecoveryTime;
CategoryRecoveryTime = _cooldowns->CategoryRecoveryTime;
StartRecoveryTime = _cooldowns->StartRecoveryTime;
+ CooldownAuraSpellId = _cooldowns->AuraSpellID;
}
// SpellEquippedItemsEntry
@@ -3924,7 +3944,7 @@ Optional<SpellPowerCost> SpellInfo::CalcPowerCost(SpellPowerEntry const* power,
powerCost += int32(CalculatePct(unitCaster->GetCreateMana(), power->PowerCostPct));
break;
case POWER_ALTERNATE_POWER:
- TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", power->PowerType, Id);
+ TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type POWER_ALTERNATE_POWER in spell %d", Id);
return {};
default:
{
@@ -3943,6 +3963,35 @@ Optional<SpellPowerCost> SpellInfo::CalcPowerCost(SpellPowerEntry const* power,
else
{
powerCost = int32(power->OptionalCost);
+
+ if (power->OptionalCostPct)
+ {
+ switch (power->PowerType)
+ {
+ // health as power used
+ case POWER_HEALTH:
+ powerCost += int32(CalculatePct(unitCaster->GetMaxHealth(), power->OptionalCostPct));
+ break;
+ case POWER_MANA:
+ powerCost += int32(CalculatePct(unitCaster->GetCreateMana(), power->OptionalCostPct));
+ break;
+ case POWER_ALTERNATE_POWER:
+ TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unsupported power type POWER_ALTERNATE_POWER in spell %d for optional cost percent", Id);
+ return {};
+ default:
+ {
+ if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(Powers(power->PowerType)))
+ {
+ powerCost += int32(CalculatePct(powerTypeEntry->MaxBasePower, power->OptionalCostPct));
+ break;
+ }
+
+ TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d for optional cost percent", power->PowerType, Id);
+ return {};
+ }
+ }
+ }
+
powerCost += unitCaster->GetTotalAuraModifier(SPELL_AURA_MOD_ADDITIONAL_POWER_COST, [this, power](AuraEffect const* aurEff) -> bool
{
return aurEff->GetMiscValue() == power->PowerType
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 100c1166ee4..878904a6444 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -380,11 +380,16 @@ class TC_GAME_API SpellInfo
uint32 TargetAuraSpell = 0;
uint32 ExcludeCasterAuraSpell = 0;
uint32 ExcludeTargetAuraSpell = 0;
+ AuraType CasterAuraType = SPELL_AURA_NONE;
+ AuraType TargetAuraType = SPELL_AURA_NONE;
+ AuraType ExcludeCasterAuraType = SPELL_AURA_NONE;
+ AuraType ExcludeTargetAuraType = SPELL_AURA_NONE;
SpellCastTimesEntry const* CastTimeEntry = nullptr;
uint32 RecoveryTime = 0;
uint32 CategoryRecoveryTime = 0;
uint32 StartRecoveryCategory = 0;
uint32 StartRecoveryTime = 0;
+ uint32 CooldownAuraSpellId = 0;
EnumFlag<SpellInterruptFlags> InterruptFlags = SpellInterruptFlags::None;
EnumFlag<SpellAuraInterruptFlags> AuraInterruptFlags = SpellAuraInterruptFlags::None;
EnumFlag<SpellAuraInterruptFlags2> AuraInterruptFlags2 = SpellAuraInterruptFlags2::None;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 9d90a5560bb..05554c372b5 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2767,17 +2767,19 @@ void SpellMgr::LoadSpellInfoServerside()
"AttributesEx4, AttributesEx5, AttributesEx6, AttributesEx7, AttributesEx8, AttributesEx9, AttributesEx10, AttributesEx11, AttributesEx12, AttributesEx13, "
// 19 20 21 22 23 24 25 26 27
"AttributesEx14, Stances, StancesNot, Targets, TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, "
- // 28 29 30 31 32 33 34
- "ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex, "
- // 35 36 37 38 39 40 41
+ // 28 29 30 31 32 33
+ "ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, "
+ // 34 35 36 37 38
+ "CasterAuraType, TargetAuraType, ExcludeCasterAuraType, ExcludeTargetAuraType, CastingTimeIndex, "
+ // 39 40 41 42 43 44 45
"RecoveryTime, CategoryRecoveryTime, StartRecoveryCategory, StartRecoveryTime, InterruptFlags, AuraInterruptFlags1, AuraInterruptFlags2, "
- // 42 43 44 45 46 47 48 49 50 51 52
+ // 46 47 48 49 50 51 52 53 54 55 56
"ChannelInterruptFlags1, ChannelInterruptFlags2, ProcFlags, ProcFlags2, ProcChance, ProcCharges, ProcCooldown, ProcBasePPM, MaxLevel, BaseLevel, SpellLevel, "
- // 35 54 55 56 57 58 59 60 61
+ // 57 58 59 60 61 62 63 64 65
"DurationIndex, RangeIndex, Speed, LaunchDelay, StackAmount, EquippedItemClass, EquippedItemSubClassMask, EquippedItemInventoryTypeMask, ContentTuningId, "
- // 62 63 64 65 66 67 68 69 70 71
+ // 66 67 68 69 70 71 72 73 74 75
"SpellName, ConeAngle, ConeWidth, MaxTargetLevel, MaxAffectedTargets, SpellFamilyName, SpellFamilyFlags1, SpellFamilyFlags2, SpellFamilyFlags3, SpellFamilyFlags4, "
- // 72 73 74 75 76
+ // 76 77 78 79 80
"DmgClass, PreventionType, AreaGroupId, SchoolMask, ChargeCategoryId FROM serverside_spell");
if (spellsResult)
{
@@ -2795,7 +2797,7 @@ void SpellMgr::LoadSpellInfoServerside()
continue;
}
- mServersideSpellNames.emplace_back(spellId, fields[62].GetString());
+ mServersideSpellNames.emplace_back(spellId, fields[66].GetString());
SpellInfo& spellInfo = const_cast<SpellInfo&>(*mSpellInfoMap.emplace(&mServersideSpellNames.back().Name, difficulty, spellEffects[{ spellId, difficulty }]).first);
spellInfo.CategoryId = fields[2].GetUInt32();
@@ -2830,45 +2832,49 @@ void SpellMgr::LoadSpellInfoServerside()
spellInfo.TargetAuraSpell = fields[31].GetUInt32();
spellInfo.ExcludeCasterAuraSpell = fields[32].GetUInt32();
spellInfo.ExcludeTargetAuraSpell = fields[33].GetUInt32();
- spellInfo.CastTimeEntry = sSpellCastTimesStore.LookupEntry(fields[34].GetUInt32());
- spellInfo.RecoveryTime = fields[35].GetUInt32();
- spellInfo.CategoryRecoveryTime = fields[36].GetUInt32();
- spellInfo.StartRecoveryCategory = fields[37].GetUInt32();
- spellInfo.StartRecoveryTime = fields[38].GetUInt32();
- spellInfo.InterruptFlags = SpellInterruptFlags(fields[39].GetUInt32());
- spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags(fields[40].GetUInt32());
- spellInfo.AuraInterruptFlags2 = SpellAuraInterruptFlags2(fields[41].GetUInt32());
- spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags(fields[42].GetUInt32());
- spellInfo.ChannelInterruptFlags2 = SpellAuraInterruptFlags2(fields[43].GetUInt32());
- spellInfo.ProcFlags[0] = fields[44].GetUInt32();
- spellInfo.ProcFlags[1] = fields[45].GetUInt32();
- spellInfo.ProcChance = fields[46].GetUInt32();
- spellInfo.ProcCharges = fields[47].GetUInt32();
- spellInfo.ProcCooldown = fields[48].GetUInt32();
- spellInfo.ProcBasePPM = fields[49].GetFloat();
- spellInfo.MaxLevel = fields[50].GetUInt32();
- spellInfo.BaseLevel = fields[51].GetUInt32();
- spellInfo.SpellLevel = fields[52].GetUInt32();
- spellInfo.DurationEntry = sSpellDurationStore.LookupEntry(fields[53].GetUInt32());
- spellInfo.RangeEntry = sSpellRangeStore.LookupEntry(fields[54].GetUInt32());
- spellInfo.Speed = fields[55].GetFloat();
- spellInfo.LaunchDelay = fields[56].GetFloat();
- spellInfo.StackAmount = fields[57].GetUInt32();
- spellInfo.EquippedItemClass = fields[58].GetInt32();
- spellInfo.EquippedItemSubClassMask = fields[59].GetInt32();
- spellInfo.EquippedItemInventoryTypeMask = fields[60].GetInt32();
- spellInfo.ContentTuningId = fields[61].GetUInt32();
- spellInfo.ConeAngle = fields[63].GetFloat();
- spellInfo.Width = fields[64].GetFloat();
- spellInfo.MaxTargetLevel = fields[65].GetUInt32();
- spellInfo.MaxAffectedTargets = fields[66].GetUInt32();
- spellInfo.SpellFamilyName = fields[67].GetUInt32();
- spellInfo.SpellFamilyFlags = flag128(fields[68].GetUInt32(), fields[69].GetUInt32(), fields[70].GetUInt32(), fields[71].GetUInt32());
- spellInfo.DmgClass = fields[72].GetUInt32();
- spellInfo.PreventionType = fields[73].GetUInt32();
- spellInfo.RequiredAreasID = fields[74].GetInt32();
- spellInfo.SchoolMask = fields[75].GetUInt32();
- spellInfo.ChargeCategoryId = fields[76].GetUInt32();
+ spellInfo.CasterAuraType = AuraType(fields[34].GetInt32());
+ spellInfo.TargetAuraType = AuraType(fields[35].GetInt32());
+ spellInfo.ExcludeCasterAuraType = AuraType(fields[36].GetInt32());
+ spellInfo.ExcludeTargetAuraType = AuraType(fields[37].GetInt32());
+ spellInfo.CastTimeEntry = sSpellCastTimesStore.LookupEntry(fields[38].GetUInt32());
+ spellInfo.RecoveryTime = fields[39].GetUInt32();
+ spellInfo.CategoryRecoveryTime = fields[40].GetUInt32();
+ spellInfo.StartRecoveryCategory = fields[41].GetUInt32();
+ spellInfo.StartRecoveryTime = fields[42].GetUInt32();
+ spellInfo.InterruptFlags = SpellInterruptFlags(fields[43].GetUInt32());
+ spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags(fields[44].GetUInt32());
+ spellInfo.AuraInterruptFlags2 = SpellAuraInterruptFlags2(fields[45].GetUInt32());
+ spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags(fields[46].GetUInt32());
+ spellInfo.ChannelInterruptFlags2 = SpellAuraInterruptFlags2(fields[47].GetUInt32());
+ spellInfo.ProcFlags[0] = fields[48].GetUInt32();
+ spellInfo.ProcFlags[1] = fields[49].GetUInt32();
+ spellInfo.ProcChance = fields[50].GetUInt32();
+ spellInfo.ProcCharges = fields[51].GetUInt32();
+ spellInfo.ProcCooldown = fields[52].GetUInt32();
+ spellInfo.ProcBasePPM = fields[53].GetFloat();
+ spellInfo.MaxLevel = fields[54].GetUInt32();
+ spellInfo.BaseLevel = fields[55].GetUInt32();
+ spellInfo.SpellLevel = fields[56].GetUInt32();
+ spellInfo.DurationEntry = sSpellDurationStore.LookupEntry(fields[57].GetUInt32());
+ spellInfo.RangeEntry = sSpellRangeStore.LookupEntry(fields[58].GetUInt32());
+ spellInfo.Speed = fields[59].GetFloat();
+ spellInfo.LaunchDelay = fields[60].GetFloat();
+ spellInfo.StackAmount = fields[61].GetUInt32();
+ spellInfo.EquippedItemClass = fields[62].GetInt32();
+ spellInfo.EquippedItemSubClassMask = fields[63].GetInt32();
+ spellInfo.EquippedItemInventoryTypeMask = fields[64].GetInt32();
+ spellInfo.ContentTuningId = fields[65].GetUInt32();
+ spellInfo.ConeAngle = fields[67].GetFloat();
+ spellInfo.Width = fields[68].GetFloat();
+ spellInfo.MaxTargetLevel = fields[69].GetUInt32();
+ spellInfo.MaxAffectedTargets = fields[70].GetUInt32();
+ spellInfo.SpellFamilyName = fields[71].GetUInt32();
+ spellInfo.SpellFamilyFlags = flag128(fields[72].GetUInt32(), fields[73].GetUInt32(), fields[74].GetUInt32(), fields[75].GetUInt32());
+ spellInfo.DmgClass = fields[76].GetUInt32();
+ spellInfo.PreventionType = fields[77].GetUInt32();
+ spellInfo.RequiredAreasID = fields[78].GetInt32();
+ spellInfo.SchoolMask = fields[79].GetUInt32();
+ spellInfo.ChargeCategoryId = fields[80].GetUInt32();
} while (spellsResult->NextRow());
}