aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp107
-rw-r--r--src/server/game/DataStores/DB2Stores.h3
-rw-r--r--src/server/game/DataStores/DB2Structure.h32
-rw-r--r--src/server/game/DataStores/DBCEnums.h14
-rw-r--r--src/server/game/DataStores/GameTables.h4
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp227
-rw-r--r--src/server/game/Spells/SpellInfo.h4
-rw-r--r--src/server/game/Spells/SpellMgr.cpp8
-rw-r--r--src/server/game/Spells/SpellMgr.h4
10 files changed, 301 insertions, 104 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 82fc12559c8..64ca72a6381 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -27,6 +27,7 @@
#include "Timer.h"
#include "Util.h"
#include <array>
+#include <numeric>
#include <sstream>
#include <cctype>
@@ -95,6 +96,8 @@ DB2Storage<DurabilityQualityEntry> sDurabilityQualityStore("Durabil
DB2Storage<EmotesEntry> sEmotesStore("Emotes.db2", EmotesLoadInfo::Instance());
DB2Storage<EmotesTextEntry> sEmotesTextStore("EmotesText.db2", EmotesTextLoadInfo::Instance());
DB2Storage<EmotesTextSoundEntry> sEmotesTextSoundStore("EmotesTextSound.db2", EmotesTextSoundLoadInfo::Instance());
+DB2Storage<ExpectedStatEntry> sExpectedStatStore("ExpectedStat.db2", ExpectedStatLoadInfo::Instance());
+DB2Storage<ExpectedStatModEntry> sExpectedStatModStore("ExpectedStatMod.db2", ExpectedStatModLoadInfo::Instance());
DB2Storage<FactionEntry> sFactionStore("Faction.db2", FactionLoadInfo::Instance());
DB2Storage<FactionTemplateEntry> sFactionTemplateStore("FactionTemplate.db2", FactionTemplateLoadInfo::Instance());
DB2Storage<GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore("GameObjectDisplayInfo.db2", GameobjectDisplayInfoLoadInfo::Instance());
@@ -214,7 +217,6 @@ DB2Storage<SkillLineAbilityEntry> sSkillLineAbilityStore("SkillLin
DB2Storage<SkillRaceClassInfoEntry> sSkillRaceClassInfoStore("SkillRaceClassInfo.db2", SkillRaceClassInfoLoadInfo::Instance());
DB2Storage<SoundKitEntry> sSoundKitStore("SoundKit.db2", SoundKitLoadInfo::Instance());
DB2Storage<SpecializationSpellsEntry> sSpecializationSpellsStore("SpecializationSpells.db2", SpecializationSpellsLoadInfo::Instance());
-DB2Storage<SpellEntry> sSpellStore("Spell.db2", SpellLoadInfo::Instance());
DB2Storage<SpellAuraOptionsEntry> sSpellAuraOptionsStore("SpellAuraOptions.db2", SpellAuraOptionsLoadInfo::Instance());
DB2Storage<SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore("SpellAuraRestrictions.db2", SpellAuraRestrictionsLoadInfo::Instance());
DB2Storage<SpellCastTimesEntry> sSpellCastTimesStore("SpellCastTimes.db2", SpellCastTimesLoadInfo::Instance());
@@ -233,6 +235,7 @@ DB2Storage<SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionSt
DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore("SpellLearnSpell.db2", SpellLearnSpellLoadInfo::Instance());
DB2Storage<SpellLevelsEntry> sSpellLevelsStore("SpellLevels.db2", SpellLevelsLoadInfo::Instance());
DB2Storage<SpellMiscEntry> sSpellMiscStore("SpellMisc.db2", SpellMiscLoadInfo::Instance());
+DB2Storage<SpellNameEntry> sSpellNameStore("SpellName.db2", SpellNameLoadInfo::Instance());
DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerLoadInfo::Instance());
DB2Storage<SpellPowerDifficultyEntry> sSpellPowerDifficultyStore("SpellPowerDifficulty.db2", SpellPowerDifficultyLoadInfo::Instance());
DB2Storage<SpellProcsPerMinuteEntry> sSpellProcsPerMinuteStore("SpellProcsPerMinute.db2", SpellProcsPerMinuteLoadInfo::Instance());
@@ -348,6 +351,7 @@ namespace
ChrSpecialzationByClassContainer _defaultChrSpecializationsByClass;
CurvePointsContainer _curvePoints;
EmotesTextSoundContainer _emoteTextSounds;
+ std::unordered_map<std::pair<uint32 /*level*/, int32 /*expansion*/>, ExpectedStatEntry const*> _expectedStatsByLevel;
FactionTeamContainer _factionTeams;
HeirloomItemsContainer _heirlooms;
GlyphBindableSpellsContainer _glyphBindableSpells;
@@ -533,6 +537,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sEmotesStore);
LOAD_DB2(sEmotesTextStore);
LOAD_DB2(sEmotesTextSoundStore);
+ LOAD_DB2(sExpectedStatStore);
+ LOAD_DB2(sExpectedStatModStore);
LOAD_DB2(sFactionStore);
LOAD_DB2(sFactionTemplateStore);
LOAD_DB2(sGameObjectsStore);
@@ -652,7 +658,6 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sSkillRaceClassInfoStore);
LOAD_DB2(sSoundKitStore);
LOAD_DB2(sSpecializationSpellsStore);
- LOAD_DB2(sSpellStore);
LOAD_DB2(sSpellAuraOptionsStore);
LOAD_DB2(sSpellAuraRestrictionsStore);
LOAD_DB2(sSpellCastTimesStore);
@@ -671,6 +676,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sSpellLearnSpellStore);
LOAD_DB2(sSpellLevelsStore);
LOAD_DB2(sSpellMiscStore);
+ LOAD_DB2(sSpellNameStore);
LOAD_DB2(sSpellPowerStore);
LOAD_DB2(sSpellPowerDifficultyStore);
LOAD_DB2(sSpellProcsPerMinuteStore);
@@ -814,6 +820,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (EmotesTextSoundEntry const* emoteTextSound : sEmotesTextSoundStore)
_emoteTextSounds[EmotesTextSoundContainer::key_type(emoteTextSound->EmotesTextID, emoteTextSound->RaceID, emoteTextSound->SexID, emoteTextSound->ClassID)] = emoteTextSound;
+ for (ExpectedStatEntry const* expectedStat : sExpectedStatStore)
+ _expectedStatsByLevel[std::make_pair(expectedStat->Lvl, expectedStat->ExpansionID)] = expectedStat;
+
for (FactionEntry const* faction : sFactionStore)
if (faction->ParentFactionID)
_factionTeams[faction->ParentFactionID].push_back(faction->ID);
@@ -1149,7 +1158,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
!sItemStore.LookupEntry(157831) || // last item added in 7.3.5 (25996)
!sItemExtendedCostStore.LookupEntry(6300) || // last item extended cost added in 7.3.5 (25996)
!sMapStore.LookupEntry(1903) || // last map added in 7.3.5 (25996)
- !sSpellStore.LookupEntry(263166)) // last spell added in 7.3.5 (25996)
+ !sSpellNameStore.LookupEntry(263166)) // last spell added in 7.3.5 (25996)
{
TC_LOG_ERROR("misc", "You have _outdated_ DB2 files. Please extract correct versions from current using client.");
exit(1);
@@ -1543,6 +1552,98 @@ EmotesTextSoundEntry const* DB2Manager::GetTextSoundEmoteFor(uint32 emote, uint8
return nullptr;
}
+template<float(ExpectedStatModEntry::*field)>
+struct ExpectedStatModReducer
+{
+ float operator()(float mod, ExpectedStatModEntry const* expectedStatMod)
+ {
+ return mod * (expectedStatMod ? expectedStatMod->*field : 1.0f);
+ }
+};
+
+float DB2Manager::EvaluateExpectedStat(ExpectedStatType stat, uint32 level, int32 expansion, uint32 contentTuningId, Classes unitClass) const
+{
+ auto expectedStatItr = _expectedStatsByLevel.find(std::make_pair(level, expansion));
+ if (expectedStatItr == _expectedStatsByLevel.end())
+ expectedStatItr = _expectedStatsByLevel.find(std::make_pair(level, -2));
+
+ if (expectedStatItr == _expectedStatsByLevel.end())
+ return 1.0f;
+
+ std::array<ExpectedStatModEntry const*, 3> mods;
+ mods.fill(nullptr);
+ if (ContentTuningEntry const* contentTuning = sContentTuningStore.LookupEntry(contentTuningId))
+ {
+ mods[0] = sExpectedStatModStore.LookupEntry(contentTuning->ExpectedStatModID);
+ mods[1] = sExpectedStatModStore.LookupEntry(contentTuning->ExpectedStatModID2);
+ }
+
+ switch (unitClass)
+ {
+ case CLASS_WARRIOR:
+ mods[2] = sExpectedStatModStore.LookupEntry(4);
+ break;
+ case CLASS_PALADIN:
+ mods[2] = sExpectedStatModStore.LookupEntry(2);
+ break;
+ case CLASS_ROGUE:
+ mods[2] = sExpectedStatModStore.LookupEntry(3);
+ break;
+ case CLASS_MAGE:
+ mods[2] = sExpectedStatModStore.LookupEntry(1);
+ break;
+ default:
+ break;
+ }
+
+ float value = 0.0f;
+ switch (stat)
+ {
+ case ExpectedStatType::CreatureHealth:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->CreatureHealth,
+ ExpectedStatModReducer<&ExpectedStatModEntry::CreatureHealthMod>());
+ break;
+ case ExpectedStatType::PlayerHealth:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->PlayerHealth,
+ ExpectedStatModReducer<&ExpectedStatModEntry::PlayerHealthMod>());
+ break;
+ case ExpectedStatType::CreatureAutoAttackDps:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->CreatureAutoAttackDps,
+ ExpectedStatModReducer<&ExpectedStatModEntry::CreatureAutoAttackDPSMod>());
+ break;
+ case ExpectedStatType::CreatureArmor:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->CreatureArmor,
+ ExpectedStatModReducer<&ExpectedStatModEntry::CreatureArmorMod>());
+ break;
+ case ExpectedStatType::PlayerMana:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->PlayerMana,
+ ExpectedStatModReducer<&ExpectedStatModEntry::PlayerManaMod>());
+ break;
+ case ExpectedStatType::PlayerPrimaryStat:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->PlayerPrimaryStat,
+ ExpectedStatModReducer<&ExpectedStatModEntry::PlayerPrimaryStatMod>());
+ break;
+ case ExpectedStatType::PlayerSecondaryStat:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->PlayerSecondaryStat,
+ ExpectedStatModReducer<&ExpectedStatModEntry::PlayerSecondaryStatMod>());
+ break;
+ case ExpectedStatType::ArmorConstant:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->ArmorConstant,
+ ExpectedStatModReducer<&ExpectedStatModEntry::ArmorConstantMod>());
+ break;
+ case ExpectedStatType::None:
+ break;
+ case ExpectedStatType::CreatureSpellDamage:
+ value = std::accumulate(mods.begin(), mods.end(), expectedStatItr->second->CreatureSpellDamage,
+ ExpectedStatModReducer<&ExpectedStatModEntry::CreatureSpellDamageMod>());
+ break;
+ default:
+ break;
+ }
+
+ return value;
+}
+
std::vector<uint32> const* DB2Manager::GetFactionTeamList(uint32 faction) const
{
auto itr = _factionTeams.find(faction);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 50853a52947..68a10fbd4d3 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -164,7 +164,6 @@ TC_GAME_API extern DB2Storage<SceneScriptPackageEntry> sSceneScript
TC_GAME_API extern DB2Storage<SkillLineAbilityEntry> sSkillLineAbilityStore;
TC_GAME_API extern DB2Storage<SkillRaceClassInfoEntry> sSkillRaceClassInfoStore;
TC_GAME_API extern DB2Storage<SoundKitEntry> sSoundKitStore;
-TC_GAME_API extern DB2Storage<SpellEntry> sSpellStore;
TC_GAME_API extern DB2Storage<SpellAuraOptionsEntry> sSpellAuraOptionsStore;
TC_GAME_API extern DB2Storage<SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore;
TC_GAME_API extern DB2Storage<SpellCastTimesEntry> sSpellCastTimesStore;
@@ -183,6 +182,7 @@ TC_GAME_API extern DB2Storage<SpellItemEnchantmentConditionEntry> sSpellItemEn
TC_GAME_API extern DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore;
TC_GAME_API extern DB2Storage<SpellLevelsEntry> sSpellLevelsStore;
TC_GAME_API extern DB2Storage<SpellMiscEntry> sSpellMiscStore;
+TC_GAME_API extern DB2Storage<SpellNameEntry> sSpellNameStore;
TC_GAME_API extern DB2Storage<SpellPowerEntry> sSpellPowerStore;
TC_GAME_API extern DB2Storage<SpellProcsPerMinuteEntry> sSpellProcsPerMinuteStore;
TC_GAME_API extern DB2Storage<SpellRadiusEntry> sSpellRadiusStore;
@@ -277,6 +277,7 @@ public:
static char const* GetCreatureFamilyPetName(uint32 petfamily, uint32 locale);
float GetCurveValueAt(uint32 curveId, float x) const;
EmotesTextSoundEntry const* GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const;
+ float EvaluateExpectedStat(ExpectedStatType stat, uint32 level, int32 expansion, uint32 contentTuningId, Classes unitClass) const;
std::vector<uint32> const* GetFactionTeamList(uint32 faction) const;
HeirloomEntry const* GetHeirloomByItemId(uint32 itemId) const;
std::vector<uint32> const* GetGlyphBindableSpells(uint32 glyphPropertiesId) const;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index f8649bdf40a..574087b8900 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -550,7 +550,7 @@ struct ContentTuningEntry
int32 MaxLevel;
int32 Flags;
int32 ExpectedStatModID;
- int32 Unknown;
+ int32 ExpectedStatModID2;
};
struct ConversationLineEntry
@@ -955,6 +955,36 @@ struct EmotesTextSoundEntry
uint16 EmotesTextID;
};
+struct ExpectedStatEntry
+{
+ uint32 ID;
+ int32 ExpansionID;
+ float CreatureHealth;
+ float PlayerHealth;
+ float CreatureAutoAttackDps;
+ float CreatureArmor;
+ float PlayerMana;
+ float PlayerPrimaryStat;
+ float PlayerSecondaryStat;
+ float ArmorConstant;
+ float CreatureSpellDamage;
+ int32 Lvl;
+};
+
+struct ExpectedStatModEntry
+{
+ uint32 ID;
+ float CreatureHealthMod;
+ float PlayerHealthMod;
+ float CreatureAutoAttackDPSMod;
+ float CreatureArmorMod;
+ float PlayerManaMod;
+ float PlayerPrimaryStatMod;
+ float PlayerSecondaryStatMod;
+ float ArmorConstantMod;
+ float CreatureSpellDamageMod;
+};
+
struct FactionEntry
{
int64 ReputationRaceMask[4];
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 730f11a9908..fe7913f26b0 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -643,6 +643,20 @@ enum SpawnMask
SPAWNMASK_RAID_ALL = (SPAWNMASK_RAID_NORMAL_ALL | SPAWNMASK_RAID_HEROIC_ALL)
};
+enum class ExpectedStatType : uint8
+{
+ CreatureHealth = 0,
+ PlayerHealth = 1,
+ CreatureAutoAttackDps = 2,
+ CreatureArmor = 3,
+ PlayerMana = 4,
+ PlayerPrimaryStat = 5,
+ PlayerSecondaryStat = 6,
+ ArmorConstant = 7,
+ None = 8,
+ CreatureSpellDamage = 9
+};
+
enum FactionTemplateFlags
{
FACTION_TEMPLATE_ENEMY_SPAR = 0x00000020, // guessed, sparring with enemies?
diff --git a/src/server/game/DataStores/GameTables.h b/src/server/game/DataStores/GameTables.h
index d265f2657a9..6e79de31e62 100644
--- a/src/server/game/DataStores/GameTables.h
+++ b/src/server/game/DataStores/GameTables.h
@@ -176,6 +176,7 @@ struct GtSpellScalingEntry
float Gem2 = 0.0f;
float Gem3 = 0.0f;
float Health = 0.0f;
+ float DamageReplaceStat = 0.0f;
};
struct GtXpEntry
@@ -290,6 +291,7 @@ inline float GetSpellScalingColumnForClass(GtSpellScalingEntry const* row, int32
case CLASS_DEMON_HUNTER:
return row->DemonHunter;
case -1:
+ case -7:
return row->Item;
case -2:
return row->Consumable;
@@ -301,6 +303,8 @@ inline float GetSpellScalingColumnForClass(GtSpellScalingEntry const* row, int32
return row->Gem3;
case -6:
return row->Health;
+ case -8:
+ return row->DamageReplaceStat;
default:
break;
}
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index c842126b31d..5d61501903b 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -1276,7 +1276,7 @@ enum SpellEffectName
SPELL_EFFECT_199 = 199,
SPELL_EFFECT_HEAL_BATTLEPET_PCT = 200, // NYI
SPELL_EFFECT_ENABLE_BATTLE_PETS = 201, // NYI
- SPELL_EFFECT_202 = 202,
+ SPELL_EFFECT_202 = 202, // some sort of apply aura effect
SPELL_EFFECT_203 = 203,
SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY = 204,
SPELL_EFFECT_LAUNCH_QUEST_CHOICE = 205,
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index d1dfa32f7cb..4a8695a60f5 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -368,6 +368,7 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_
{TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 147
{TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 148
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 149
+ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 150
};
SpellEffectInfo::SpellEffectInfo(SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* _effect)
@@ -377,7 +378,6 @@ SpellEffectInfo::SpellEffectInfo(SpellInfo const* spellInfo, uint8 effIndex, Spe
Effect = _effect ? _effect->Effect : 0;
ApplyAuraName = _effect ? _effect->EffectAura : 0;
ApplyAuraPeriod = _effect ? _effect->EffectAuraPeriod : 0;
- DieSides = _effect ? _effect->EffectDieSides : 0;
RealPointsPerLevel = _effect ? _effect->EffectRealPointsPerLevel : 0.0f;
BasePoints = _effect ? _effect->EffectBasePoints : 0;
PointsPerResource = _effect ? _effect->EffectPointsPerResource : 0.0f;
@@ -488,21 +488,32 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const*
if (!_spellInfo->Scaling.Class)
return 0;
- if (!_spellInfo->Scaling.ScalesFromItemLevel)
+ uint32 effectiveItemLevel = itemLevel != -1 ? uint32(itemLevel) : 1u;
+ if (_spellInfo->Scaling.ScalesFromItemLevel || _spellInfo->HasAttribute(SPELL_ATTR11_SCALES_WITH_ITEM_LEVEL))
{
- if (!_spellInfo->HasAttribute(SPELL_ATTR11_SCALES_WITH_ITEM_LEVEL))
- value = GetSpellScalingColumnForClass(sSpellScalingGameTable.GetRow(level), _spellInfo->Scaling.Class);
- else
+ if (_spellInfo->Scaling.ScalesFromItemLevel)
+ effectiveItemLevel = _spellInfo->Scaling.ScalesFromItemLevel;
+
+ if (_spellInfo->Scaling.Class == -8)
{
- uint32 effectiveItemLevel = itemLevel != -1 ? uint32(itemLevel) : 1u;
- value = GetRandomPropertyPoints(effectiveItemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0);
- if (IsAura() && ApplyAuraName == SPELL_AURA_MOD_RATING)
- if (GtCombatRatingsMultByILvl const* ratingMult = sCombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel))
- value *= ratingMult->ArmorMultiplier;
+ RandPropPointsEntry const* randPropPoints = sRandPropPointsStore.LookupEntry(effectiveItemLevel);
+ if (!randPropPoints)
+ randPropPoints = sRandPropPointsStore.AssertEntry(sRandPropPointsStore.GetNumRows() - 1);
+
+ value = randPropPoints->DamageReplaceStat;
}
+ else
+ value = GetRandomPropertyPoints(effectiveItemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0);
}
else
- value = GetRandomPropertyPoints(_spellInfo->Scaling.ScalesFromItemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0);
+ value = GetSpellScalingColumnForClass(sSpellScalingGameTable.GetRow(level), _spellInfo->Scaling.Class);
+
+ if (_spellInfo->Scaling.Class == -7)
+ {
+ // todo: get inventorytype here
+ if (GtCombatRatingsMultByILvl const* ratingMult = sCombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel))
+ value *= ratingMult->ArmorMultiplier;
+ }
}
value *= Scaling.Coefficient;
@@ -526,33 +537,36 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const*
}
else
{
- if (caster)
+ int32 level = caster ? int32(caster->getLevel()) : 0;
+ float value = basePoints;
+ ExpectedStatType stat = GetScalingExpectedStat();
+ if (stat != ExpectedStatType::None)
{
- int32 level = int32(caster->getLevel());
- if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
- level = int32(_spellInfo->MaxLevel);
- else if (level < int32(_spellInfo->BaseLevel))
- level = int32(_spellInfo->BaseLevel);
- level -= int32(_spellInfo->SpellLevel);
- basePoints += int32(level * basePointsPerLevel);
+ if (_spellInfo->HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION))
+ stat = ExpectedStatType::CreatureAutoAttackDps;
+
+ // TODO - add expansion and content tuning id args?
+ value = sDB2Manager.EvaluateExpectedStat(stat, level, -2, 0, CLASS_NONE) * value / 100.0f;
}
- // roll in a range <1;EffectDieSides> as of patch 3.3.3
- int32 randomPoints = int32(DieSides);
- switch (randomPoints)
+ if (Scaling.Variance)
{
- case 0: break;
- case 1: basePoints += 1; break; // range 1..1
- default:
- {
- // range can have positive (1..rand) and negative (rand..1) values, so order its for irand
- int32 randvalue = (randomPoints >= 1)
- ? irand(1, randomPoints)
- : irand(randomPoints, 1);
+ float delta = fabs(Scaling.Variance * 0.5f);
+ float valueVariance = frand(-delta, delta);
+ value += value * valueVariance;
- basePoints += randvalue;
- break;
- }
+ if (variance)
+ *variance = valueVariance;
+ }
+
+ if (stat == ExpectedStatType::None)
+ {
+ if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
+ level = int32(_spellInfo->MaxLevel);
+ level -= int32(_spellInfo->BaseLevel);
+ if (level < 0)
+ level = 0;
+ value += level * basePointsPerLevel;
}
}
@@ -567,58 +581,6 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const*
value += comboDamage * comboPoints;
value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value);
-
- // amount multiplication based on caster's level
- if (!caster->IsControlledByPlayer() &&
- _spellInfo->SpellLevel && _spellInfo->SpellLevel != caster->getLevel() &&
- !basePointsPerLevel && (_spellInfo->HasAttribute(SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)))
- {
- bool canEffectScale = false;
- switch (Effect)
- {
- case SPELL_EFFECT_SCHOOL_DAMAGE:
- case SPELL_EFFECT_DUMMY:
- case SPELL_EFFECT_POWER_DRAIN:
- case SPELL_EFFECT_HEALTH_LEECH:
- case SPELL_EFFECT_HEAL:
- case SPELL_EFFECT_WEAPON_DAMAGE:
- case SPELL_EFFECT_POWER_BURN:
- case SPELL_EFFECT_SCRIPT_EFFECT:
- case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
- case SPELL_EFFECT_FORCE_CAST_WITH_VALUE:
- case SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE:
- case SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE:
- canEffectScale = true;
- break;
- default:
- break;
- }
-
- switch (ApplyAuraName)
- {
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_DUMMY:
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_DAMAGE_SHIELD:
- case SPELL_AURA_PROC_TRIGGER_DAMAGE:
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_PERIODIC_MANA_LEECH:
- case SPELL_AURA_SCHOOL_ABSORB:
- case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
- canEffectScale = true;
- break;
- default:
- break;
- }
-
- if (canEffectScale)
- {
- GtNpcManaCostScalerEntry const* spellScaler = sNpcManaCostScalerGameTable.GetRow(_spellInfo->SpellLevel);
- GtNpcManaCostScalerEntry const* casterScaler = sNpcManaCostScalerGameTable.GetRow(caster->getLevel());
- if (spellScaler && casterScaler)
- value *= casterScaler->Scaler / spellScaler->Scaler;
- }
- }
}
return int32(value);
@@ -626,10 +588,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster /*= nullptr*/, int32 const*
int32 SpellEffectInfo::CalcBaseValue(int32 value) const
{
- if (DieSides == 0)
- return value;
- else
- return value - 1;
+ return value;
}
float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
@@ -723,6 +682,94 @@ SpellTargetObjectTypes SpellEffectInfo::GetUsedTargetObjectType() const
return _data[Effect].UsedTargetObjectType;
}
+ExpectedStatType SpellEffectInfo::GetScalingExpectedStat() const
+{
+ switch (Effect)
+ {
+ case SPELL_EFFECT_SCHOOL_DAMAGE:
+ case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE:
+ case SPELL_EFFECT_HEALTH_LEECH:
+ case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
+ case SPELL_EFFECT_WEAPON_DAMAGE:
+ return ExpectedStatType::CreatureSpellDamage;
+ case SPELL_EFFECT_HEAL:
+ case SPELL_EFFECT_HEAL_MECHANICAL:
+ return ExpectedStatType::PlayerHealth;
+ case SPELL_EFFECT_ENERGIZE:
+ case SPELL_EFFECT_POWER_BURN:
+ if (!MiscValue)
+ return ExpectedStatType::PlayerMana;
+ return ExpectedStatType::None;
+ case SPELL_EFFECT_POWER_DRAIN:
+ return ExpectedStatType::PlayerMana;
+ case SPELL_EFFECT_APPLY_AURA:
+ case SPELL_EFFECT_PERSISTENT_AREA_AURA:
+ case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
+ case SPELL_EFFECT_APPLY_AREA_AURA_PET:
+ case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
+ case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
+ case SPELL_EFFECT_APPLY_AURA_ON_PET:
+ case SPELL_EFFECT_202:
+ switch (ApplyAuraName)
+ {
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_MOD_DAMAGE_DONE:
+ case SPELL_AURA_DAMAGE_SHIELD:
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_MOD_DAMAGE_DONE_CREATURE:
+ case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
+ case SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS:
+ case SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS:
+ case SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS:
+ return ExpectedStatType::CreatureSpellDamage;
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_MOD_DAMAGE_TAKEN:
+ case SPELL_AURA_MOD_INCREASE_HEALTH:
+ case SPELL_AURA_SCHOOL_ABSORB:
+ case SPELL_AURA_MOD_REGEN:
+ case SPELL_AURA_MANA_SHIELD:
+ case SPELL_AURA_MOD_HEALING:
+ case SPELL_AURA_MOD_HEALING_DONE:
+ case SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT:
+ case SPELL_AURA_MOD_MAX_HEALTH:
+ case SPELL_AURA_MOD_INCREASE_HEALTH_2:
+ case SPELL_AURA_SCHOOL_HEAL_ABSORB:
+ return ExpectedStatType::PlayerHealth;
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ return ExpectedStatType::PlayerMana;
+ case SPELL_AURA_MOD_STAT:
+ case SPELL_AURA_MOD_ATTACK_POWER:
+ case SPELL_AURA_MOD_RANGED_ATTACK_POWER:
+ return ExpectedStatType::PlayerPrimaryStat;
+ case SPELL_AURA_MOD_RATING:
+ return ExpectedStatType::PlayerSecondaryStat;
+ case SPELL_AURA_MOD_RESISTANCE:
+ case SPELL_AURA_MOD_BASE_RESISTANCE:
+ case SPELL_AURA_MOD_TARGET_RESISTANCE:
+ case SPELL_AURA_MOD_BONUS_ARMOR:
+ return ExpectedStatType::ArmorConstant;
+ case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_MOD_INCREASE_ENERGY:
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL:
+ case SPELL_AURA_MOD_POWER_REGEN:
+ case SPELL_AURA_POWER_BURN:
+ case SPELL_AURA_MOD_MAX_POWER:
+ if (!MiscValue)
+ return ExpectedStatType::PlayerMana;
+ return ExpectedStatType::None;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ExpectedStatType::None;
+}
+
SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{
// implicit target type used target object type
@@ -1042,7 +1089,7 @@ SpellInfo::SpellInfo(SpellInfoLoadHelper const& data, SpellEffectEntryMap const&
// SpellAuraOptionsEntry
SpellAuraOptionsEntry const* _options = data.AuraOptions;
SpellProcsPerMinuteEntry const* _ppm = _options ? sSpellProcsPerMinuteStore.LookupEntry(_options->SpellProcsPerMinuteID) : nullptr;
- ProcFlags = _options ? _options->ProcTypeMask : 0;
+ ProcFlags = _options ? _options->ProcTypeMask[0] : 0;
ProcChance = _options ? _options->ProcChance : 0;
ProcCharges = _options ? _options->ProcCharges : 0;
ProcCooldown = _options ? _options->ProcCategoryRecovery : 0;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index dcbcaeed397..d1f8c40bb4b 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -323,7 +323,6 @@ public:
uint32 Effect;
uint32 ApplyAuraName;
uint32 ApplyAuraPeriod;
- int32 DieSides;
float RealPointsPerLevel;
int32 BasePoints;
float PointsPerResource;
@@ -352,7 +351,7 @@ public:
float ResourceCoefficient;
} Scaling;
- SpellEffectInfo() : _spellInfo(NULL), EffectIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0), DieSides(0),
+ SpellEffectInfo() : _spellInfo(NULL), EffectIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0),
RealPointsPerLevel(0), BasePoints(0), PointsPerResource(0), Amplitude(0), ChainAmplitude(0),
BonusCoefficient(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), PositionFacing(0),
RadiusEntry(NULL), ChainTargets(0), ItemType(0), TriggerSpell(0), BonusCoefficientFromAP(0.0f), ImplicitTargetConditions(NULL) { }
@@ -382,6 +381,7 @@ public:
SpellEffectImplicitTargetTypes GetImplicitTargetType() const;
SpellTargetObjectTypes GetUsedTargetObjectType() const;
+ ExpectedStatType GetScalingExpectedStat() const;
ImmunityInfo const* GetImmunityInfo() const { return &_immunityInfo; }
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index bebd534b34b..ca9bcfaf50d 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2209,7 +2209,7 @@ void SpellMgr::LoadSpellInfoStore()
uint32 oldMSTime = getMSTime();
UnloadSpellInfoStore();
- mSpellInfoMap.resize(sSpellStore.GetNumRows(), NULL);
+ mSpellInfoMap.resize(sSpellNameStore.GetNumRows(), NULL);
std::unordered_map<uint32, SpellInfoLoadHelper> loadData;
std::unordered_map<int32, SpellEffectEntryMap> effectsBySpell;
@@ -2286,11 +2286,11 @@ void SpellMgr::LoadSpellInfoStore()
for (SpellXSpellVisualEntry const* visual : sSpellXSpellVisualStore)
visualsBySpell[visual->SpellID][visual->DifficultyID].push_back(visual);
- for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
+ for (uint32 i = 0; i < sSpellNameStore.GetNumRows(); ++i)
{
- if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i))
+ if (SpellNameEntry const* spellNameEntry = sSpellNameStore.LookupEntry(i))
{
- loadData[i].Entry = spellEntry;
+ loadData[i].Entry = spellNameEntry;
mSpellInfoMap[i] = new SpellInfo(loadData[i], effectsBySpell[i], std::move(visualsBySpell[i]));
}
}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 1034f6b4333..eeb0399f357 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -37,7 +37,6 @@ class Player;
class Unit;
class ProcEventInfo;
struct SkillLineAbilityEntry;
-struct SpellEntry;
struct SpellAuraOptionsEntry;
struct SpellAuraRestrictionsEntry;
struct SpellCastingRequirementsEntry;
@@ -48,6 +47,7 @@ struct SpellEquippedItemsEntry;
struct SpellInterruptsEntry;
struct SpellLevelsEntry;
struct SpellMiscEntry;
+struct SpellNameEntry;
struct SpellReagentsEntry;
struct SpellScalingEntry;
struct SpellShapeshiftEntry;
@@ -575,7 +575,7 @@ TC_GAME_API extern PetFamilySpellsStore sPetFamilySpells
struct SpellInfoLoadHelper
{
- SpellEntry const* Entry = nullptr;
+ SpellNameEntry const* Entry = nullptr;
SpellAuraOptionsEntry const* AuraOptions = nullptr;
SpellAuraRestrictionsEntry const* AuraRestrictions = nullptr;