aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/master/2020_05_02_01_world.sql7
-rw-r--r--src/server/game/DataStores/GameTables.cpp20
-rw-r--r--src/server/game/DataStores/GameTables.h40
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp67
-rw-r--r--src/server/game/Entities/Creature/CreatureData.h41
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp9
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp49
-rw-r--r--src/server/game/Server/Packets/CombatLogPacketsCommon.cpp21
-rw-r--r--src/tools/map_extractor/System.cpp17
10 files changed, 103 insertions, 172 deletions
diff --git a/sql/updates/world/master/2020_05_02_01_world.sql b/sql/updates/world/master/2020_05_02_01_world.sql
new file mode 100644
index 00000000000..ba0f927c713
--- /dev/null
+++ b/sql/updates/world/master/2020_05_02_01_world.sql
@@ -0,0 +1,7 @@
+ALTER TABLE `creature_template_scaling`
+ ADD COLUMN `DifficultyID` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `Entry`,
+ ADD COLUMN `ContentTuningID` INT(10) NOT NULL DEFAULT '0' AFTER `LevelScalingDeltaMax`,
+ DROP PRIMARY KEY,
+ ADD PRIMARY KEY (`Entry`, `DifficultyID`);
+
+ALTER TABLE `creature_classlevelstats` DROP `basearmor`;
diff --git a/src/server/game/DataStores/GameTables.cpp b/src/server/game/DataStores/GameTables.cpp
index 8340bef7ca0..a8f83354675 100644
--- a/src/server/game/DataStores/GameTables.cpp
+++ b/src/server/game/DataStores/GameTables.cpp
@@ -24,7 +24,6 @@
#include <fstream>
#include <sstream>
-GameTable<GtArmorMitigationByLvlEntry> sArmorMitigationByLvlGameTable;
GameTable<GtArtifactKnowledgeMultiplierEntry> sArtifactKnowledgeMultiplierGameTable;
GameTable<GtArtifactLevelXPEntry> sArtifactLevelXPGameTable;
GameTable<GtBarberShopCostBaseEntry> sBarberShopCostBaseGameTable;
@@ -33,9 +32,7 @@ GameTable<GtCombatRatingsEntry> sCombatRatingsGameTable;
GameTable<GtCombatRatingsMultByILvl> sCombatRatingsMultByILvlGameTable;
GameTable<GtHpPerStaEntry> sHpPerStaGameTable;
GameTable<GtItemSocketCostPerLevelEntry> sItemSocketCostPerLevelGameTable;
-GameTable<GtNpcDamageByClassEntry> sNpcDamageByClassGameTable[MAX_EXPANSIONS];
GameTable<GtNpcManaCostScalerEntry> sNpcManaCostScalerGameTable;
-GameTable<GtNpcTotalHpEntry> sNpcTotalHpGameTable[MAX_EXPANSIONS];
GameTable<GtSpellScalingEntry> sSpellScalingGameTable;
GameTable<GtStaminaMultByILvl> sStaminaMultByILvlGameTable;
GameTable<GtXpEntry> sXpGameTable;
@@ -112,7 +109,6 @@ void LoadGameTables(std::string const& dataPath)
#define LOAD_GT(store, file) gameTableCount += LoadGameTable(bad_gt_files, store, gtPath / file); ++expectedGameTableCount;
- LOAD_GT(sArmorMitigationByLvlGameTable, "ArmorMitigationByLvl.txt");
LOAD_GT(sArtifactKnowledgeMultiplierGameTable, "ArtifactKnowledgeMultiplier.txt");
LOAD_GT(sArtifactLevelXPGameTable, "ArtifactLevelXP.txt");
LOAD_GT(sBarberShopCostBaseGameTable, "BarberShopCostBase.txt");
@@ -121,23 +117,7 @@ void LoadGameTables(std::string const& dataPath)
LOAD_GT(sCombatRatingsMultByILvlGameTable, "CombatRatingsMultByILvl.txt");
LOAD_GT(sItemSocketCostPerLevelGameTable, "ItemSocketCostPerLevel.txt");
LOAD_GT(sHpPerStaGameTable, "HpPerSta.txt");
- LOAD_GT(sNpcDamageByClassGameTable[0], "NpcDamageByClass.txt");
- LOAD_GT(sNpcDamageByClassGameTable[1], "NpcDamageByClassExp1.txt");
- LOAD_GT(sNpcDamageByClassGameTable[2], "NpcDamageByClassExp2.txt");
- LOAD_GT(sNpcDamageByClassGameTable[3], "NpcDamageByClassExp3.txt");
- LOAD_GT(sNpcDamageByClassGameTable[4], "NpcDamageByClassExp4.txt");
- LOAD_GT(sNpcDamageByClassGameTable[5], "NpcDamageByClassExp5.txt");
- LOAD_GT(sNpcDamageByClassGameTable[6], "NpcDamageByClassExp6.txt");
- LOAD_GT(sNpcDamageByClassGameTable[7], "NpcDamageByClassExp7.txt");
LOAD_GT(sNpcManaCostScalerGameTable, "NPCManaCostScaler.txt");
- LOAD_GT(sNpcTotalHpGameTable[0], "NpcTotalHp.txt");
- LOAD_GT(sNpcTotalHpGameTable[1], "NpcTotalHpExp1.txt");
- LOAD_GT(sNpcTotalHpGameTable[2], "NpcTotalHpExp2.txt");
- LOAD_GT(sNpcTotalHpGameTable[3], "NpcTotalHpExp3.txt");
- LOAD_GT(sNpcTotalHpGameTable[4], "NpcTotalHpExp4.txt");
- LOAD_GT(sNpcTotalHpGameTable[5], "NpcTotalHpExp5.txt");
- LOAD_GT(sNpcTotalHpGameTable[6], "NpcTotalHpExp6.txt");
- LOAD_GT(sNpcTotalHpGameTable[7], "NpcTotalHpExp7.txt");
LOAD_GT(sSpellScalingGameTable, "SpellScaling.txt");
LOAD_GT(sStaminaMultByILvlGameTable, "StaminaMultByILvl.txt");
LOAD_GT(sXpGameTable, "xp.txt");
diff --git a/src/server/game/DataStores/GameTables.h b/src/server/game/DataStores/GameTables.h
index 14f108c1399..16f5f26dae2 100644
--- a/src/server/game/DataStores/GameTables.h
+++ b/src/server/game/DataStores/GameTables.h
@@ -24,11 +24,6 @@
enum InventoryType : uint8;
-struct GtArmorMitigationByLvlEntry
-{
- float Mitigation = 0.0f;
-};
-
struct GtArtifactKnowledgeMultiplierEntry
{
float Multiplier = 0.0f;
@@ -115,43 +110,11 @@ struct GtItemSocketCostPerLevelEntry
float SocketCost = 0.0f;
};
-struct GtNpcDamageByClassEntry
-{
- float Rogue = 0.0f;
- float Druid = 0.0f;
- float Hunter = 0.0f;
- float Mage = 0.0f;
- float Paladin = 0.0f;
- float Priest = 0.0f;
- float Shaman = 0.0f;
- float Warlock = 0.0f;
- float Warrior = 0.0f;
- float DeathKnight = 0.0f;
- float Monk = 0.0f;
- float DemonHunter = 0.0f;
-};
-
struct GtNpcManaCostScalerEntry
{
float Scaler = 0.0f;
};
-struct GtNpcTotalHpEntry
-{
- float Rogue = 0.0f;
- float Druid = 0.0f;
- float Hunter = 0.0f;
- float Mage = 0.0f;
- float Paladin = 0.0f;
- float Priest = 0.0f;
- float Shaman = 0.0f;
- float Warlock = 0.0f;
- float Warrior = 0.0f;
- float DeathKnight = 0.0f;
- float Monk = 0.0f;
- float DemonHunter = 0.0f;
-};
-
struct GtSpellScalingEntry
{
float Rogue = 0.0f;
@@ -213,7 +176,6 @@ private:
std::vector<T> _data;
};
-TC_GAME_API extern GameTable<GtArmorMitigationByLvlEntry> sArmorMitigationByLvlGameTable;
TC_GAME_API extern GameTable<GtArtifactKnowledgeMultiplierEntry> sArtifactKnowledgeMultiplierGameTable;
TC_GAME_API extern GameTable<GtArtifactLevelXPEntry> sArtifactLevelXPGameTable;
TC_GAME_API extern GameTable<GtBarberShopCostBaseEntry> sBarberShopCostBaseGameTable;
@@ -222,9 +184,7 @@ TC_GAME_API extern GameTable<GtCombatRatingsEntry> sCombatRatin
TC_GAME_API extern GameTable<GtCombatRatingsMultByILvl> sCombatRatingsMultByILvlGameTable;
TC_GAME_API extern GameTable<GtHpPerStaEntry> sHpPerStaGameTable;
TC_GAME_API extern GameTable<GtItemSocketCostPerLevelEntry> sItemSocketCostPerLevelGameTable;
-TC_GAME_API extern GameTable<GtNpcDamageByClassEntry> sNpcDamageByClassGameTable[MAX_EXPANSIONS];
TC_GAME_API extern GameTable<GtNpcManaCostScalerEntry> sNpcManaCostScalerGameTable;
-TC_GAME_API extern GameTable<GtNpcTotalHpEntry> sNpcTotalHpGameTable[MAX_EXPANSIONS];
TC_GAME_API extern GameTable<GtSpellScalingEntry> sSpellScalingGameTable;
TC_GAME_API extern GameTable<GtStaminaMultByILvl> sStaminaMultByILvlGameTable;
TC_GAME_API extern GameTable<GtXpEntry> sXpGameTable;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index f9f68237d0d..bafab099086 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -24,6 +24,7 @@
#include "CreatureAISelector.h"
#include "CreatureGroups.h"
#include "DatabaseEnv.h"
+#include "DB2Stores.h"
#include "Formulas.h"
#include "GameEventMgr.h"
#include "GameTime.h"
@@ -215,6 +216,27 @@ WorldPacket CreatureTemplate::BuildQueryData(LocaleConstant loc) const
return *queryTemp.Write();
}
+CreatureLevelScaling const* CreatureTemplate::GetLevelScaling(Difficulty difficulty) const
+{
+ auto it = scalingStore.find(difficulty);
+ if (it != scalingStore.end())
+ return &it->second;
+
+ struct DefaultCreatureLevelScaling : public CreatureLevelScaling
+ {
+ DefaultCreatureLevelScaling()
+ {
+ MinLevel = 0;
+ MaxLevel = 0;
+ DeltaLevelMin = 0;
+ DeltaLevelMax = 0;
+ ContentTuningID = 0;
+ }
+ };
+ static const DefaultCreatureLevelScaling defScaling;
+ return &defScaling;
+}
+
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
if (Unit* victim = ObjectAccessor::GetUnit(m_owner, m_victim))
@@ -1372,17 +1394,17 @@ void Creature::SelectLevel()
uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
SetLevel(level);
- if (HasScalableLevels())
- {
- SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelMin), cInfo->levelScaling->MinLevel);
- SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelMax), cInfo->levelScaling->MaxLevel);
+ CreatureLevelScaling const* scaling = cInfo->GetLevelScaling(GetMap()->GetDifficultyID());
- int8 mindelta = std::min(cInfo->levelScaling->DeltaLevelMax, cInfo->levelScaling->DeltaLevelMin);
- int8 maxdelta = std::max(cInfo->levelScaling->DeltaLevelMax, cInfo->levelScaling->DeltaLevelMin);
- int8 delta = mindelta == maxdelta ? mindelta : irand(mindelta, maxdelta);
+ SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelMin), scaling->MinLevel);
+ SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelMax), scaling->MaxLevel);
- SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelDelta), delta);
- }
+ int32 mindelta = std::min(scaling->DeltaLevelMax, scaling->DeltaLevelMin);
+ int32 maxdelta = std::max(scaling->DeltaLevelMax, scaling->DeltaLevelMin);
+ int32 delta = mindelta == maxdelta ? mindelta : irand(mindelta, maxdelta);
+
+ SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ScalingLevelDelta), delta);
+ SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::ContentTuningID), scaling->ContentTuningID);
UpdateLevelDependantStats();
}
@@ -1391,12 +1413,13 @@ void Creature::UpdateLevelDependantStats()
{
CreatureTemplate const* cInfo = GetCreatureTemplate();
uint32 rank = IsPet() ? 0 : cInfo->rank;
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class);
+ uint8 level = getLevel();
+ CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
// health
float healthmod = _GetHealthMod(rank);
- uint32 basehp = stats->GenerateHealth(cInfo);
+ uint32 basehp = GetMaxHealthByLevel(level);
uint32 health = uint32(basehp * healthmod);
SetCreateHealth(health);
@@ -1422,7 +1445,7 @@ void Creature::UpdateLevelDependantStats()
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
// damage
- float basedamage = stats->GenerateBaseDamage(cInfo);
+ float basedamage = GetBaseDamageForLevel(level);
float weaponBaseMinDamage = basedamage;
float weaponBaseMaxDamage = basedamage * 1.5f;
@@ -1439,7 +1462,7 @@ void Creature::UpdateLevelDependantStats()
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
- float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float?
+ float armor = GetBaseArmorForLevel(level); /// @todo Why is this treated as uint32 when it's a float?
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, armor);
}
@@ -2670,14 +2693,17 @@ void Creature::AllLootRemovedFromCorpse()
bool Creature::HasScalableLevels() const
{
CreatureTemplate const* cinfo = GetCreatureTemplate();
- return cinfo->levelScaling.is_initialized();
+ CreatureLevelScaling const* scaling = cinfo->GetLevelScaling(GetMap()->GetDifficultyID());
+
+ return (scaling->MinLevel != 0 && scaling->MaxLevel != 0);
}
uint64 Creature::GetMaxHealthByLevel(uint8 level) const
{
CreatureTemplate const* cInfo = GetCreatureTemplate();
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
- return stats->GenerateHealth(cInfo);
+ CreatureLevelScaling const* scaling = cInfo->GetLevelScaling(GetMap()->GetDifficultyID());
+ float baseHealth = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureHealth, level, cInfo->HealthScalingExpansion, scaling->ContentTuningID, Classes(cInfo->unit_class));
+ return baseHealth * cInfo->ModHealth * cInfo->ModHealthExtra;
}
float Creature::GetHealthMultiplierForTarget(WorldObject const* target) const
@@ -2695,8 +2721,8 @@ float Creature::GetHealthMultiplierForTarget(WorldObject const* target) const
float Creature::GetBaseDamageForLevel(uint8 level) const
{
CreatureTemplate const* cInfo = GetCreatureTemplate();
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
- return stats->GenerateBaseDamage(cInfo);
+ CreatureLevelScaling const* scaling = cInfo->GetLevelScaling(GetMap()->GetDifficultyID());
+ return sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureAutoAttackDps, level, cInfo->HealthScalingExpansion, scaling->ContentTuningID, Classes(cInfo->unit_class));
}
float Creature::GetDamageMultiplierForTarget(WorldObject const* target) const
@@ -2712,8 +2738,9 @@ float Creature::GetDamageMultiplierForTarget(WorldObject const* target) const
float Creature::GetBaseArmorForLevel(uint8 level) const
{
CreatureTemplate const* cInfo = GetCreatureTemplate();
- CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
- return stats->GenerateArmor(cInfo);
+ CreatureLevelScaling const* scaling = cInfo->GetLevelScaling(GetMap()->GetDifficultyID());
+ float baseArmor = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureArmor, level, cInfo->HealthScalingExpansion, scaling->ContentTuningID, Classes(cInfo->unit_class));
+ return baseArmor * cInfo->ModArmor;
}
float Creature::GetArmorMultiplierForTarget(WorldObject const* target) const
diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h
index d5657ced163..c7adebf0887 100644
--- a/src/server/game/Entities/Creature/CreatureData.h
+++ b/src/server/game/Entities/Creature/CreatureData.h
@@ -288,7 +288,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000, // creature ignore pathfinding
CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK = 0x40000000, // creature is immune to knockback effects
- CREATURE_FLAG_EXTRA_UNUSED_31 = 0x80000000,
+ CREATURE_FLAG_EXTRA_UNUSED_31 = 0x80000000,
// Masks
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_11 | CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_13 |
@@ -309,14 +309,6 @@ const uint32 MAX_CREATURE_NAMES = 4;
const uint32 MAX_CREATURE_SPELLS = 8;
const uint32 MAX_CREATURE_DIFFICULTIES = 3;
-struct CreatureLevelScaling
-{
- uint16 MinLevel;
- uint16 MaxLevel;
- int16 DeltaLevelMin;
- int16 DeltaLevelMax;
-};
-
struct CreatureModel
{
static CreatureModel const DefaultInvisibleModel;
@@ -333,6 +325,15 @@ struct CreatureModel
float Probability;
};
+struct CreatureLevelScaling
+{
+ uint16 MinLevel;
+ uint16 MaxLevel;
+ int16 DeltaLevelMin;
+ int16 DeltaLevelMax;
+ int32 ContentTuningID;
+};
+
// from `creature_template` table
struct TC_GAME_API CreatureTemplate
{
@@ -348,7 +349,7 @@ struct TC_GAME_API CreatureTemplate
uint32 GossipMenuId;
int16 minlevel;
int16 maxlevel;
- Optional<CreatureLevelScaling> levelScaling;
+ std::unordered_map<Difficulty, CreatureLevelScaling> scalingStore;
int32 HealthScalingExpansion;
uint32 RequiredExpansion;
uint32 VignetteID; /// @todo Read Vignette.db2
@@ -408,6 +409,7 @@ struct TC_GAME_API CreatureTemplate
CreatureModel const* GetModelWithDisplayId(uint32 displayId) const;
CreatureModel const* GetFirstInvisibleModel() const;
CreatureModel const* GetFirstVisibleModel() const;
+ CreatureLevelScaling const* GetLevelScaling(Difficulty difficulty) const;
// helpers
SkillType GetRequiredLootSkill() const
@@ -477,20 +479,11 @@ struct TC_GAME_API CreatureTemplate
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
struct TC_GAME_API CreatureBaseStats
{
- uint32 BaseHealth[MAX_EXPANSIONS];
uint32 BaseMana;
- uint32 BaseArmor;
uint32 AttackPower;
uint32 RangedAttackPower;
- float BaseDamage[MAX_EXPANSIONS];
// Helpers
-
- uint32 GenerateHealth(CreatureTemplate const* info) const
- {
- return uint32(ceil(BaseHealth[info->HealthScalingExpansion] * info->ModHealth * info->ModHealthExtra));
- }
-
uint32 GenerateMana(CreatureTemplate const* info) const
{
// Mana can be 0.
@@ -500,16 +493,6 @@ struct TC_GAME_API CreatureBaseStats
return uint32(ceil(BaseMana * info->ModMana * info->ModManaExtra));
}
- uint32 GenerateArmor(CreatureTemplate const* info) const
- {
- return uint32(ceil(BaseArmor * info->ModArmor));
- }
-
- float GenerateBaseDamage(CreatureTemplate const* info) const
- {
- return BaseDamage[info->HealthScalingExpansion];
- }
-
static CreatureBaseStats const* GetBaseStats(uint8 level, uint8 unitClass);
};
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 8852af1be8c..53dbc7b484c 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -840,7 +840,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
{
// remove elite bonuses included in DB values
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(petlevel, cinfo->unit_class);
- SetCreateHealth(stats->BaseHealth[cinfo->HealthScalingExpansion]);
+ CreatureLevelScaling const* scaling = cinfo->GetLevelScaling(GetMap()->GetDifficultyID());
+
+ SetCreateHealth(sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureHealth, petlevel, cinfo->HealthScalingExpansion, scaling->ContentTuningID, Classes(cinfo->unit_class)) * cinfo->ModHealth * cinfo->ModHealthExtra);
SetCreateMana(stats->BaseMana);
SetCreateStat(STAT_STRENGTH, 22);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index ad69398d494..e3441184188 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -1640,14 +1640,13 @@ uint32 Unit::CalcArmorReducedDamage(Unit* attacker, Unit* victim, const uint32 d
return damage;
uint8 attackerLevel = attacker->GetLevelForTarget(victim);
- if (attackerLevel > sArmorMitigationByLvlGameTable.GetTableRowCount())
- attackerLevel = sArmorMitigationByLvlGameTable.GetTableRowCount();
+ // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
+ float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, Classes(attacker->getClass()));
- GtArmorMitigationByLvlEntry const* ambl = sArmorMitigationByLvlGameTable.GetRow(attackerLevel);
- if (!ambl)
+ if (!armorConstant)
return damage;
- float mitigation = std::min(armor / (armor + ambl->Mitigation), 0.85f);
+ float mitigation = std::min(armor / (armor + armorConstant), 0.85f);
return std::max<uint32>(damage * (1.0f - mitigation), 1);
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index f519c69948f..e26fe6308ee 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -704,8 +704,8 @@ void ObjectMgr::LoadCreatureScalingData()
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3 4
- QueryResult result = WorldDatabase.Query("SELECT Entry, LevelScalingMin, LevelScalingMax, LevelScalingDeltaMin, LevelScalingDeltaMax FROM creature_template_scaling");
+ // 0 1 2 3 4 5 6
+ QueryResult result = WorldDatabase.Query("SELECT Entry, DifficultyID, LevelScalingMin, LevelScalingMax, LevelScalingDeltaMin, LevelScalingDeltaMax, ContentTuningID FROM creature_template_scaling ORDER BY Entry");
if (!result)
{
@@ -719,8 +719,9 @@ void ObjectMgr::LoadCreatureScalingData()
Field* fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
+ Difficulty difficulty = Difficulty(fields[1].GetUInt8());
- CreatureTemplateContainer::iterator itr = _creatureTemplateStore.find(entry);
+ auto itr = _creatureTemplateStore.find(entry);
if (itr == _creatureTemplateStore.end())
{
TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_template_scaling`", entry);
@@ -728,11 +729,13 @@ void ObjectMgr::LoadCreatureScalingData()
}
CreatureLevelScaling creatureLevelScaling;
- creatureLevelScaling.MinLevel = fields[1].GetUInt16();
- creatureLevelScaling.MaxLevel = fields[2].GetUInt16();
- creatureLevelScaling.DeltaLevelMin = fields[3].GetInt16();
- creatureLevelScaling.DeltaLevelMax = fields[4].GetInt16();
- itr->second.levelScaling = creatureLevelScaling;
+ creatureLevelScaling.MinLevel = fields[2].GetUInt16();
+ creatureLevelScaling.MaxLevel = fields[3].GetUInt16();
+ creatureLevelScaling.DeltaLevelMin = fields[4].GetInt16();
+ creatureLevelScaling.DeltaLevelMax = fields[5].GetInt16();
+ creatureLevelScaling.ContentTuningID = fields[6].GetInt32();
+
+ itr->second.scalingStore[difficulty] = creatureLevelScaling;
++count;
} while (result->NextRow());
@@ -2232,6 +2235,8 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, float
if (!map)
return UI64LIT(0);
+ CreatureLevelScaling const* scaling = cInfo->GetLevelScaling(map->GetDifficultyID());
+
ObjectGuid::LowType guid = GenerateCreatureSpawnId();
CreatureData& data = NewOrExistCreatureData(guid);
data.id = entry;
@@ -2245,7 +2250,7 @@ ObjectGuid::LowType ObjectMgr::AddCreatureData(uint32 entry, uint32 mapId, float
data.spawntimesecs = spawntimedelay;
data.spawndist = 0;
data.currentwaypoint = 0;
- data.curhealth = stats->GenerateHealth(cInfo);
+ data.curhealth = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureHealth, level, cInfo->HealthScalingExpansion, scaling->ContentTuningID, Classes(cInfo->unit_class)) * cInfo->ModHealth * cInfo->ModHealthExtra;
data.curmana = stats->GenerateMana(cInfo);
data.movementType = cInfo->MovementType;
data.spawnDifficulties.push_back(DIFFICULTY_NONE);
@@ -9222,12 +9227,6 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit
{
DefaultCreatureBaseStats()
{
- BaseArmor = 1;
- for (uint8 j = 0; j < MAX_EXPANSIONS; ++j)
- {
- BaseHealth[j] = 1;
- BaseDamage[j] = 0.0f;
- }
BaseMana = 0;
AttackPower = 0;
RangedAttackPower = 0;
@@ -9240,8 +9239,8 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit
void ObjectMgr::LoadCreatureClassLevelStats()
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3 4 5
- QueryResult result = WorldDatabase.Query("SELECT level, class, basemana, basearmor, attackpower, rangedattackpower FROM creature_classlevelstats");
+ // 0 1 2 3 4
+ QueryResult result = WorldDatabase.Query("SELECT level, class, basemana, attackpower, rangedattackpower FROM creature_classlevelstats");
if (!result)
{
@@ -9262,22 +9261,10 @@ void ObjectMgr::LoadCreatureClassLevelStats()
CreatureBaseStats stats;
- for (uint8 i = 0; i < MAX_EXPANSIONS; ++i)
- {
- stats.BaseHealth[i] = GetGameTableColumnForClass(sNpcTotalHpGameTable[i].GetRow(Level), Class);
- stats.BaseDamage[i] = GetGameTableColumnForClass(sNpcDamageByClassGameTable[i].GetRow(Level), Class);
- if (stats.BaseDamage[i] < 0.0f)
- {
- TC_LOG_ERROR("sql.sql", "Creature base stats for class %u, level %u has invalid negative base damage[%u] - set to 0.0", Class, Level, i);
- stats.BaseDamage[i] = 0.0f;
- }
- }
-
stats.BaseMana = fields[2].GetUInt32();
- stats.BaseArmor = fields[3].GetUInt32();
- stats.AttackPower = fields[4].GetUInt16();
- stats.RangedAttackPower = fields[5].GetUInt16();
+ stats.AttackPower = fields[3].GetUInt16();
+ stats.RangedAttackPower = fields[4].GetUInt16();
_creatureBaseStatsStore[MAKE_PAIR16(Level, Class)] = stats;
diff --git a/src/server/game/Server/Packets/CombatLogPacketsCommon.cpp b/src/server/game/Server/Packets/CombatLogPacketsCommon.cpp
index fc5af6e5fbe..f70f96234f0 100644
--- a/src/server/game/Server/Packets/CombatLogPacketsCommon.cpp
+++ b/src/server/game/Server/Packets/CombatLogPacketsCommon.cpp
@@ -64,6 +64,7 @@ namespace WorldPackets
bool ContentTuningParams::GenerateDataForUnits<Creature, Player>(Creature* attacker, Player* target)
{
CreatureTemplate const* creatureTemplate = attacker->GetCreatureTemplate();
+ CreatureLevelScaling const* creatureScaling = creatureTemplate->GetLevelScaling(attacker->GetMap()->GetDifficultyID());
Type = TYPE_CREATURE_TO_PLAYER_DAMAGE;
PlayerLevelDelta = target->m_activePlayerData->ScalingPlayerLevelDelta;
@@ -71,9 +72,9 @@ namespace WorldPackets
TargetItemLevel = 0;
ScalingHealthItemLevelCurveID = target->m_unitData->ScalingHealthItemLevelCurveID;
TargetLevel = target->getLevel();
- Expansion = creatureTemplate->RequiredExpansion;
- TargetMinScalingLevel = uint8(creatureTemplate->levelScaling->MinLevel);
- TargetMaxScalingLevel = uint8(creatureTemplate->levelScaling->MaxLevel);
+ Expansion = creatureTemplate->HealthScalingExpansion;
+ TargetMinScalingLevel = uint8(creatureScaling->MinLevel);
+ TargetMaxScalingLevel = uint8(creatureScaling->MaxLevel);
TargetScalingLevelDelta = int8(attacker->m_unitData->ScalingLevelDelta);
return true;
}
@@ -82,6 +83,7 @@ namespace WorldPackets
bool ContentTuningParams::GenerateDataForUnits<Player, Creature>(Player* attacker, Creature* target)
{
CreatureTemplate const* creatureTemplate = target->GetCreatureTemplate();
+ CreatureLevelScaling const* creatureScaling = creatureTemplate->GetLevelScaling(target->GetMap()->GetDifficultyID());
Type = TYPE_PLAYER_TO_CREATURE_DAMAGE;
PlayerLevelDelta = attacker->m_activePlayerData->ScalingPlayerLevelDelta;
@@ -89,9 +91,9 @@ namespace WorldPackets
TargetItemLevel = 0;
ScalingHealthItemLevelCurveID = target->m_unitData->ScalingHealthItemLevelCurveID;
TargetLevel = target->getLevel();
- Expansion = creatureTemplate->RequiredExpansion;
- TargetMinScalingLevel = uint8(creatureTemplate->levelScaling->MinLevel);
- TargetMaxScalingLevel = uint8(creatureTemplate->levelScaling->MaxLevel);
+ Expansion = creatureTemplate->HealthScalingExpansion;
+ TargetMinScalingLevel = uint8(creatureScaling->MinLevel);
+ TargetMaxScalingLevel = uint8(creatureScaling->MaxLevel);
TargetScalingLevelDelta = int8(target->m_unitData->ScalingLevelDelta);
return true;
}
@@ -101,14 +103,15 @@ namespace WorldPackets
{
Creature* accessor = target->HasScalableLevels() ? target : attacker;
CreatureTemplate const* creatureTemplate = accessor->GetCreatureTemplate();
+ CreatureLevelScaling const* creatureScaling = creatureTemplate->GetLevelScaling(accessor->GetMap()->GetDifficultyID());
Type = TYPE_CREATURE_TO_CREATURE_DAMAGE;
PlayerLevelDelta = 0;
PlayerItemLevel = 0;
TargetLevel = target->getLevel();
- Expansion = creatureTemplate->RequiredExpansion;
- TargetMinScalingLevel = uint8(creatureTemplate->levelScaling->MinLevel);
- TargetMaxScalingLevel = uint8(creatureTemplate->levelScaling->MaxLevel);
+ Expansion = creatureTemplate->HealthScalingExpansion;
+ TargetMinScalingLevel = uint8(creatureScaling->MinLevel);
+ TargetMaxScalingLevel = uint8(creatureScaling->MaxLevel);
TargetScalingLevelDelta = int8(accessor->m_unitData->ScalingLevelDelta);
return true;
}
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp
index 8f2be503c56..05e0867daa5 100644
--- a/src/tools/map_extractor/System.cpp
+++ b/src/tools/map_extractor/System.cpp
@@ -1356,7 +1356,6 @@ void ExtractGameTables()
DB2FileInfo GameTables[] =
{
- { 1385707, "ArmorMitigationByLvl.txt" },
{ 1582086, "ArtifactKnowledgeMultiplier.txt" },
{ 1391662, "ArtifactLevelXP.txt" },
{ 1892815, "AzeriteBaseExperiencePerLevel.txt" },
@@ -1375,23 +1374,7 @@ void ExtractGameTables()
{ 2012881, "ItemLevelByLevel.txt" },
{ 1726830, "ItemLevelSquish.txt" },
{ 1391643, "ItemSocketCostPerLevel.txt" },
- { 1391644, "NpcDamageByClass.txt" },
- { 1391645, "NpcDamageByClassExp1.txt" },
- { 1391646, "NpcDamageByClassExp2.txt" },
- { 1391647, "NpcDamageByClassExp3.txt" },
- { 1391648, "NpcDamageByClassExp4.txt" },
- { 1391649, "NpcDamageByClassExp5.txt" },
- { 1391650, "NpcDamageByClassExp6.txt" },
- { 1536195, "NpcDamageByClassExp7.txt" },
{ 1391651, "NPCManaCostScaler.txt" },
- { 1391652, "NpcTotalHp.txt" },
- { 1391653, "NpcTotalHpExp1.txt" },
- { 1391654, "NpcTotalHpExp2.txt" },
- { 1391655, "NpcTotalHpExp3.txt" },
- { 1391656, "NpcTotalHpExp4.txt" },
- { 1391657, "NpcTotalHpExp5.txt" },
- { 1391658, "NpcTotalHpExp6.txt" },
- { 1536196, "NpcTotalHpExp7.txt" },
{ 1391659, "SandboxScaling.txt" },
{ 1391660, "SpellScaling.txt" },
{ 1980632, "StaminaMultByILvl.txt" },