diff options
Diffstat (limited to 'src')
29 files changed, 507 insertions, 415 deletions
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index a03c4039e91..c53b532658d 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -182,7 +182,7 @@ Creature* ScriptedAI::DoSpawnCreature(uint32 entry, float offsetX, float offsetY return me->SummonCreature(entry, me->GetPositionX() + offsetX, me->GetPositionY() + offsetY, me->GetPositionZ() + offsetZ, angle, TempSummonType(type), despawntime); } -SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effects) +SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, float rangeMin, float rangeMax, SelectEffect effect) { //No target so we can't cast if (!target) @@ -215,7 +215,7 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec continue; //Check the type of spell if we are looking for a specific spell type - if (effects && !(SpellSummary[me->m_spells[i]].Effects & (1 << (effects-1)))) + if (effect && !(SpellSummary[me->m_spells[i]].Effects & (1 << (effect-1)))) continue; //Check for school if specified @@ -226,17 +226,6 @@ SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mec if (mechanic && tempSpell->Mechanic != mechanic) continue; - //Make sure that the spell uses the requested amount of power - if (powerCostMin && tempSpell->ManaCost < powerCostMin) - continue; - - if (powerCostMax && tempSpell->ManaCost > powerCostMax) - continue; - - //Continue if we don't have the mana to actually cast this spell - if (tempSpell->ManaCost > (uint32)me->GetPower(Powers(tempSpell->PowerType))) - continue; - //Check if the spell meets our range requirements if (rangeMin && me->GetSpellMinRangeForTarget(target, tempSpell) < rangeMin) continue; diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 5763f3a47da..74d0654dff2 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -250,7 +250,7 @@ struct ScriptedAI : public CreatureAI bool HealthAbovePct(uint32 pct) const { return me->HealthAbovePct(pct); } //Returns spells that meet the specified criteria from the creatures spell list - SpellInfo const* SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effect); + SpellInfo const* SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, float rangeMin, float rangeMax, SelectEffect effect); void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 797abc201dc..108e5cedd09 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -491,12 +491,32 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u bool _allowMove = false; SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(e.action.cast.spell); - int32 mana = me->GetPower(POWER_MANA); + std::vector<SpellInfo::CostData> costs = spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()); + bool hasPower = true; + for (SpellInfo::CostData const& cost : costs) + { + if (cost.Power == POWER_HEALTH) + { + if (me->GetHealth() <= cost.Amount) + { + hasPower = false; + break; + } + } + else + { + if (me->GetPower(cost.Power) < cost.Amount) + { + hasPower = false; + break; + } + } + + } if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || me->GetDistance(*itr) < spellInfo->GetMinRange(true) || - !me->IsWithinLOSInMap(*itr) || - mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) + !me->IsWithinLOSInMap(*itr) || !hasPower) _allowMove = true; ENSURE_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index f6fb39fea75..3efb2297c93 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -50,6 +50,7 @@ DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore("SpellClassO DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore("SpellLearnSpell.db2", SpellLearnSpellFormat, HOTFIX_SEL_SPELL_LEARN_SPELL); DB2Storage<SpellMiscEntry> sSpellMiscStore("SpellMisc.db2", SpellMiscFormat, HOTFIX_SEL_SPELL_MISC); DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerFormat, HOTFIX_SEL_SPELL_POWER); +DB2Storage<SpellPowerDifficultyEntry> sSpellPowerDifficultyStore("SpellPowerDifficulty.db2", SpellPowerDifficultyFormat, HOTFIX_SEL_SPELL_POWER_DIFFICULTY); DB2Storage<SpellReagentsEntry> sSpellReagentsStore("SpellReagents.db2", SpellReagentsFormat, HOTFIX_SEL_SPELL_REAGENTS); DB2Storage<SpellRuneCostEntry> sSpellRuneCostStore("SpellRuneCost.db2", SpellRuneCostFormat, HOTFIX_SEL_SPELL_RUNE_COST); DB2Storage<SpellTotemsEntry> sSpellTotemsStore("SpellTotems.db2", SpellTotemsFormat, HOTFIX_SEL_SPELL_TOTEMS); @@ -57,7 +58,6 @@ DB2Storage<TaxiNodesEntry> sTaxiNodesStore("TaxiNodes.db2", Tax DB2Storage<TaxiPathEntry> sTaxiPathStore("TaxiPath.db2", TaxiPathFormat, HOTFIX_SEL_TAXI_PATH); DB2Storage<TaxiPathNodeEntry> sTaxiPathNodeStore("TaxiPathNode.db2", TaxiPathNodeFormat, HOTFIX_SEL_TAXI_PATH_NODE); -SpellPowerBySpellIDMap sSpellPowerBySpellIDStore; TaxiMask sTaxiNodesMask; TaxiMask sOldContinentsNodesMask; TaxiMask sHordeTaxiNodesMask; @@ -199,7 +199,24 @@ void DB2Manager::LoadStores(std::string const& dataPath) _phasesByGroup[group->PhaseGroupID].insert(phase->ID); for (SpellPowerEntry const* power : sSpellPowerStore) - sSpellPowerBySpellIDStore[power->SpellID] = power; + { + if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID)) + { + std::vector<SpellPowerEntry const*>& powers = _spellPowerDifficulties[power->SpellID][powerDifficulty->DifficultyID]; + if (powers.size() <= powerDifficulty->PowerIndex) + powers.resize(powerDifficulty->PowerIndex + 1); + + powers[powerDifficulty->PowerIndex] = power; + } + else + { + std::vector<SpellPowerEntry const*>& powers = _spellPowers[power->SpellID]; + if (powers.size() <= power->PowerIndex) + powers.resize(power->PowerIndex + 1); + + powers[power->PowerIndex] = power; + } + } for (TaxiPathEntry const* entry : sTaxiPathStore) sTaxiPathSetBySource[entry->From][entry->To] = TaxiPathBySourceAndDestination(entry->ID, entry->Cost); @@ -475,3 +492,45 @@ std::set<uint32> DB2Manager::GetPhasesForGroup(uint32 group) const return std::set<uint32>(); } + +std::vector<SpellPowerEntry const*> DB2Manager::GetSpellPowers(uint32 spellId, Difficulty difficulty /*= DIFFICULTY_NONE*/, bool* hasDifficultyPowers /*= nullptr*/) const +{ + std::vector<SpellPowerEntry const*> powers; + + auto difficultyItr = _spellPowerDifficulties.find(spellId); + if (difficultyItr != _spellPowerDifficulties.end()) + { + if (hasDifficultyPowers) + *hasDifficultyPowers = true; + + DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty); + while (difficultyEntry) + { + auto powerDifficultyItr = difficultyItr->second.find(difficultyEntry->ID); + if (powerDifficultyItr != difficultyItr->second.end()) + { + if (powerDifficultyItr->second.size() > powers.size()) + powers.resize(powerDifficultyItr->second.size()); + + for (SpellPowerEntry const* difficultyPower : powerDifficultyItr->second) + if (!powers[difficultyPower->PowerIndex]) + powers[difficultyPower->PowerIndex] = difficultyPower; + } + + difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID); + } + } + + auto itr = _spellPowers.find(spellId); + if (itr != _spellPowers.end()) + { + if (itr->second.size() > powers.size()) + powers.resize(itr->second.size()); + + for (SpellPowerEntry const* power : itr->second) + if (!powers[power->PowerIndex]) + powers[power->PowerIndex] = power; + } + + return powers; +} diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 3dff3d2a4c0..8fdf23ec58c 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -44,7 +44,6 @@ extern DB2Storage<SpellTotemsEntry> sSpellTotemsStore; extern DB2Storage<TaxiNodesEntry> sTaxiNodesStore; extern DB2Storage<TaxiPathEntry> sTaxiPathStore; -extern SpellPowerBySpellIDMap sSpellPowerBySpellIDStore; extern TaxiMask sTaxiNodesMask; extern TaxiMask sOldContinentsNodesMask; extern TaxiMask sHordeTaxiNodesMask; @@ -75,6 +74,8 @@ public: typedef std::unordered_map<uint32, std::set<ItemBonusTreeNodeEntry const*>> ItemBonusTreeContainer; typedef std::unordered_map<uint32, MountEntry const*> MountContainer; typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer; + typedef std::unordered_map<uint32, std::vector<SpellPowerEntry const*>> SpellPowerContainer; + typedef std::unordered_map<uint32, std::unordered_map<uint32, std::vector<SpellPowerEntry const*>>> SpellPowerDifficultyContainer; static DB2Manager& Instance() { @@ -97,6 +98,7 @@ public: uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const; MountEntry const* GetMount(uint32 spellId) const; std::set<uint32> GetPhasesForGroup(uint32 group) const; + std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const; private: StorageMap _stores; @@ -110,6 +112,8 @@ private: ItemToBonusTreeContainer _itemToBonusTree; MountContainer _mountsBySpellId; PhaseGroupContainer _phasesByGroup; + SpellPowerContainer _spellPowers; + SpellPowerDifficultyContainer _spellPowerDifficulties; }; #define sDB2Manager DB2Manager::Instance() diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 6c333b70682..e52acc0e2c3 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -405,6 +405,13 @@ struct SpellPowerEntry float HealthCostPercentage; // 13 }; +struct SpellPowerDifficultyEntry +{ + uint32 SpellPowerID; // 0 + uint32 DifficultyID; // 1 + uint32 PowerIndex; // 2 +}; + #define MAX_SPELL_REAGENTS 8 struct SpellReagentsEntry @@ -471,8 +478,6 @@ struct TaxiPathNodeEntry #pragma pack(pop) -typedef std::map<uint32, SpellPowerEntry const*> SpellPowerBySpellIDMap; - struct TaxiPathBySourceAndDestination { TaxiPathBySourceAndDestination() : ID(0), price(0) { } diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index 1920f2b90b4..baab3cf9302 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -45,6 +45,7 @@ char const SpellClassOptionsFormat[] = "niiiiii"; char const SpellLearnSpellFormat[] = "niii"; char const SpellMiscFormat[] = "niiiiiiiiiiiiiiiiifiiiiif"; char const SpellPowerFormat[] = "niiiiiiiiiffif"; +char const SpellPowerDifficultyFormat[] = "nii"; char const SpellReagentsFormat[] = "niiiiiiiiiiiiiiiiii"; char const SpellRuneCostFormat[] = "niiiii"; char const SpellTotemsFormat[] = "niiii"; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 096b4b749be..f5c7b42292e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1721,8 +1721,12 @@ SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) if (bcontinue) continue; - if (spellInfo->ManaCost > (uint32)GetPower(POWER_MANA)) - continue; + std::vector<SpellInfo::CostData> costs = spellInfo->CalcPowerCost(this, SpellSchoolMask(spellInfo->SchoolMask)); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + if (m->Amount > (uint32)GetPower(POWER_MANA)) + continue; + float range = spellInfo->GetMaxRange(false); float minrange = spellInfo->GetMinRange(false); float dist = GetDistance(victim); @@ -1765,8 +1769,11 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim) if (bcontinue) continue; - if (spellInfo->ManaCost > (uint32)GetPower(POWER_MANA)) - continue; + std::vector<SpellInfo::CostData> costs = spellInfo->CalcPowerCost(this, SpellSchoolMask(spellInfo->SchoolMask)); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + if (m->Amount > (uint32)GetPower(POWER_MANA)) + continue; float range = spellInfo->GetMaxRange(true); float minrange = spellInfo->GetMinRange(true); diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index a73d570d0e7..b4b08d7ace2 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -162,7 +162,7 @@ class ObjectGuid return UI64LIT(0xFFFFFFFFFF); } - uint32 GetMaxCounter() const { return GetMaxCounter(GetHigh()); } + LowType GetMaxCounter() const { return GetMaxCounter(GetHigh()); } uint8& operator[](uint32 index) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 88de4a88bfc..caeac1c73ea 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5491,7 +5491,12 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere case 28719: { // mana back - basepoints0 = int32(CalculatePct(procSpell->ManaCost, 30)); + std::vector<SpellInfo::CostData> costs = procSpell->CalcPowerCost(this, procSpell->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m == costs.end()) + return false; + + basepoints0 = int32(CalculatePct(m->Amount, 30)); target = this; triggered_spell_id = 28742; break; @@ -6712,7 +6717,12 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg // Enlightenment (trigger only from mana cost spells) case 35095: { - if (!procSpell || procSpell->PowerType != POWER_MANA || (procSpell->ManaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->ManaCostPerlevel == 0)) + if (!procSpell) + return false; + + std::vector<SpellInfo::CostData> costs = procSpell->CalcPowerCost(this, procSpell->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA && cost.Amount > 0; }); + if (m == costs.end()) return false; break; } @@ -11510,16 +11520,28 @@ int32 Unit::GetCreatePowers(Powers power) const return (GetTypeId() == TYPEID_PLAYER || !((Creature const*)this)->IsPet() || ((Pet const*)this)->getPetType() != HUNTER_PET ? 0 : 100); case POWER_ENERGY: return 100; + case POWER_COMBO_POINTS: + return 5; case POWER_RUNIC_POWER: return 1000; case POWER_RUNES: return 0; case POWER_SOUL_SHARDS: - return 3; + return 400; case POWER_ECLIPSE: return 100; case POWER_HOLY_POWER: return 3; + case POWER_CHI: + return 4; + case POWER_SHADOW_ORBS: + return 3; + case POWER_BURNING_EMBERS: + return 40; + case POWER_DEMONIC_FURY: + return 1000; + case POWER_ARCANE_CHARGES: + return 4; case POWER_HEALTH: return 0; default: @@ -12322,10 +12344,13 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: case SPELL_AURA_MOD_POWER_COST_SCHOOL: // Skip melee hits and spells ws wrong school or zero cost - if (procSpell && - (procSpell->ManaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check - (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check - takeCharges = true; + if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check + { + std::vector<SpellInfo::CostData> costs = procSpell->CalcPowerCost(this, procSpell->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Amount > 0; }); + if (m != costs.end()) + takeCharges = true; + } break; case SPELL_AURA_MECHANIC_IMMUNITY: // Compare mechanic diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6112975a1b2..f7a87dddebe 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6239,30 +6239,11 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo()); - bool haveCastItem = !GetBase()->GetCastItemGUID().IsEmpty(); - - // Health Funnel - // damage caster for heal amount - if (target != caster && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && GetSpellInfo()->Id != 755) - { - uint32 funnelDamage = GetSpellInfo()->ManaPerSecond; // damage is not affected by spell power - - if ((int32)funnelDamage > gain && gain > 0) - funnelDamage = gain; - - uint32 funnelAbsorb = 0; - caster->DealDamageMods(caster, funnelDamage, &funnelAbsorb); - caster->SendSpellNonMeleeDamageLog(caster, GetId(), funnelDamage, GetSpellInfo()->GetSchoolMask(), funnelAbsorb, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - caster->DealDamage(caster, funnelDamage, &cleanDamage, NODAMAGE, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); - } - uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; // ignore item heals - if (!haveCastItem) + if (GetBase()->GetCastItemGUID().IsEmpty()) caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo()); } @@ -6286,17 +6267,6 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con // ignore negative values (can be result apply spellmods to aura damage int32 drainAmount = std::max(m_amount, 0); - // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana) - // It's mana percent cost spells, m_amount is percent drain from target - if (m_spellInfo->ManaCostPercentage) - { - // max value - int32 maxmana = CalculatePct(caster->GetMaxPower(powerType), drainAmount * 2.0f); - ApplyPct(drainAmount, target->GetMaxPower(powerType)); - if (drainAmount > maxmana) - drainAmount = maxmana; - } - TC_LOG_DEBUG("spells.periodic", "PeriodicTick: %s power leech of %s for %u dmg inflicted by %u", GetCasterGUID().ToString().c_str(), target->GetGUID().ToString().c_str(), drainAmount, GetId()); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 6fa4936ffa0..9f09242b37c 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -369,7 +369,12 @@ m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr) { - if (m_spellInfo->ManaPerSecond) + std::vector<SpellPowerEntry const*> powers = sDB2Manager.GetSpellPowers(GetId(), caster ? caster->GetMap()->GetDifficultyID() : DIFFICULTY_NONE); + for (SpellPowerEntry const* power : powers) + if (power->ManaCostPerSecond != 0 || power->ManaCostPercentagePerSecond > 0.0f) + m_periodicCosts.push_back(power); + + if (!m_periodicCosts.empty()) m_timeCla = 1 * IN_MILLISECONDS; m_maxDuration = CalcMaxDuration(caster); @@ -737,22 +742,37 @@ void Aura::Update(uint32 diff, Unit* caster) m_timeCla -= diff; else if (caster) { - if (int32 manaPerSecond = m_spellInfo->ManaPerSecond) + if (!m_periodicCosts.empty()) { m_timeCla += 1000 - diff; - Powers powertype = Powers(m_spellInfo->PowerType); - if (powertype == POWER_HEALTH) + for (SpellPowerEntry const* power : m_periodicCosts) { - if (int32(caster->GetHealth()) > manaPerSecond) - caster->ModifyHealth(-manaPerSecond); + if (power->RequiredAura && !caster->HasAura(power->RequiredAura)) + continue; + + int32 manaPerSecond = power->ManaCostPerSecond; + Powers powertype = Powers(power->PowerType); + if (powertype != POWER_HEALTH) + manaPerSecond += int32(CalculatePct(caster->GetMaxPower(powertype), power->ManaCostPercentagePerSecond)); else - Remove(); + manaPerSecond += int32(CalculatePct(caster->GetMaxHealth(), power->ManaCostPercentagePerSecond)); + + if (manaPerSecond) + { + if (powertype == POWER_HEALTH) + { + if (int32(caster->GetHealth()) > manaPerSecond) + caster->ModifyHealth(-manaPerSecond); + else + Remove(); + } + else if (int32(caster->GetPower(powertype)) >= manaPerSecond) + caster->ModifyPower(powertype, -manaPerSecond); + else + Remove(); + } } - else if (int32(caster->GetPower(powertype)) >= manaPerSecond) - caster->ModifyPower(powertype, -manaPerSecond); - else - Remove(); } } } @@ -809,7 +829,7 @@ void Aura::RefreshDuration(bool withMods) else SetDuration(GetMaxDuration()); - if (m_spellInfo->ManaPerSecond) + if (!m_periodicCosts.empty()) m_timeCla = 1 * IN_MILLISECONDS; } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 8710f312dda..adab5db5843 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -301,6 +301,7 @@ class Aura int32 m_maxDuration; // Max aura duration int32 m_duration; // Current time int32 m_timeCla; // Timer for power per sec calcultion + std::vector<SpellPowerEntry const*> m_periodicCosts;// Periodic costs int32 m_updateTargetMapInterval; // Timer for UpdateTargetMapOfEffect uint8 const m_casterLevel; // Aura level (store caster level for correct show level dep amount) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 44012185f11..ef32ce4275b 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -655,7 +655,6 @@ m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo)), m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell(); m_runesState = 0; - m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before. m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before. m_timer = 0; // will set to castime in prepare m_channeledDuration = 0; // will be setup in Spell::handle_immediate @@ -2966,7 +2965,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->SetSpellModTakingSpell(this, true); // Fill cost data (not use power for item casts - m_powerCost = m_CastItem ? 0 : m_spellInfo->CalcPowerCost(m_caster, m_spellSchoolMask); + if (!m_CastItem) + m_powerCost = m_spellInfo->CalcPowerCost(m_caster, m_spellSchoolMask); if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->SetSpellModTakingSpell(this, false); @@ -3504,9 +3504,6 @@ void Spell::_handle_finish_phase() // Real add combo points from effects if (m_comboPointGain) m_caster->m_movedPlayer->GainSpellComboPoints(m_comboPointGain); - - if (m_spellInfo->PowerType == POWER_HOLY_POWER && m_caster->m_movedPlayer->getClass() == CLASS_PALADIN) - HandleHolyPower(m_caster->m_movedPlayer); } if (m_caster->m_extraAttacks && HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) @@ -3856,10 +3853,11 @@ void Spell::SendSpellStart() if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet())) - && m_spellInfo->PowerType != POWER_HEALTH) + && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellInfo::CostData const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end()) castFlags |= CAST_FLAG_POWER_LEFT_SELF; - if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNES) + if (m_spellInfo->RuneCostID && + std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_RUNES; }) != m_powerCost.end()) castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it WorldPackets::Spells::SpellStart packet; @@ -3880,11 +3878,13 @@ void Spell::SendSpellStart() if (castFlags & CAST_FLAG_POWER_LEFT_SELF) { - /// @todo Implement multiple power types - WorldPackets::Spells::SpellPowerData powerData; - powerData.Type = m_spellInfo->PowerType; - powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType); - castData.RemainingPower.push_back(powerData); + for (SpellInfo::CostData const& cost : m_powerCost) + { + WorldPackets::Spells::SpellPowerData powerData; + powerData.Type = cost.Power; + powerData.Cost = m_caster->GetPower(cost.Power); + castData.RemainingPower.push_back(powerData); + } } if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list @@ -3936,68 +3936,6 @@ void Spell::SendSpellStart() castData.Predict.Type = 0; }**/ - /*WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); - if (m_CastItem) - data << m_CastItem->GetPackGUID(); - else - data << m_caster->GetPackGUID(); - - data << m_caster->GetPackGUID(); - data << uint8(m_cast_count); // pending spell cast? - data << uint32(m_spellInfo->Id); // spellId - data << uint32(castFlags); // cast flags - data << uint32(m_timer); // delay? - data << uint32(m_casttime); - - m_targets.Write(data); - - if (castFlags & CAST_FLAG_POWER_LEFT_SELF) - data << uint32(m_caster->GetPower((Powers)m_spellInfo->PowerType)); - - if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list - { - //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature - //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster - if (Player* player = m_caster->ToPlayer()) - { - data << uint8(m_runesState); // runes state before - data << uint8(player->GetRunesState()); // runes state after - for (uint8 i = 0; i < MAX_RUNES; ++i) - { - // float casts ensure the division is performed on floats as we need float result - float baseCd = float(player->GetRuneBaseCooldown(i)); - data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed - } - } - else - { - data << uint8(0); - data << uint8(0); - for (uint8 i = 0; i < MAX_RUNES; ++i) - data << uint8(0); - } - } - - if (castFlags & CAST_FLAG_PROJECTILE) - { - data << uint32(0); // Ammo display ID - data << uint32(0); // Inventory Type - } - - if (castFlags & CAST_FLAG_IMMUNITY) - { - data << uint32(0); - data << uint32(0); - } - - if (castFlags & CAST_FLAG_HEAL_PREDICTION) - { - data << uint32(0); - data << uint8(0); // unkByte - // if (unkByte == 2) - // data.append(0); - }*/ - m_caster->SendMessageToSet(packet.Write(), true); } @@ -4017,13 +3955,13 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsPet())) - && m_spellInfo->PowerType != POWER_HEALTH) + && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellInfo::CostData const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end()) castFlags |= CAST_FLAG_POWER_LEFT_SELF; // should only be sent to self, but the current messaging doesn't make that possible if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->RuneCostID - && m_spellInfo->PowerType == POWER_RUNES + && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_RUNES; }) != m_powerCost.end() && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it @@ -4059,11 +3997,13 @@ void Spell::SendSpellGo() if (castFlags & CAST_FLAG_POWER_LEFT_SELF) { - /// @todo Implement multiple power types - WorldPackets::Spells::SpellPowerData powerData; - powerData.Type = m_spellInfo->PowerType; - powerData.Cost = m_caster->GetPower((Powers)m_spellInfo->PowerType); - castData.RemainingPower.push_back(powerData); + for (SpellInfo::CostData const& cost : m_powerCost) + { + WorldPackets::Spells::SpellPowerData powerData; + powerData.Type = cost.Power; + powerData.Cost = m_caster->GetPower(cost.Power); + castData.RemainingPower.push_back(powerData); + } } if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list @@ -4449,64 +4389,67 @@ void Spell::TakePower() return; } - Powers powerType = Powers(m_spellInfo->PowerType); - bool hit = true; - if (m_caster->GetTypeId() == TYPEID_PLAYER) + for (SpellInfo::CostData& cost : m_powerCost) { - if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNES) + Powers powerType = Powers(cost.Power); + bool hit = true; + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - ObjectGuid targetGUID = m_targets.GetUnitTargetGUID(); - if (!targetGUID.IsEmpty()) + if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNES) { - for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + ObjectGuid targetGUID = m_targets.GetUnitTargetGUID(); + if (!targetGUID.IsEmpty()) { - if (ihit->targetGUID == targetGUID) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { - if (ihit->missCondition != SPELL_MISS_NONE) + if (ihit->targetGUID == targetGUID) { - hit = false; - //lower spell cost on fail (by talent aura) - if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, m_powerCost); + if (ihit->missCondition != SPELL_MISS_NONE) + { + hit = false; + //lower spell cost on fail (by talent aura) + if (Player* modOwner = m_caster->ToPlayer()->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_SPELL_COST_REFUND_ON_FAIL, cost.Amount); + } + break; } - break; } } } } - } - if (powerType == POWER_RUNES) - { - TakeRunePower(hit); - return; - } + if (powerType == POWER_RUNES) + { + TakeRunePower(hit); + continue; + } - if (!m_powerCost) - return; + if (!cost.Amount) + continue; - // health as power used - if (powerType == POWER_HEALTH) - { - m_caster->ModifyHealth(-(int32)m_powerCost); - return; - } + // health as power used + if (powerType == POWER_HEALTH) + { + m_caster->ModifyHealth(-cost.Amount); + continue; + } - if (powerType >= MAX_POWERS) - { - TC_LOG_ERROR("spells", "Spell::TakePower: Unknown power type '%d'", powerType); - return; - } + if (powerType >= MAX_POWERS) + { + TC_LOG_ERROR("spells", "Spell::TakePower: Unknown power type '%d'", powerType); + continue; + } - if (hit) - m_caster->ModifyPower(powerType, -m_powerCost); - else - m_caster->ModifyPower(powerType, -irand(0, m_powerCost/4)); + if (hit) + m_caster->ModifyPower(powerType, -cost.Amount); + else + m_caster->ModifyPower(powerType, -irand(0, cost.Amount / 4)); + } } SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { - if (m_spellInfo->PowerType != POWER_RUNES || !runeCostID) + if (std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_RUNES; }) == m_powerCost.end() || !runeCostID) return SPELL_CAST_OK; Player* player = m_caster->ToPlayer(); @@ -4714,42 +4657,6 @@ void Spell::HandleThreatSpells() TC_LOG_DEBUG("spells", "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size())); } -void Spell::HandleHolyPower(Player* caster) -{ - if (!caster) - return; - - bool hit = true; - Player* modOwner = caster->GetSpellModOwner(); - - m_powerCost = caster->GetPower(POWER_HOLY_POWER); // Always use all the holy power we have - - if (!m_powerCost || !modOwner) - return; - - ObjectGuid targetGUID = m_targets.GetUnitTargetGUID(); - if (!targetGUID.IsEmpty()) - { - for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - { - if (ihit->targetGUID == targetGUID) - { - if (ihit->missCondition != SPELL_MISS_NONE && ihit->missCondition != SPELL_MISS_MISS) - hit = false; - - break; - } - } - - // The spell did hit the target, apply aura cost mods if there are any. - if (hit) - { - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, m_powerCost); - m_caster->ModifyPower(POWER_HOLY_POWER, -m_powerCost); - } - } -} - void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode) { effectHandleMode = mode; @@ -5961,34 +5868,36 @@ SpellCastResult Spell::CheckPower() if (m_CastItem) return SPELL_CAST_OK; - // health as power used - need check health amount - if (m_spellInfo->PowerType == POWER_HEALTH) + for (SpellInfo::CostData const& cost : m_powerCost) { - if (int32(m_caster->GetHealth()) <= m_powerCost) - return SPELL_FAILED_CASTER_AURASTATE; - return SPELL_CAST_OK; - } - // Check valid power type - if (m_spellInfo->PowerType >= MAX_POWERS) - { - TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '%d'", m_spellInfo->PowerType); - return SPELL_FAILED_UNKNOWN; - } + // health as power used - need check health amount + if (cost.Power == POWER_HEALTH) + { + if (int32(m_caster->GetHealth()) <= cost.Amount) + return SPELL_FAILED_CASTER_AURASTATE; + continue; + } + // Check valid power type + if (cost.Power >= MAX_POWERS) + { + TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '%d'", cost.Power); + return SPELL_FAILED_UNKNOWN; + } - //check rune cost only if a spell has PowerType == POWER_RUNES - if (m_spellInfo->PowerType == POWER_RUNES) - { - SpellCastResult failReason = CheckRuneCost(m_spellInfo->RuneCostID); - if (failReason != SPELL_CAST_OK) - return failReason; + //check rune cost only if a spell has PowerType == POWER_RUNES + if (cost.Power == POWER_RUNES) + { + SpellCastResult failReason = CheckRuneCost(m_spellInfo->RuneCostID); + if (failReason != SPELL_CAST_OK) + return failReason; + } + + // Check power amount + if (int32(m_caster->GetPower(cost.Power)) < cost.Amount) + return SPELL_FAILED_NO_POWER; } - // Check power amount - Powers powerType = Powers(m_spellInfo->PowerType); - if (int32(m_caster->GetPower(powerType)) < m_powerCost) - return SPELL_FAILED_NO_POWER; - else - return SPELL_CAST_OK; + return SPELL_CAST_OK; } SpellCastResult Spell::CheckItems() diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 42c5258f4f8..113ac31b461 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -468,7 +468,6 @@ class Spell void SendChannelStart(uint32 duration); void SendResurrectRequest(Player* target); - void HandleHolyPower(Player* caster); void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode); void HandleThreatSpells(); @@ -517,7 +516,7 @@ class Spell Unit* GetCaster() const { return m_caster; } Unit* GetOriginalCaster() const { return m_originalCaster; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } - int32 GetPowerCost() const { return m_powerCost; } + std::vector<SpellInfo::CostData> GetPowerCost() const { return m_powerCost; } bool UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) @@ -560,7 +559,8 @@ class Spell //Spell data SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) WeaponAttackType m_attackType; // For weapon based attack - int32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare + + std::vector<SpellInfo::CostData> m_powerCost; // Calculated spell cost initialized only in Spell::prepare int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare int32 m_channeledDuration; // Calculated channeled spell duration in order to calculate correct pushback. bool m_canReflect; // can reflect this spell? diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index db332f2fc49..e43d4ec3eab 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4747,13 +4747,18 @@ void Spell::EffectDestroyAllTotems(SpellEffIndex /*effIndex*/) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); if (spellInfo) { - mana += spellInfo->ManaCost; - mana += int32(CalculatePct(m_caster->GetCreateMana(), spellInfo->ManaCostPercentage)); + std::vector<SpellInfo::CostData> costs = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + mana += m->Amount; } + totem->ToTotem()->UnSummon(); } } + ApplyPct(mana, damage); + if (mana) m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true); } @@ -5621,11 +5626,7 @@ void Spell::EffectCastButtons(SpellEffIndex /*effIndex*/) if (!spellInfo->HasAttribute(SPELL_ATTR9_SUMMON_PLAYER_TOTEM)) continue; - int32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask()); - if (m_caster->GetPower(POWER_MANA) < cost) - continue; - - TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_IGNORE_GCD | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY); + TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_IGNORE_GCD | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY | TRIGGERED_DONT_REPORT_CAST_ERROR); m_caster->CastSpell(m_caster, spell_id, triggerFlags); } } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ebc4cf53b98..65b43a436d7 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -942,7 +942,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 244 SPELL_EFFECT_244 }; -SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap const& effectsMap) +SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap const& effectsMap) : _hasPowerDifficultyData(false) { Id = spellEntry->ID; @@ -1084,12 +1084,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap const& ef SpellLevel = _levels ? _levels->SpellLevel : 0; // SpellPowerEntry - SpellPowerEntry const* _power = GetSpellPower(); - ManaCost = _power ? _power->ManaCost : 0; - ManaCostPerlevel = _power ? _power->ManaCostPerLevel : 0; - ManaCostPercentage = _power ? _power->ManaCostPercentage : 0; - ManaPerSecond = _power ? _power->ManaCostPerSecond : 0; - PowerType = _power ? _power->PowerType : 0; + PowerCosts = sDB2Manager.GetSpellPowers(Id, DIFFICULTY_NONE, &_hasPowerDifficultyData); // SpellReagentsEntry SpellReagentsEntry const* _reagents = GetSpellReagents(); @@ -1393,8 +1388,7 @@ bool SpellInfo::IsStackableWithRanks() const { if (IsPassive()) return false; - if (PowerType != POWER_MANA && PowerType != POWER_HEALTH) - return false; + if (IsProfessionOrRiding()) return false; @@ -1423,6 +1417,7 @@ bool SpellInfo::IsStackableWithRanks() const break; } } + return true; } @@ -2524,109 +2519,178 @@ uint32 SpellInfo::GetRecoveryTime() const return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime; } -int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const +std::vector<SpellInfo::CostData> SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const { - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER) + std::vector<CostData> costs; + auto collector = [this, caster, schoolMask, &costs](std::vector<SpellPowerEntry const*> const& powers) { - // If power type - health drain all - if (PowerType == POWER_HEALTH) - return caster->GetHealth(); - // Else drain all power - if (PowerType < MAX_POWERS) - return caster->GetPower(Powers(PowerType)); - TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", PowerType, Id); - return 0; - } + costs.reserve(powers.size()); + int32 healthCost = 0; - // Base powerCost - int32 powerCost = ManaCost; - // PCT cost from total amount - if (ManaCostPercentage) - { - switch (PowerType) + + for (SpellPowerEntry const* power : powers) { - // health as power used - case POWER_HEALTH: - powerCost += int32(CalculatePct(caster->GetCreateHealth(), ManaCostPercentage)); - break; - case POWER_MANA: - powerCost += int32(CalculatePct(caster->GetCreateMana(), ManaCostPercentage)); - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(PowerType)), ManaCostPercentage)); - break; - case POWER_RUNES: - case POWER_RUNIC_POWER: - TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); - break; - default: - TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", PowerType, Id); - return 0; - } - } + if (power->RequiredAura && !caster->HasAura(power->RequiredAura)) + continue; - // Flat mod from caster auras by spell school and power type - Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL); - for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) - { - if (!((*i)->GetMiscValue() & schoolMask)) - continue; - if (!((*i)->GetMiscValueB() & (1 << PowerType))) - continue; - powerCost += (*i)->GetAmount(); - } + // Spell drain all exist power on cast (Only paladin lay of Hands) + if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER) + { + // If power type - health drain all + if (power->PowerType == POWER_HEALTH) + { + healthCost = caster->GetHealth(); + continue; + } + // Else drain all power + if (power->PowerType < MAX_POWERS) + { + CostData cost; + cost.Power = Powers(power->PowerType); + cost.Amount = caster->GetPower(cost.Power); + costs.push_back(cost); + continue; + } - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST) - { - uint32 speed = 0; -/* REVIEW - MERGE - if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm())) - speed = ss->attackSpeed; - else -*/ - { - WeaponAttackType slot = BASE_ATTACK; - if (AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND) - slot = OFF_ATTACK; + TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", power->PowerType, Id); + continue; + } - speed = caster->GetAttackTime(slot); - } + // Base powerCost + int32 powerCost = power->ManaCost; + // PCT cost from total amount + if (power->ManaCostPercentage) + { + switch (power->PowerType) + { + // health as power used + case POWER_HEALTH: + powerCost += int32(CalculatePct(caster->GetMaxHealth(), power->ManaCostPercentage)); + break; + case POWER_MANA: + case POWER_RAGE: + case POWER_FOCUS: + case POWER_ENERGY: + powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(power->PowerType)), power->ManaCostPercentage)); + break; + case POWER_RUNES: + case POWER_RUNIC_POWER: + TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); + break; + default: + TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", power->PowerType, Id); + continue; + } + } - powerCost += speed / 100; - } + if (power->HealthCostPercentage) + healthCost += int32(CalculatePct(caster->GetMaxHealth(), power->HealthCostPercentage)); - // Apply cost mod by spell - if (Player* modOwner = caster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost); + // Flat mod from caster auras by spell school and power type + Unit::AuraEffectList const& auras = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL); + for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) + { + if (!((*i)->GetMiscValue() & schoolMask)) + continue; - if (!caster->IsControlledByPlayer()) - { - if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION) + if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) + continue; + + powerCost += (*i)->GetAmount(); + } + + // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) + if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST) + { + uint32 speed = 0; + if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm())) + speed = ss->CombatRoundTime; + else + { + WeaponAttackType slot = BASE_ATTACK; + if (AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND) + slot = OFF_ATTACK; + + speed = caster->GetAttackTime(slot); + } + + powerCost += speed / 100; + } + + // Apply cost mod by spell + if (Player* modOwner = caster->GetSpellModOwner()) + { + if (power->PowerIndex == 0) + modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost); + else if (power->PowerIndex == 1) + modOwner->ApplySpellMod(Id, SPELLMOD_SPELL_COST2, powerCost); + } + + if (!caster->IsControlledByPlayer()) + { + if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION) + { + GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.EvaluateTable(SpellLevel - 1, 0); + GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.EvaluateTable(caster->getLevel() - 1, 0); + if (spellScaler && casterScaler) + powerCost *= casterScaler->ratio / spellScaler->ratio; + } + } + + // PCT mod from user auras by spell school and power type + Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); + for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) + { + if (!((*i)->GetMiscValue() & schoolMask)) + continue; + + if (!((*i)->GetMiscValueB() & (1 << power->PowerType))) + continue; + + powerCost += CalculatePct(powerCost, (*i)->GetAmount()); + } + + if (power->PowerType == POWER_HEALTH) + { + healthCost += powerCost; + continue; + } + + bool found = false; + for (CostData& cost : costs) + { + if (cost.Power == Powers(power->PowerType)) + { + cost.Amount += powerCost; + found = true; + } + } + + if (!found) + { + CostData cost; + cost.Power = Powers(power->PowerType); + cost.Amount = powerCost; + costs.push_back(cost); + } + } + + if (healthCost > 0) { - GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.EvaluateTable(SpellLevel - 1, 0); - GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.EvaluateTable(caster->getLevel() - 1, 0); - if (spellScaler && casterScaler) - powerCost *= casterScaler->ratio / spellScaler->ratio; + CostData cost; + cost.Power = POWER_HEALTH; + cost.Amount = healthCost; + costs.push_back(cost); } - } + }; - // PCT mod from user auras by spell school and power type - Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); - for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) - { - if (!((*i)->GetMiscValue() & schoolMask)) - continue; - if (!((*i)->GetMiscValueB() & (1 << PowerType))) - continue; - powerCost += CalculatePct(powerCost, (*i)->GetAmount()); - } - if (powerCost < 0) - powerCost = 0; - return powerCost; + if (_hasPowerDifficultyData) // optimization - use static data for 99.5% cases (4753 of 4772 in build 6.1.0.19702) + collector(PowerCosts); + else + collector(sDB2Manager.GetSpellPowers(Id, caster->GetMap()->GetDifficultyID())); + + std::remove_if(costs.begin(), costs.end(), [](CostData const& cost) { return cost.Amount <= 0; }); + return costs; } bool SpellInfo::IsRanked() const @@ -3080,14 +3144,6 @@ SpellLevelsEntry const* SpellInfo::GetSpellLevels() const return SpellLevelsId ? sSpellLevelsStore.LookupEntry(SpellLevelsId) : NULL; } -SpellPowerEntry const* SpellInfo::GetSpellPower() const -{ - auto itr = sSpellPowerBySpellIDStore.find(Id); - if (itr != sSpellPowerBySpellIDStore.end()) - return itr->second; - return NULL; -} - SpellReagentsEntry const* SpellInfo::GetSpellReagents() const { return SpellReagentsId ? sSpellReagentsStore.LookupEntry(SpellReagentsId) : NULL; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 9e39e88d9d3..62381372657 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -370,11 +370,7 @@ public: uint32 BaseLevel; uint32 SpellLevel; SpellDurationEntry const* DurationEntry; - uint32 PowerType; - uint32 ManaCost; - uint32 ManaCostPerlevel; - uint32 ManaPerSecond; - uint32 ManaCostPercentage; + std::vector<SpellPowerEntry const*> PowerCosts; uint32 RuneCostID; SpellRangeEntry const* RangeEntry; float Speed; @@ -443,7 +439,6 @@ public: SpellEquippedItemsEntry const* GetSpellEquippedItems() const; SpellInterruptsEntry const* GetSpellInterrupts() const; SpellLevelsEntry const* GetSpellLevels() const; - SpellPowerEntry const* GetSpellPower() const; SpellReagentsEntry const* GetSpellReagents() const; SpellScalingEntry const* GetSpellScaling() const; SpellShapeshiftEntry const* GetSpellShapeshift() const; @@ -551,7 +546,13 @@ public: uint32 CalcCastTime(uint8 level = 0, Spell* spell = NULL) const; uint32 GetRecoveryTime() const; - int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const; + struct CostData + { + Powers Power; + int32 Amount; + }; + + std::vector<CostData> CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const; bool IsRanked() const; uint8 GetRank() const; @@ -580,6 +581,7 @@ public: SpellEffectInfo const* GetEffect(WorldObject const* obj, uint32 index) const { return GetEffect(obj->GetMap()->GetDifficultyID(), index); } SpellEffectInfoMap _effects; + bool _hasPowerDifficultyData; }; #endif // _SPELLINFO_H diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0d9fcc141bb..518463a9539 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3701,10 +3701,6 @@ void SpellMgr::LoadSpellInfoCorrections() case 40167: // Introspection spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; break; - case 2378: // Minor Fortitude - spellInfo->ManaCost = 0; - spellInfo->ManaPerSecond = 0; - break; // Stonecore spells case 95284: // Teleport (from entrance to Slabhide) case 95285: // Teleport (from Slabhide to entrance) diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 2418e75d22c..84a6fab9318 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -539,8 +539,13 @@ class spell_dru_lifebloom : public SpellScriptLoader GetTarget()->CastCustomSpell(GetTarget(), SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); // restore mana - int32 returnMana = CalculatePct(caster->GetCreateMana(), GetSpellInfo()->ManaCostPercentage) * stack / 2; - caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + std::vector<SpellInfo::CostData> costs = GetSpellInfo()->CalcPowerCost(caster, GetSpellInfo()->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + { + int32 returnMana = m->Amount * stack / 2; + caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + } return; } @@ -562,8 +567,13 @@ class spell_dru_lifebloom : public SpellScriptLoader target->CastCustomSpell(target, SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, NULL, GetCasterGUID()); // restore mana - int32 returnMana = CalculatePct(caster->GetCreateMana(), GetSpellInfo()->ManaCostPercentage) * dispelInfo->GetRemovedCharges() / 2; - caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + std::vector<SpellInfo::CostData> costs = GetSpellInfo()->CalcPowerCost(caster, GetSpellInfo()->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + { + int32 returnMana = m->Amount * dispelInfo->GetRemovedCharges() / 2; + caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + } return; } diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index a0c01479cdb..7952eb325a5 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -947,10 +947,14 @@ class spell_hun_thrill_of_the_hunt : public SpellScriptLoader void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - int32 focus = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), SpellSchoolMask(eventInfo.GetDamageInfo()->GetSchoolMask())); - focus = CalculatePct(focus, aurEff->GetAmount()); - - GetTarget()->CastCustomSpell(GetTarget(), SPELL_HUNTER_THRILL_OF_THE_HUNT, &focus, NULL, NULL, true, NULL, aurEff); + std::vector<SpellInfo::CostData> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), SpellSchoolMask(eventInfo.GetDamageInfo()->GetSchoolMask())); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_FOCUS; }); + if (m != costs.end()) + { + int32 focus = CalculatePct(m->Amount, aurEff->GetAmount()); + if (focus > 0) + GetTarget()->CastCustomSpell(GetTarget(), SPELL_HUNTER_THRILL_OF_THE_HUNT, &focus, NULL, NULL, true, NULL, aurEff); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index 16e819430d2..c5e2deaac24 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -1004,11 +1004,14 @@ class spell_mage_master_of_elements : public SpellScriptLoader { PreventDefaultAction(); - int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask())); - mana = CalculatePct(mana, aurEff->GetAmount()); - - if (mana > 0) - GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + std::vector<SpellInfo::CostData> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + { + int32 mana = CalculatePct(m->Amount, aurEff->GetAmount()); + if (mana > 0) + GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 589f67fc39b..f9224e435af 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -794,10 +794,14 @@ class spell_sha_item_mana_surge : public SpellScriptLoader void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); - int32 mana = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), SpellSchoolMask(eventInfo.GetDamageInfo()->GetSchoolMask())); - mana = int32(CalculatePct(mana, 35)); - - GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + std::vector<SpellInfo::CostData> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()); + auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_MANA; }); + if (m != costs.end()) + { + int32 mana = CalculatePct(m->Amount, 35); + if (mana > 0) + GetTarget()->CastCustomSpell(SPELL_SHAMAN_ITEM_MANA_SURGE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + } } void Register() override diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index efe885843f0..b9127cc08e9 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -92,7 +92,7 @@ public: if (buffTimer <= diff) { //Find a spell that targets friendly and applies an aura (these are generally buffs) - SpellInfo const* info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); + SpellInfo const* info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_AURA); if (info && !globalCooldown) { @@ -124,13 +124,13 @@ public: //Select a healing spell if less than 30% hp if (me->HealthBelowPct(30)) - info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); + info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_HEALING); //No healing spell available, select a hostile spell if (info) healing = true; else - info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE); + info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, SELECT_EFFECT_DONTCARE); //20% chance to replace our white hit with a spell if (info && urand(0, 99) < 20 && !globalCooldown) @@ -160,13 +160,13 @@ public: //Select a healing spell if less than 30% hp ONLY 33% of the time if (me->HealthBelowPct(30) && 33 > urand(0, 99)) - info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); + info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_HEALING); //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) if (info) healing = true; else - info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE); + info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE); //Found a spell, check if we arn't on cooldown if (info && !globalCooldown) diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index dfb7d62bc71..b90ac012ced 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -76,7 +76,7 @@ public: if (BuffTimer <= diff) { //Find a spell that targets friendly and applies an aura (these are generally buffs) - SpellInfo const* info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); + SpellInfo const* info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_AURA); if (info && !GlobalCooldown) { @@ -108,11 +108,11 @@ public: //Select a healing spell if less than 30% hp if (HealthBelowPct(30)) - info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); + info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_HEALING); //No healing spell available, select a hostile spell if (info) Healing = true; - else info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE); + else info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, SELECT_EFFECT_DONTCARE); //50% chance if elite or higher, 20% chance if not, to replace our white hit with a spell if (info && (rand32() % (me->GetCreatureTemplate()->rank > 1 ? 2 : 5) == 0) && !GlobalCooldown) @@ -139,11 +139,11 @@ public: //Select a healing spell if less than 30% hp ONLY 33% of the time if (HealthBelowPct(30) && rand32() % 3 == 0) - info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); + info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, SELECT_EFFECT_HEALING); //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) if (info) Healing = true; - else info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE); + else info = SelectSpell(me->GetVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE); //Found a spell, check if we arn't on cooldown if (info && !GlobalCooldown) diff --git a/src/server/shared/Cryptography/ARC4.cpp b/src/server/shared/Cryptography/ARC4.cpp index 28c3da8d228..4915383f8dc 100644 --- a/src/server/shared/Cryptography/ARC4.cpp +++ b/src/server/shared/Cryptography/ARC4.cpp @@ -19,14 +19,14 @@ #include "ARC4.h" #include <openssl/sha.h> -ARC4::ARC4(uint8 len) : m_ctx() +ARC4::ARC4(uint32 len) : m_ctx() { EVP_CIPHER_CTX_init(&m_ctx); EVP_EncryptInit_ex(&m_ctx, EVP_rc4(), NULL, NULL, NULL); EVP_CIPHER_CTX_set_key_length(&m_ctx, len); } -ARC4::ARC4(uint8 *seed, uint8 len) : m_ctx() +ARC4::ARC4(uint8 *seed, uint32 len) : m_ctx() { EVP_CIPHER_CTX_init(&m_ctx); EVP_EncryptInit_ex(&m_ctx, EVP_rc4(), NULL, NULL, NULL); diff --git a/src/server/shared/Cryptography/ARC4.h b/src/server/shared/Cryptography/ARC4.h index 16a0cb92eb9..aa08901f456 100644 --- a/src/server/shared/Cryptography/ARC4.h +++ b/src/server/shared/Cryptography/ARC4.h @@ -25,8 +25,8 @@ class ARC4 { public: - ARC4(uint8 len); - ARC4(uint8 *seed, uint8 len); + ARC4(uint32 len); + ARC4(uint8 *seed, uint32 len); ~ARC4(); void Init(uint8 *seed); void UpdateData(int len, uint8 *data); diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.cpp b/src/server/shared/Database/Implementation/HotfixDatabase.cpp index f85c1e821a1..7f148f95e00 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/shared/Database/Implementation/HotfixDatabase.cpp @@ -148,9 +148,13 @@ void HotfixDatabaseConnection::DoPrepareStatements() "CastingTimeIndex, DurationIndex, RangeIndex, Speed, SpellVisualID1, SpellVisualID2, SpellIconID, ActiveIconID, " "SchoolMask, MultistrikeSpeedMod FROM spell_misc ORDER BY ID DESC", CONNECTION_SYNCH); + // SpellPower.db2 PrepareStatement(HOTFIX_SEL_SPELL_POWER, "SELECT ID, SpellID, PowerIndex, PowerType, ManaCost, ManaCostPerLevel, ManaCostPerSecond, ManaCostAdditional, " "PowerDisplayID, UnitPowerBarID, ManaCostPercentage, ManaCostPercentagePerSecond, RequiredAura, HealthCostPercentage FROM spell_power ORDER BY ID DESC", CONNECTION_SYNCH); + // SpellPowerDifficulty.db2 + PrepareStatement(HOTFIX_SEL_SPELL_POWER_DIFFICULTY, "SELECT SpellPowerID, DifficultyID, PowerIndex FROM spell_power_difficulty ORDER BY SpellPowerID DESC", CONNECTION_SYNCH); + // SpellReagents.db2 PrepareStatement(HOTFIX_SEL_SPELL_REAGENTS, "SELECT ID, Reagent1, Reagent2, Reagent3, Reagent4, Reagent5, Reagent6, Reagent7, Reagent8, " "ReagentCount1, ReagentCount2, ReagentCount3, ReagentCount4, ReagentCount5, ReagentCount6, ReagentCount7, ReagentCount8, " diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.h b/src/server/shared/Database/Implementation/HotfixDatabase.h index b5130ff6f20..70472537510 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.h +++ b/src/server/shared/Database/Implementation/HotfixDatabase.h @@ -102,6 +102,8 @@ enum HotfixDatabaseStatements HOTFIX_SEL_SPELL_POWER, + HOTFIX_SEL_SPELL_POWER_DIFFICULTY, + HOTFIX_SEL_SPELL_REAGENTS, HOTFIX_SEL_SPELL_RUNE_COST, |