aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/hotfixes/2015_03_08_00_hotfixes.sql24
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp15
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp26
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp63
-rw-r--r--src/server/game/DataStores/DB2Stores.h6
-rw-r--r--src/server/game/DataStores/DB2Structure.h9
-rw-r--r--src/server/game/DataStores/DB2fmt.h1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp15
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp39
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp32
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp44
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h1
-rw-r--r--src/server/game/Spells/Spell.cpp267
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellEffects.cpp15
-rw-r--r--src/server/game/Spells/SpellInfo.cpp270
-rw-r--r--src/server/game/Spells/SpellInfo.h16
-rw-r--r--src/server/game/Spells/SpellMgr.cpp4
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp18
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp12
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp13
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp12
-rw-r--r--src/server/scripts/World/guards.cpp10
-rw-r--r--src/server/scripts/World/mob_generic_creature.cpp10
-rw-r--r--src/server/shared/Cryptography/ARC4.cpp4
-rw-r--r--src/server/shared/Cryptography/ARC4.h4
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.cpp4
-rw-r--r--src/server/shared/Database/Implementation/HotfixDatabase.h2
30 files changed, 531 insertions, 415 deletions
diff --git a/sql/updates/hotfixes/2015_03_08_00_hotfixes.sql b/sql/updates/hotfixes/2015_03_08_00_hotfixes.sql
new file mode 100644
index 00000000000..9f2f8516eb8
--- /dev/null
+++ b/sql/updates/hotfixes/2015_03_08_00_hotfixes.sql
@@ -0,0 +1,24 @@
+--
+-- Table structure for table `spell_power_difficulty`
+--
+
+DROP TABLE IF EXISTS `spell_power_difficulty`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `spell_power_difficulty` (
+ `SpellPowerID` int(10) unsigned NOT NULL DEFAULT '0',
+ `DifficultyID` int(10) unsigned NOT NULL DEFAULT '0',
+ `PowerIndex` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`SpellPowerID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `spell_power_difficulty`
+--
+
+LOCK TABLES `spell_power_difficulty` WRITE;
+/*!40000 ALTER TABLE `spell_power_difficulty` DISABLE KEYS */;
+/*!40000 ALTER TABLE `spell_power_difficulty` ENABLE KEYS */;
+UNLOCK TABLES;
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,