Core/Creatures: Update creature scaling to use content tuning
Closes #22831
This commit is contained in:
@@ -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`;
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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" },
|
||||
|
||||
Reference in New Issue
Block a user