Core/Creatures: Update creature scaling to use content tuning

Port From (https://github.com/TrinityCore/TrinityCore/commit/314a35f0cd912daed7c0663f4f13552b6747fd98)
This commit is contained in:
hondacrx
2020-05-20 15:27:22 -04:00
parent 2acce62671
commit c1dbec58bd
10 changed files with 85 additions and 147 deletions
-20
View File
@@ -359,7 +359,6 @@ namespace Game.DataStorage
DataPath = dataPath + "/gt/"; DataPath = dataPath + "/gt/";
ArmorMitigationByLvlGameTable = GameTableReader.Read<GtArmorMitigationByLvlRecord>("ArmorMitigationByLvl.txt");
ArtifactKnowledgeMultiplierGameTable = GameTableReader.Read<GtArtifactKnowledgeMultiplierRecord>("ArtifactKnowledgeMultiplier.txt"); ArtifactKnowledgeMultiplierGameTable = GameTableReader.Read<GtArtifactKnowledgeMultiplierRecord>("ArtifactKnowledgeMultiplier.txt");
ArtifactLevelXPGameTable = GameTableReader.Read<GtArtifactLevelXPRecord>("artifactLevelXP.txt"); ArtifactLevelXPGameTable = GameTableReader.Read<GtArtifactLevelXPRecord>("artifactLevelXP.txt");
BarberShopCostBaseGameTable = GameTableReader.Read<GtBarberShopCostBaseRecord>("BarberShopCostBase.txt"); BarberShopCostBaseGameTable = GameTableReader.Read<GtBarberShopCostBaseRecord>("BarberShopCostBase.txt");
@@ -368,23 +367,7 @@ namespace Game.DataStorage
CombatRatingsMultByILvlGameTable = GameTableReader.Read<GtGenericMultByILvlRecord>("CombatRatingsMultByILvl.txt"); CombatRatingsMultByILvlGameTable = GameTableReader.Read<GtGenericMultByILvlRecord>("CombatRatingsMultByILvl.txt");
ItemSocketCostPerLevelGameTable = GameTableReader.Read<GtItemSocketCostPerLevelRecord>("ItemSocketCostPerLevel.txt"); ItemSocketCostPerLevelGameTable = GameTableReader.Read<GtItemSocketCostPerLevelRecord>("ItemSocketCostPerLevel.txt");
HpPerStaGameTable = GameTableReader.Read<GtHpPerStaRecord>("HpPerSta.txt"); HpPerStaGameTable = GameTableReader.Read<GtHpPerStaRecord>("HpPerSta.txt");
NpcDamageByClassGameTable[0] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClass.txt");
NpcDamageByClassGameTable[1] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp1.txt");
NpcDamageByClassGameTable[2] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp2.txt");
NpcDamageByClassGameTable[3] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp3.txt");
NpcDamageByClassGameTable[4] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp4.txt");
NpcDamageByClassGameTable[5] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp5.txt");
NpcDamageByClassGameTable[6] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp6.txt");
NpcDamageByClassGameTable[7] = GameTableReader.Read<GtNpcDamageByClassRecord>("NpcDamageByClassExp7.txt");
NpcManaCostScalerGameTable = GameTableReader.Read<GtNpcManaCostScalerRecord>("NPCManaCostScaler.txt"); NpcManaCostScalerGameTable = GameTableReader.Read<GtNpcManaCostScalerRecord>("NPCManaCostScaler.txt");
NpcTotalHpGameTable[0] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHp.txt");
NpcTotalHpGameTable[1] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp1.txt");
NpcTotalHpGameTable[2] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp2.txt");
NpcTotalHpGameTable[3] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp3.txt");
NpcTotalHpGameTable[4] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp4.txt");
NpcTotalHpGameTable[5] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp5.txt");
NpcTotalHpGameTable[6] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp6.txt");
NpcTotalHpGameTable[7] = GameTableReader.Read<GtNpcTotalHpRecord>("NpcTotalHpExp7.txt");
SpellScalingGameTable = GameTableReader.Read<GtSpellScalingRecord>("SpellScaling.txt"); SpellScalingGameTable = GameTableReader.Read<GtSpellScalingRecord>("SpellScaling.txt");
StaminaMultByILvlGameTable = GameTableReader.Read<GtGenericMultByILvlRecord>("StaminaMultByILvl.txt"); StaminaMultByILvlGameTable = GameTableReader.Read<GtGenericMultByILvlRecord>("StaminaMultByILvl.txt");
XpGameTable = GameTableReader.Read<GtXpRecord>("xp.txt"); XpGameTable = GameTableReader.Read<GtXpRecord>("xp.txt");
@@ -648,7 +631,6 @@ namespace Game.DataStorage
#endregion #endregion
#region GameTables #region GameTables
public static GameTable<GtArmorMitigationByLvlRecord> ArmorMitigationByLvlGameTable;
public static GameTable<GtArtifactKnowledgeMultiplierRecord> ArtifactKnowledgeMultiplierGameTable; public static GameTable<GtArtifactKnowledgeMultiplierRecord> ArtifactKnowledgeMultiplierGameTable;
public static GameTable<GtArtifactLevelXPRecord> ArtifactLevelXPGameTable; public static GameTable<GtArtifactLevelXPRecord> ArtifactLevelXPGameTable;
public static GameTable<GtBarberShopCostBaseRecord> BarberShopCostBaseGameTable; public static GameTable<GtBarberShopCostBaseRecord> BarberShopCostBaseGameTable;
@@ -657,9 +639,7 @@ namespace Game.DataStorage
public static GameTable<GtGenericMultByILvlRecord> CombatRatingsMultByILvlGameTable; public static GameTable<GtGenericMultByILvlRecord> CombatRatingsMultByILvlGameTable;
public static GameTable<GtHpPerStaRecord> HpPerStaGameTable; public static GameTable<GtHpPerStaRecord> HpPerStaGameTable;
public static GameTable<GtItemSocketCostPerLevelRecord> ItemSocketCostPerLevelGameTable; public static GameTable<GtItemSocketCostPerLevelRecord> ItemSocketCostPerLevelGameTable;
public static GameTable<GtNpcDamageByClassRecord>[] NpcDamageByClassGameTable = new GameTable<GtNpcDamageByClassRecord>[(int)Expansion.Max];
public static GameTable<GtNpcManaCostScalerRecord> NpcManaCostScalerGameTable; public static GameTable<GtNpcManaCostScalerRecord> NpcManaCostScalerGameTable;
public static GameTable<GtNpcTotalHpRecord>[] NpcTotalHpGameTable = new GameTable<GtNpcTotalHpRecord>[(int)Expansion.Max];
public static GameTable<GtSpellScalingRecord> SpellScalingGameTable; public static GameTable<GtSpellScalingRecord> SpellScalingGameTable;
public static GameTable<GtGenericMultByILvlRecord> StaminaMultByILvlGameTable; public static GameTable<GtGenericMultByILvlRecord> StaminaMultByILvlGameTable;
public static GameTable<GtXpRecord> XpGameTable; public static GameTable<GtXpRecord> XpGameTable;
@@ -17,11 +17,6 @@
namespace Game.DataStorage namespace Game.DataStorage
{ {
public sealed class GtArmorMitigationByLvlRecord
{
public float Mitigation;
}
public sealed class GtArtifactKnowledgeMultiplierRecord public sealed class GtArtifactKnowledgeMultiplierRecord
{ {
public float Multiplier; public float Multiplier;
@@ -108,43 +103,11 @@ namespace Game.DataStorage
public float SocketCost; public float SocketCost;
} }
public sealed class GtNpcDamageByClassRecord
{
public float Rogue;
public float Druid;
public float Hunter;
public float Mage;
public float Paladin;
public float Priest;
public float Shaman;
public float Warlock;
public float Warrior;
public float DeathKnight;
public float Monk;
public float DemonHunter;
}
public sealed class GtNpcManaCostScalerRecord public sealed class GtNpcManaCostScalerRecord
{ {
public float Scaler; public float Scaler;
} }
public sealed class GtNpcTotalHpRecord
{
public float Rogue;
public float Druid;
public float Hunter;
public float Mage;
public float Paladin;
public float Priest;
public float Shaman;
public float Warlock;
public float Warrior;
public float DeathKnight;
public float Monk;
public float DemonHunter;
}
public sealed class GtSpellScalingRecord public sealed class GtSpellScalingRecord
{ {
public float Rogue; public float Rogue;
+25 -20
View File
@@ -1150,17 +1150,17 @@ namespace Game.Entities
byte level = (byte)(minlevel == maxlevel ? minlevel : RandomHelper.URand(minlevel, maxlevel)); byte level = (byte)(minlevel == maxlevel ? minlevel : RandomHelper.URand(minlevel, maxlevel));
SetLevel(level); SetLevel(level);
if (HasScalableLevels()) CreatureLevelScaling scaling = cInfo.GetLevelScaling(GetMap().GetDifficultyID());
{
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelMin), cInfo.levelScaling.Value.MinLevel);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelMax), cInfo.levelScaling.Value.MaxLevel);
int mindelta = Math.Min(cInfo.levelScaling.Value.DeltaLevelMax, cInfo.levelScaling.Value.DeltaLevelMin); SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelMin), scaling.MinLevel);
int maxdelta = Math.Max(cInfo.levelScaling.Value.DeltaLevelMax, cInfo.levelScaling.Value.DeltaLevelMin); SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelMax), scaling.MaxLevel);
int delta = mindelta == maxdelta ? mindelta : RandomHelper.IRand(mindelta, maxdelta);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelDelta), delta); int mindelta = Math.Min(scaling.DeltaLevelMax, scaling.DeltaLevelMin);
} int maxdelta = Math.Max(scaling.DeltaLevelMax, scaling.DeltaLevelMin);
int delta = mindelta == maxdelta ? mindelta : RandomHelper.IRand(mindelta, maxdelta);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ScalingLevelDelta), delta);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ContentTuningID), scaling.ContentTuningID);
UpdateLevelDependantStats(); UpdateLevelDependantStats();
} }
@@ -1169,12 +1169,13 @@ namespace Game.Entities
{ {
CreatureTemplate cInfo = GetCreatureTemplate(); CreatureTemplate cInfo = GetCreatureTemplate();
CreatureEliteType rank = IsPet() ? 0 : cInfo.Rank; CreatureEliteType rank = IsPet() ? 0 : cInfo.Rank;
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(GetLevel(), cInfo.UnitClass); uint level = GetLevel();
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass);
// health // health
float healthmod = _GetHealthMod(rank); float healthmod = _GetHealthMod(rank);
uint basehp = stats.GenerateHealth(cInfo); uint basehp = (uint)GetMaxHealthByLevel(level);
uint health = (uint)(basehp * healthmod); uint health = (uint)(basehp * healthmod);
SetCreateHealth(health); SetCreateHealth(health);
@@ -1200,7 +1201,7 @@ namespace Game.Entities
SetStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, health); SetStatFlatModifier(UnitMods.Health, UnitModifierFlatType.Base, health);
//Damage //Damage
float basedamage = stats.GenerateBaseDamage(cInfo); float basedamage = GetBaseDamageForLevel(level);
float weaponBaseMinDamage = basedamage; float weaponBaseMinDamage = basedamage;
float weaponBaseMaxDamage = basedamage * 1.5f; float weaponBaseMaxDamage = basedamage * 1.5f;
@@ -1216,7 +1217,7 @@ namespace Game.Entities
SetStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Base, stats.AttackPower); SetStatFlatModifier(UnitMods.AttackPower, UnitModifierFlatType.Base, stats.AttackPower);
SetStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Base, stats.RangedAttackPower); SetStatFlatModifier(UnitMods.AttackPowerRanged, UnitModifierFlatType.Base, stats.RangedAttackPower);
float armor = 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(UnitMods.Armor, UnitModifierFlatType.Base, armor); SetStatFlatModifier(UnitMods.Armor, UnitModifierFlatType.Base, armor);
} }
@@ -2352,14 +2353,17 @@ namespace Game.Entities
public bool HasScalableLevels() public bool HasScalableLevels()
{ {
CreatureTemplate cinfo = GetCreatureTemplate(); CreatureTemplate cinfo = GetCreatureTemplate();
return cinfo.levelScaling.HasValue; CreatureLevelScaling scaling = cinfo.GetLevelScaling(GetMap().GetDifficultyID());
return (scaling.MinLevel != 0 && scaling.MaxLevel != 0);
} }
ulong GetMaxHealthByLevel(uint level) ulong GetMaxHealthByLevel(uint level)
{ {
CreatureTemplate cInfo = GetCreatureTemplate(); CreatureTemplate cInfo = GetCreatureTemplate();
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass); CreatureLevelScaling scaling = cInfo.GetLevelScaling(GetMap().GetDifficultyID());
return stats.GenerateHealth(cInfo); float baseHealth = Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureHealth, level, cInfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cInfo.UnitClass);
return (ulong)(baseHealth * cInfo.ModHealth * cInfo.ModHealthExtra);
} }
public override float GetHealthMultiplierForTarget(WorldObject target) public override float GetHealthMultiplierForTarget(WorldObject target)
@@ -2377,8 +2381,8 @@ namespace Game.Entities
float GetBaseDamageForLevel(uint level) float GetBaseDamageForLevel(uint level)
{ {
CreatureTemplate cInfo = GetCreatureTemplate(); CreatureTemplate cInfo = GetCreatureTemplate();
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass); CreatureLevelScaling scaling = cInfo.GetLevelScaling(GetMap().GetDifficultyID());
return stats.GenerateBaseDamage(cInfo); return Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureAutoAttackDps, level, cInfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cInfo.UnitClass);
} }
public override float GetDamageMultiplierForTarget(WorldObject target) public override float GetDamageMultiplierForTarget(WorldObject target)
@@ -2394,8 +2398,9 @@ namespace Game.Entities
float GetBaseArmorForLevel(uint level) float GetBaseArmorForLevel(uint level)
{ {
CreatureTemplate cInfo = GetCreatureTemplate(); CreatureTemplate cInfo = GetCreatureTemplate();
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass); CreatureLevelScaling scaling = cInfo.GetLevelScaling(GetMap().GetDifficultyID());
return stats.GenerateArmor(cInfo); float baseArmor = Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureArmor, level, cInfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cInfo.UnitClass);
return baseArmor * cInfo.ModArmor;
} }
public override float GetArmorMultiplierForTarget(WorldObject target) public override float GetArmorMultiplierForTarget(WorldObject target)
+12 -20
View File
@@ -37,7 +37,7 @@ namespace Game.Entities
public string IconName; public string IconName;
public uint GossipMenuId; public uint GossipMenuId;
public short Minlevel; public short Minlevel;
public Optional<CreatureLevelScaling> levelScaling; public Dictionary<Difficulty, CreatureLevelScaling> scalingStorage = new Dictionary<Difficulty, CreatureLevelScaling>();
public short Maxlevel; public short Maxlevel;
public int HealthScalingExpansion; public int HealthScalingExpansion;
public uint RequiredExpansion; public uint RequiredExpansion;
@@ -265,23 +265,24 @@ namespace Game.Entities
QueryData.Stats = stats; QueryData.Stats = stats;
} }
public CreatureLevelScaling GetLevelScaling(Difficulty difficulty)
{
var creatureLevelScaling = scalingStorage.LookupByKey(difficulty);
if (creatureLevelScaling != null)
return creatureLevelScaling;
return new CreatureLevelScaling();
}
} }
public class CreatureBaseStats public class CreatureBaseStats
{ {
public uint[] BaseHealth = new uint[(int)Expansion.Max];
public uint BaseMana; public uint BaseMana;
public uint BaseArmor;
public uint AttackPower; public uint AttackPower;
public uint RangedAttackPower; public uint RangedAttackPower;
public float[] BaseDamage = new float[(int)Expansion.Max];
// Helpers // Helpers
public uint GenerateHealth(CreatureTemplate info)
{
return (uint)Math.Ceiling(BaseHealth[info.HealthScalingExpansion] * info.ModHealth * info.ModHealthExtra);
}
public uint GenerateMana(CreatureTemplate info) public uint GenerateMana(CreatureTemplate info)
{ {
// Mana can be 0. // Mana can be 0.
@@ -290,16 +291,6 @@ namespace Game.Entities
return (uint)Math.Ceiling(BaseMana * info.ModMana * info.ModManaExtra); return (uint)Math.Ceiling(BaseMana * info.ModMana * info.ModManaExtra);
} }
public float GenerateArmor(CreatureTemplate info)
{
return (float)Math.Ceiling(BaseArmor * info.ModArmor);
}
public float GenerateBaseDamage(CreatureTemplate info)
{
return BaseDamage[info.HealthScalingExpansion];
}
} }
public class CreatureLocale public class CreatureLocale
@@ -459,11 +450,12 @@ namespace Game.Entities
} }
} }
public struct CreatureLevelScaling public class CreatureLevelScaling
{ {
public ushort MinLevel; public ushort MinLevel;
public ushort MaxLevel; public ushort MaxLevel;
public short DeltaLevelMin; public short DeltaLevelMin;
public short DeltaLevelMax; public short DeltaLevelMax;
public uint ContentTuningID;
} }
} }
@@ -1037,7 +1037,7 @@ namespace Game.Entities
public UpdateField<ulong> MaxHealth = new UpdateField<ulong>(0, 30); public UpdateField<ulong> MaxHealth = new UpdateField<ulong>(0, 30);
public UpdateField<uint> Level = new UpdateField<uint>(0, 31); public UpdateField<uint> Level = new UpdateField<uint>(0, 31);
public UpdateField<int> EffectiveLevel = new UpdateField<int>(32, 33); public UpdateField<int> EffectiveLevel = new UpdateField<int>(32, 33);
public UpdateField<int> ContentTuningID = new UpdateField<int>(32, 34); public UpdateField<uint> ContentTuningID = new UpdateField<uint>(32, 34);
public UpdateField<int> ScalingLevelMin = new UpdateField<int>(32, 35); public UpdateField<int> ScalingLevelMin = new UpdateField<int>(32, 35);
public UpdateField<int> ScalingLevelMax = new UpdateField<int>(32, 36); public UpdateField<int> ScalingLevelMax = new UpdateField<int>(32, 36);
public UpdateField<int> ScalingLevelDelta = new UpdateField<int>(32, 37); public UpdateField<int> ScalingLevelDelta = new UpdateField<int>(32, 37);
@@ -1186,7 +1186,7 @@ namespace Game.Entities
data.WriteUInt64(MaxHealth); data.WriteUInt64(MaxHealth);
data.WriteUInt32(Level); data.WriteUInt32(Level);
data.WriteInt32(EffectiveLevel); data.WriteInt32(EffectiveLevel);
data.WriteInt32(ContentTuningID); data.WriteUInt32(ContentTuningID);
data.WriteInt32(ScalingLevelMin); data.WriteInt32(ScalingLevelMin);
data.WriteInt32(ScalingLevelMax); data.WriteInt32(ScalingLevelMax);
data.WriteInt32(ScalingLevelDelta); data.WriteInt32(ScalingLevelDelta);
@@ -1541,7 +1541,7 @@ namespace Game.Entities
} }
if (changesMask[34]) if (changesMask[34])
{ {
data.WriteInt32(ContentTuningID); data.WriteUInt32(ContentTuningID);
} }
if (changesMask[35]) if (changesMask[35])
{ {
+4 -1
View File
@@ -487,7 +487,10 @@ namespace Game.Entities
{ {
// remove elite bonuses included in DB values // remove elite bonuses included in DB values
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(petlevel, cinfo.UnitClass); CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(petlevel, cinfo.UnitClass);
SetCreateHealth(stats.BaseHealth[cinfo.HealthScalingExpansion]); CreatureLevelScaling scaling = cinfo.GetLevelScaling(GetMap().GetDifficultyID());
SetCreateHealth((uint)(Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureHealth, petlevel, cinfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cinfo.UnitClass) * cinfo.ModHealth * cinfo.ModHealthExtra));
SetCreateMana(stats.BaseMana); SetCreateMana(stats.BaseMana);
SetCreateStat(Stats.Strength, 22); SetCreateStat(Stats.Strength, 22);
+4 -5
View File
@@ -2760,14 +2760,13 @@ namespace Game.Entities
return damage; return damage;
uint attackerLevel = attacker.GetLevelForTarget(victim); uint attackerLevel = attacker.GetLevelForTarget(victim);
if (attackerLevel > CliDB.ArmorMitigationByLvlGameTable.GetTableRowCount()) // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
attackerLevel = (uint)CliDB.ArmorMitigationByLvlGameTable.GetTableRowCount(); float armorConstant = Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.ArmorConstant, attackerLevel, -2, 0, attacker.GetClass());
GtArmorMitigationByLvlRecord ambl = CliDB.ArmorMitigationByLvlGameTable.GetRow(attackerLevel); if (armorConstant == 0)
if (ambl == null)
return damage; return damage;
float mitigation = Math.Min(armor / (armor + ambl.Mitigation), 0.85f); float mitigation = Math.Min(armor / (armor + armorConstant), 0.85f);
return Math.Max((uint)(damage * (1.0f - mitigation)), 1); return Math.Max((uint)(damage * (1.0f - mitigation)), 1);
} }
+18 -32
View File
@@ -2295,9 +2295,9 @@ namespace Game
var time = Time.GetMSTime(); var time = Time.GetMSTime();
creatureBaseStatsStorage.Clear(); creatureBaseStatsStorage.Clear();
// 0 1 2 3 4 5
SQLResult result = DB.World.Query("SELECT level, class, basemana, basearmor, attackpower, rangedattackpower FROM creature_classlevelstats");
// 0 1 2 3 4
SQLResult result = DB.World.Query("SELECT level, class, basemana, attackpower, rangedattackpower FROM creature_classlevelstats");
if (result.IsEmpty()) if (result.IsEmpty())
{ {
Log.outError(LogFilter.ServerLoading, "Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty."); Log.outError(LogFilter.ServerLoading, "Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty.");
@@ -2315,22 +2315,9 @@ namespace Game
CreatureBaseStats stats = new CreatureBaseStats(); CreatureBaseStats stats = new CreatureBaseStats();
for (var i = 0; i < (int)Expansion.Max; ++i)
{
stats.BaseHealth[i] = (uint)CliDB.GetGameTableColumnForClass(CliDB.NpcTotalHpGameTable[i].GetRow(Level), (Class)_class);
stats.BaseDamage[i] = CliDB.GetGameTableColumnForClass(CliDB.NpcDamageByClassGameTable[i].GetRow(Level), (Class)_class);
if (stats.BaseDamage[i] < 0.0f)
{
Log.outError(LogFilter.Sql, "Creature base stats for class {0}, level {1} has invalid negative base damage[{2}] - set to 0.0", _class, Level, i);
stats.BaseDamage[i] = 0.0f;
}
}
stats.BaseMana = result.Read<uint>(2); stats.BaseMana = result.Read<uint>(2);
stats.BaseArmor = result.Read<uint>(3); stats.AttackPower = result.Read<ushort>(3);
stats.RangedAttackPower = result.Read<ushort>(4);
stats.AttackPower = result.Read<ushort>(4);
stats.RangedAttackPower = result.Read<ushort>(5);
creatureBaseStatsStorage.Add(MathFunctions.MakePair16(Level, _class), stats); creatureBaseStatsStorage.Add(MathFunctions.MakePair16(Level, _class), stats);
@@ -2417,8 +2404,8 @@ namespace Game
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
// 0 1 2 3 4 // 0 1 2 3 4 5 6
SQLResult result = DB.World.Query("SELECT Entry, LevelScalingMin, LevelScalingMax, LevelScalingDeltaMin, LevelScalingDeltaMax FROM creature_template_scaling"); SQLResult result = DB.World.Query("SELECT Entry, DifficultyID, LevelScalingMin, LevelScalingMax, LevelScalingDeltaMin, LevelScalingDeltaMax, ContentTuningID FROM creature_template_scaling ORDER BY Entry");
if (result.IsEmpty()) if (result.IsEmpty())
{ {
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature template scaling definitions. DB table `creature_template_scaling` is empty."); Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature template scaling definitions. DB table `creature_template_scaling` is empty.");
@@ -2429,6 +2416,7 @@ namespace Game
do do
{ {
uint entry = result.Read<uint>(0); uint entry = result.Read<uint>(0);
Difficulty difficulty = (Difficulty)result.Read<byte>(1);
var template = _creatureTemplateStorage.LookupByKey(entry); var template = _creatureTemplateStorage.LookupByKey(entry);
if (template == null) if (template == null)
@@ -2437,12 +2425,14 @@ namespace Game
continue; continue;
} }
CreatureLevelScaling creatureLevelScaling; CreatureLevelScaling creatureLevelScaling = new CreatureLevelScaling();
creatureLevelScaling.MinLevel = result.Read<ushort>(1); creatureLevelScaling.MinLevel = result.Read<ushort>(2);
creatureLevelScaling.MaxLevel = result.Read<ushort>(2); creatureLevelScaling.MaxLevel = result.Read<ushort>(3);
creatureLevelScaling.DeltaLevelMin = result.Read<short>(3); creatureLevelScaling.DeltaLevelMin = result.Read<short>(4);
creatureLevelScaling.DeltaLevelMax = result.Read<short>(3); creatureLevelScaling.DeltaLevelMax = result.Read<short>(5);
template.levelScaling.Set(creatureLevelScaling); creatureLevelScaling.ContentTuningID = result.Read<uint>(6);
template.scalingStorage[difficulty] = creatureLevelScaling;
++count; ++count;
} while (result.NextRow()); } while (result.NextRow());
@@ -3505,6 +3495,8 @@ namespace Game
if (!map) if (!map)
return 0; return 0;
CreatureLevelScaling scaling = cInfo.GetLevelScaling(map.GetDifficultyID());
ulong guid = GenerateCreatureSpawnId(); ulong guid = GenerateCreatureSpawnId();
CreatureData data = NewOrExistCreatureData(guid); CreatureData data = NewOrExistCreatureData(guid);
data.id = entry; data.id = entry;
@@ -3518,7 +3510,7 @@ namespace Game
data.spawntimesecs = spawntimedelay; data.spawntimesecs = spawntimedelay;
data.spawndist = 0; data.spawndist = 0;
data.currentwaypoint = 0; data.currentwaypoint = 0;
data.curhealth = stats.GenerateHealth(cInfo); data.curhealth = (uint)(Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.CreatureHealth, level, cInfo.HealthScalingExpansion, scaling.ContentTuningID, (Class)cInfo.UnitClass) * cInfo.ModHealth * cInfo.ModHealthExtra);
data.curmana = stats.GenerateMana(cInfo); data.curmana = stats.GenerateMana(cInfo);
data.movementType = (byte)cInfo.MovementType; data.movementType = (byte)cInfo.MovementType;
data.spawnDifficulties.Add(Difficulty.None); data.spawnDifficulties.Add(Difficulty.None);
@@ -10710,12 +10702,6 @@ namespace Game
{ {
public DefaultCreatureBaseStats() public DefaultCreatureBaseStats()
{ {
BaseArmor = 1;
for (byte j = 0; j < 4; ++j)
{
BaseHealth[j] = 1;
BaseDamage[j] = 0.0f;
}
BaseMana = 0; BaseMana = 0;
AttackPower = 0; AttackPower = 0;
RangedAttackPower = 0; RangedAttackPower = 0;
+12 -9
View File
@@ -1198,15 +1198,16 @@ namespace Game.Network.Packets
bool GenerateDataCreatureToPlayer(Creature attacker, Player target) bool GenerateDataCreatureToPlayer(Creature attacker, Player target)
{ {
CreatureTemplate creatureTemplate = attacker.GetCreatureTemplate(); CreatureTemplate creatureTemplate = attacker.GetCreatureTemplate();
CreatureLevelScaling creatureScaling = creatureTemplate.GetLevelScaling(attacker.GetMap().GetDifficultyID());
TuningType = ContentTuningType.CreatureToPlayerDamage; TuningType = ContentTuningType.CreatureToPlayerDamage;
PlayerLevelDelta = (short)target.m_activePlayerData.ScalingPlayerLevelDelta; PlayerLevelDelta = (short)target.m_activePlayerData.ScalingPlayerLevelDelta;
PlayerItemLevel = (ushort)target.GetAverageItemLevel(); PlayerItemLevel = (ushort)target.GetAverageItemLevel();
ScalingHealthItemLevelCurveID = (ushort)target.m_unitData.ScalingHealthItemLevelCurveID; ScalingHealthItemLevelCurveID = (ushort)target.m_unitData.ScalingHealthItemLevelCurveID;
TargetLevel = (byte)target.GetLevel(); TargetLevel = (byte)target.GetLevel();
Expansion = (byte)creatureTemplate.RequiredExpansion; Expansion = (byte)creatureTemplate.HealthScalingExpansion;
TargetMinScalingLevel = (byte)creatureTemplate.levelScaling.Value.MinLevel; TargetMinScalingLevel = (byte)creatureScaling.MinLevel;
TargetMaxScalingLevel = (byte)creatureTemplate.levelScaling.Value.MaxLevel; TargetMaxScalingLevel = (byte)creatureScaling.MaxLevel;
TargetScalingLevelDelta = (sbyte)attacker.m_unitData.ScalingLevelDelta; TargetScalingLevelDelta = (sbyte)attacker.m_unitData.ScalingLevelDelta;
return true; return true;
} }
@@ -1214,15 +1215,16 @@ namespace Game.Network.Packets
bool GenerateDataPlayerToCreature(Player attacker, Creature target) bool GenerateDataPlayerToCreature(Player attacker, Creature target)
{ {
CreatureTemplate creatureTemplate = target.GetCreatureTemplate(); CreatureTemplate creatureTemplate = target.GetCreatureTemplate();
CreatureLevelScaling creatureScaling = creatureTemplate.GetLevelScaling(target.GetMap().GetDifficultyID());
TuningType = ContentTuningType.PlayerToCreatureDamage; TuningType = ContentTuningType.PlayerToCreatureDamage;
PlayerLevelDelta = (short)attacker.m_activePlayerData.ScalingPlayerLevelDelta; PlayerLevelDelta = (short)attacker.m_activePlayerData.ScalingPlayerLevelDelta;
PlayerItemLevel = (ushort)attacker.GetAverageItemLevel(); PlayerItemLevel = (ushort)attacker.GetAverageItemLevel();
ScalingHealthItemLevelCurveID = (ushort)target.m_unitData.ScalingHealthItemLevelCurveID; ScalingHealthItemLevelCurveID = (ushort)target.m_unitData.ScalingHealthItemLevelCurveID;
TargetLevel = (byte)target.GetLevel(); TargetLevel = (byte)target.GetLevel();
Expansion = (byte)creatureTemplate.RequiredExpansion; Expansion = (byte)creatureTemplate.HealthScalingExpansion;
TargetMinScalingLevel = (byte)creatureTemplate.levelScaling.Value.MinLevel; TargetMinScalingLevel = (byte)creatureScaling.MinLevel;
TargetMaxScalingLevel = (byte)creatureTemplate.levelScaling.Value.MaxLevel; TargetMaxScalingLevel = (byte)creatureScaling.MaxLevel;
TargetScalingLevelDelta = (sbyte)target.m_unitData.ScalingLevelDelta; TargetScalingLevelDelta = (sbyte)target.m_unitData.ScalingLevelDelta;
return true; return true;
} }
@@ -1231,14 +1233,15 @@ namespace Game.Network.Packets
{ {
Creature accessor = target.HasScalableLevels() ? target : attacker; Creature accessor = target.HasScalableLevels() ? target : attacker;
CreatureTemplate creatureTemplate = accessor.GetCreatureTemplate(); CreatureTemplate creatureTemplate = accessor.GetCreatureTemplate();
CreatureLevelScaling creatureScaling = creatureTemplate.GetLevelScaling(accessor.GetMap().GetDifficultyID());
TuningType = ContentTuningType.CreatureToCreatureDamage; TuningType = ContentTuningType.CreatureToCreatureDamage;
PlayerLevelDelta = 0; PlayerLevelDelta = 0;
PlayerItemLevel = 0; PlayerItemLevel = 0;
TargetLevel = (byte)target.GetLevel(); TargetLevel = (byte)target.GetLevel();
Expansion = (byte)creatureTemplate.RequiredExpansion; Expansion = (byte)creatureTemplate.HealthScalingExpansion;
TargetMinScalingLevel = (byte)creatureTemplate.levelScaling.Value.MinLevel; TargetMinScalingLevel = (byte)creatureScaling.MinLevel;
TargetMaxScalingLevel = (byte)creatureTemplate.levelScaling.Value.MaxLevel; TargetMaxScalingLevel = (byte)creatureScaling.MaxLevel;
TargetScalingLevelDelta = (sbyte)accessor.m_unitData.ScalingLevelDelta; TargetScalingLevelDelta = (sbyte)accessor.m_unitData.ScalingLevelDelta;
return true; return true;
} }
@@ -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`;