diff options
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 107 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 3 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 32 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 14 | ||||
-rw-r--r-- | src/server/game/DataStores/GameTables.h | 4 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 227 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.h | 4 |
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; |