Core/Creatures: Compute the level from ContentTuning

Port From (https://github.com/TrinityCore/TrinityCore/commit/562f65f3f8f271fc52cc428c71a562af22829dc0)
This commit is contained in:
hondacrx
2023-04-21 18:49:58 -04:00
parent b7a8a88a76
commit 8828e94482
5 changed files with 87 additions and 114 deletions
@@ -31,6 +31,7 @@ namespace Framework.Constants
public const int MaxAzeriteEssenceSlot = 4;
public const int MaxAzeriteEssenceRank = 4;
public const int AchivementCategoryPetBattles = 15117;
public const int MaxUnitClasses = 4;
/// <summary>
/// BattlePets Const
@@ -61,7 +61,7 @@ namespace Framework.Database
PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?");
PrepareStatement(WorldStatements.DEL_CREATURE, "DELETE FROM creature WHERE guid = ?");
PrepareStatement(WorldStatements.SEL_COMMANDS, "SELECT name, help FROM command");
PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?");
PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?");
PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?");
PrepareStatement(WorldStatements.SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?");
PrepareStatement(WorldStatements.SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_");
+4 -9
View File
@@ -1425,16 +1425,11 @@ namespace Game.Entities
public void SelectLevel()
{
CreatureTemplate cInfo = GetCreatureTemplate();
// level
var minMaxLevels = cInfo.GetMinMaxLevel();
int minlevel = Math.Min(minMaxLevels[0], minMaxLevels[1]);
int maxlevel = Math.Max(minMaxLevels[0], minMaxLevels[1]);
int level = (minlevel == maxlevel ? minlevel : RandomHelper.IRand(minlevel, maxlevel));
SetLevel((uint)level);
// Level
ApplyLevelScaling();
int levelWithDelta = m_unitData.ScalingLevelMax + m_unitData.ScalingLevelDelta;
byte level = (byte)MathFunctions.RoundToInterval(ref levelWithDelta, 1, SharedConst.StrongMaxLevel);
SetLevel(level);
UpdateLevelDependantStats();
}
@@ -22,9 +22,7 @@ namespace Game.Entities
public string TitleAlt;
public string IconName;
public uint GossipMenuId;
public short Minlevel;
public Dictionary<Difficulty, CreatureLevelScaling> scalingStorage = new();
public short Maxlevel;
public int HealthScalingExpansion;
public uint RequiredExpansion;
public uint VignetteID; // @todo Read Vignette.db2
@@ -145,15 +143,6 @@ namespace Game.Entities
return CreatureModel.DefaultVisibleModel;
}
public int[] GetMinMaxLevel()
{
return new[]
{
HealthScalingExpansion != (int)Expansion.LevelCurrent ? Minlevel : Minlevel + SharedConst.MaxLevel,
HealthScalingExpansion != (int)Expansion.LevelCurrent ? Maxlevel : Maxlevel + SharedConst.MaxLevel
};
}
public int GetHealthScalingExpansion()
{
return HealthScalingExpansion == (int)Expansion.LevelCurrent ? (int)Expansion.WarlordsOfDraenor : HealthScalingExpansion;
+81 -93
View File
@@ -1823,35 +1823,33 @@ namespace Game
creature.TitleAlt = fields.Read<string>(9);
creature.IconName = fields.Read<string>(10);
creature.GossipMenuId = fields.Read<uint>(11);
creature.Minlevel = fields.Read<short>(12);
creature.Maxlevel = fields.Read<short>(13);
creature.HealthScalingExpansion = fields.Read<int>(14);
creature.RequiredExpansion = fields.Read<uint>(15);
creature.VignetteID = fields.Read<uint>(16);
creature.Faction = fields.Read<uint>(17);
creature.Npcflag = fields.Read<ulong>(18);
creature.SpeedWalk = fields.Read<float>(19);
creature.SpeedRun = fields.Read<float>(20);
creature.Scale = fields.Read<float>(21);
creature.Rank = (CreatureEliteType)fields.Read<uint>(22);
creature.DmgSchool = fields.Read<uint>(23);
creature.BaseAttackTime = fields.Read<uint>(24);
creature.RangeAttackTime = fields.Read<uint>(25);
creature.BaseVariance = fields.Read<float>(26);
creature.RangeVariance = fields.Read<float>(27);
creature.UnitClass = fields.Read<uint>(28);
creature.UnitFlags = (UnitFlags)fields.Read<uint>(29);
creature.UnitFlags2 = fields.Read<uint>(30);
creature.UnitFlags3 = fields.Read<uint>(31);
creature.DynamicFlags = fields.Read<uint>(32);
creature.Family = (CreatureFamily)fields.Read<uint>(33);
creature.TrainerClass = (Class)fields.Read<byte>(34);
creature.CreatureType = (CreatureType)fields.Read<byte>(35);
creature.TypeFlags = (CreatureTypeFlags)fields.Read<uint>(36);
creature.TypeFlags2 = fields.Read<uint>(37);
creature.LootId = fields.Read<uint>(38);
creature.PickPocketId = fields.Read<uint>(39);
creature.SkinLootId = fields.Read<uint>(40);
creature.HealthScalingExpansion = fields.Read<int>(12);
creature.RequiredExpansion = fields.Read<uint>(13);
creature.VignetteID = fields.Read<uint>(14);
creature.Faction = fields.Read<uint>(15);
creature.Npcflag = fields.Read<ulong>(16);
creature.SpeedWalk = fields.Read<float>(17);
creature.SpeedRun = fields.Read<float>(18);
creature.Scale = fields.Read<float>(19);
creature.Rank = (CreatureEliteType)fields.Read<uint>(20);
creature.DmgSchool = fields.Read<uint>(21);
creature.BaseAttackTime = fields.Read<uint>(22);
creature.RangeAttackTime = fields.Read<uint>(23);
creature.BaseVariance = fields.Read<float>(24);
creature.RangeVariance = fields.Read<float>(25);
creature.UnitClass = fields.Read<uint>(26);
creature.UnitFlags = (UnitFlags)fields.Read<uint>(27);
creature.UnitFlags2 = fields.Read<uint>(28);
creature.UnitFlags3 = fields.Read<uint>(29);
creature.DynamicFlags = fields.Read<uint>(30);
creature.Family = (CreatureFamily)fields.Read<uint>(31);
creature.TrainerClass = (Class)fields.Read<byte>(32);
creature.CreatureType = (CreatureType)fields.Read<byte>(33);
creature.TypeFlags = (CreatureTypeFlags)fields.Read<uint>(34);
creature.TypeFlags2 = fields.Read<uint>(35);
creature.LootId = fields.Read<uint>(36);
creature.PickPocketId = fields.Read<uint>(37);
creature.SkinLootId = fields.Read<uint>(38);
for (var i = (int)SpellSchools.Holy; i < (int)SpellSchools.Max; ++i)
creature.Resistance[i] = 0;
@@ -1859,52 +1857,52 @@ namespace Game
for (var i = 0; i < SharedConst.MaxCreatureSpells; ++i)
creature.Spells[i] = 0;
creature.VehicleId = fields.Read<uint>(41);
creature.MinGold = fields.Read<uint>(42);
creature.MaxGold = fields.Read<uint>(43);
creature.AIName = fields.Read<string>(44);
creature.MovementType = fields.Read<uint>(45);
creature.VehicleId = fields.Read<uint>(39);
creature.MinGold = fields.Read<uint>(40);
creature.MaxGold = fields.Read<uint>(41);
creature.AIName = fields.Read<string>(42);
creature.MovementType = fields.Read<uint>(43);
if (!fields.IsNull(44))
creature.Movement.Ground = (CreatureGroundMovementType)fields.Read<byte>(44);
if (!fields.IsNull(45))
creature.Movement.Swim = fields.Read<bool>(45);
if (!fields.IsNull(46))
creature.Movement.Ground = (CreatureGroundMovementType)fields.Read<byte>(46);
creature.Movement.Flight = (CreatureFlightMovementType)fields.Read<byte>(46);
if (!fields.IsNull(47))
creature.Movement.Swim = fields.Read<bool>(47);
creature.Movement.Rooted = fields.Read<bool>(47);
if (!fields.IsNull(48))
creature.Movement.Flight = (CreatureFlightMovementType)fields.Read<byte>(48);
creature.Movement.Chase = (CreatureChaseMovementType)fields.Read<byte>(48);
if (!fields.IsNull(49))
creature.Movement.Rooted = fields.Read<bool>(49);
creature.Movement.Random = (CreatureRandomMovementType)fields.Read<byte>(49);
if (!fields.IsNull(50))
creature.Movement.Chase = (CreatureChaseMovementType)fields.Read<byte>(50);
creature.Movement.InteractionPauseTimer = fields.Read<uint>(50);
if (!fields.IsNull(51))
creature.Movement.Random = (CreatureRandomMovementType)fields.Read<byte>(51);
if (!fields.IsNull(52))
creature.Movement.InteractionPauseTimer = fields.Read<uint>(52);
creature.HoverHeight = fields.Read<float>(53);
creature.ModHealth = fields.Read<float>(54);
creature.ModHealthExtra = fields.Read<float>(55);
creature.ModMana = fields.Read<float>(56);
creature.ModManaExtra = fields.Read<float>(57);
creature.ModArmor = fields.Read<float>(58);
creature.ModDamage = fields.Read<float>(59);
creature.ModExperience = fields.Read<float>(60);
creature.RacialLeader = fields.Read<bool>(61);
creature.MovementId = fields.Read<uint>(62);
creature.CreatureDifficultyID = fields.Read<int>(63);
creature.WidgetSetID = fields.Read<int>(64);
creature.WidgetSetUnitConditionID = fields.Read<int>(65);
creature.RegenHealth = fields.Read<bool>(66);
creature.MechanicImmuneMask = fields.Read<ulong>(67);
creature.SpellSchoolImmuneMask = fields.Read<uint>(68);
creature.FlagsExtra = (CreatureFlagsExtra)fields.Read<uint>(69);
creature.ScriptID = GetScriptId(fields.Read<string>(70));
creature.StringId = fields.Read<string>(71);
creature.HoverHeight = fields.Read<float>(51);
creature.ModHealth = fields.Read<float>(52);
creature.ModHealthExtra = fields.Read<float>(53);
creature.ModMana = fields.Read<float>(54);
creature.ModManaExtra = fields.Read<float>(55);
creature.ModArmor = fields.Read<float>(56);
creature.ModDamage = fields.Read<float>(57);
creature.ModExperience = fields.Read<float>(58);
creature.RacialLeader = fields.Read<bool>(59);
creature.MovementId = fields.Read<uint>(60);
creature.CreatureDifficultyID = fields.Read<int>(61);
creature.WidgetSetID = fields.Read<int>(62);
creature.WidgetSetUnitConditionID = fields.Read<int>(63);
creature.RegenHealth = fields.Read<bool>(64);
creature.MechanicImmuneMask = fields.Read<ulong>(65);
creature.SpellSchoolImmuneMask = fields.Read<uint>(66);
creature.FlagsExtra = (CreatureFlagsExtra)fields.Read<uint>(67);
creature.ScriptID = GetScriptId(fields.Read<string>(68));
creature.StringId = fields.Read<string>(69);
creatureTemplateStorage[entry] = creature;
}
@@ -2575,12 +2573,13 @@ namespace Game
++count;
} while (result.NextRow());
foreach (var creatureTemplate in creatureTemplateStorage.Values)
for (byte unitLevel = 1; unitLevel <= SharedConst.DefaultMaxLevel + 3; ++unitLevel)
{
for (short lvl = creatureTemplate.Minlevel; lvl <= creatureTemplate.Maxlevel; ++lvl)
for (byte unitClass = 1; unitClass <= SharedConst.MaxUnitClasses; ++unitClass)
{
if (creatureBaseStatsStorage.LookupByKey(MathFunctions.MakePair16((uint)lvl, creatureTemplate.UnitClass)) == null)
Log.outError(LogFilter.Sql, "Missing base stats for creature class {0} level {1}", creatureTemplate.UnitClass, lvl);
uint unitClassMask = 1u << (unitClass - 1);
if (!creatureBaseStatsStorage.ContainsKey(MathFunctions.MakePair16(unitLevel, unitClassMask)))
Log.outError(LogFilter.Sql, $"Missing base stats for creature class {unitClassMask} level {unitLevel}");
}
}
@@ -2683,6 +2682,20 @@ namespace Game
template.scalingStorage[difficulty] = creatureLevelScaling;
// Assign creature level scaling to creature difficulty entry (if any)
// TODO: Drop the use of creature difficulties
int difficultyIndex = CreatureTemplate.DifficultyIDToDifficultyEntryIndex((uint)difficulty);
if (difficultyIndex != -1)
{
uint difficultyEntry = template.DifficultyEntry[difficultyIndex];
if (difficultyEntry != 0)
{
var difficultyTemplate = creatureTemplateStorage.LookupByKey(difficultyEntry);
if (difficultyTemplate != null)
difficultyTemplate.scalingStorage[difficulty] = creatureLevelScaling;
}
}
++count;
} while (result.NextRow());
@@ -2742,18 +2755,6 @@ namespace Game
cInfo.Entry, cInfo.HealthScalingExpansion, diff + 1, cInfo.DifficultyEntry[diff], difficultyInfo.HealthScalingExpansion);
}
if (cInfo.Minlevel > difficultyInfo.Minlevel)
{
Log.outError(LogFilter.Sql, "Creature (Entry: {0}, minlevel: {1}) has lower `minlevel` in difficulty {2} mode (Entry: {3}, minlevel: {4}).",
cInfo.Entry, cInfo.Minlevel, diff + 1, cInfo.DifficultyEntry[diff], difficultyInfo.Minlevel);
}
if (cInfo.Maxlevel > difficultyInfo.Maxlevel)
{
Log.outError(LogFilter.Sql, "Creature (Entry: {0}, maxlevel: {1}) has lower `maxlevel` in difficulty {2} mode (Entry: {3}, maxlevel: {4}).",
cInfo.Entry, cInfo.Maxlevel, diff + 1, cInfo.DifficultyEntry[diff], difficultyInfo.Maxlevel);
}
if (cInfo.Faction != difficultyInfo.Faction)
{
Log.outError(LogFilter.Sql, "Creature (Entry: {0}, faction: {1}) has different `faction` in difficulty {2} mode (Entry: {3}, faction: {4}).",
@@ -3001,19 +3002,6 @@ namespace Game
cInfo.DynamicFlags = 0;
}
var levels = cInfo.GetMinMaxLevel();
if (levels[0] < 1 || levels[0] > SharedConst.StrongMaxLevel)
{
Log.outError(LogFilter.Sql, $"Creature (ID: {cInfo.Entry}): Calculated minLevel {cInfo.Minlevel} is not within [1, 255], value has been set to {(cInfo.HealthScalingExpansion == (int)Expansion.LevelCurrent ? SharedConst.MaxLevel : 1)}.");
cInfo.Minlevel = (short)(cInfo.HealthScalingExpansion == (int)Expansion.LevelCurrent ? 0 : 1);
}
if (levels[1] < 1 || levels[1] > SharedConst.StrongMaxLevel)
{
Log.outError(LogFilter.Sql, $"Creature (ID: {cInfo.Entry}): Calculated maxLevel {cInfo.Maxlevel} is not within [1, 255], value has been set to {(cInfo.HealthScalingExpansion == (int)Expansion.LevelCurrent ? SharedConst.MaxLevel : 1)}.");
cInfo.Maxlevel = (short)(cInfo.HealthScalingExpansion == (int)Expansion.LevelCurrent ? 0 : 1);
}
cInfo.ModDamage *= Creature._GetDamageMod(cInfo.Rank);
if (cInfo.GossipMenuId != 0 && !cInfo.Npcflag.HasAnyFlag((ulong)NPCFlags.Gossip))