diff options
Diffstat (limited to 'src/server/game/Spells')
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraDefines.h | 28 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 26 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 5 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 134 | ||||
-rw-r--r-- | src/server/game/Spells/SpellHistory.cpp | 22 | ||||
-rw-r--r-- | src/server/game/Spells/SpellHistory.h | 17 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 55 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 5 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 100 |
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()); } |