diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index 222af0166..46976bc6f 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -225,6 +225,7 @@ namespace Framework.Constants public const float AttackDistance = 5.0f; public const float DefaultPlayerCombatReach = 1.5f; public const float DefaultPlayerDisplayScale = 1.0f; + public const float DefaultPlayerHoverHeight = 1.0f; public const float MinMeleeReach = 2.0f; public const float NominalMeleeRange = 5.0f; public const float MeleeRange = NominalMeleeRange - MinMeleeReach * 2; //center to center for players diff --git a/Source/Framework/Database/Databases/WorldDatabase.cs b/Source/Framework/Database/Databases/WorldDatabase.cs index 0e6af53f4..28232a6a5 100644 --- a/Source/Framework/Database/Databases/WorldDatabase.cs +++ b/Source/Framework/Database/Databases/WorldDatabase.cs @@ -60,7 +60,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, 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, 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, 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_"); diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 69c2478e7..6d914491f 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -293,8 +293,6 @@ namespace Game.Entities SetObjectScale(GetNativeObjectScale()); - SetHoverHeight(cInfo.HoverHeight); - SetCanDualWield(cInfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.UseOffhandAttack)); // checked at loading diff --git a/Source/Game/Entities/Creature/CreatureData.cs b/Source/Game/Entities/Creature/CreatureData.cs index ae1409654..77b212dfd 100644 --- a/Source/Game/Entities/Creature/CreatureData.cs +++ b/Source/Game/Entities/Creature/CreatureData.cs @@ -58,7 +58,6 @@ namespace Game.Entities public string AIName; public uint MovementType; public CreatureMovementData Movement = new(); - public float HoverHeight; public float ModHealth; public float ModHealthExtra; public float ModMana; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index b59eafc38..9c743ed40 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -2918,7 +2918,6 @@ namespace Game.Entities } SetObjectScale(1.0f); - SetHoverHeight(1.0f); // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria) m_achievementSys.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Achievements), holder.GetResult(PlayerLoginQueryLoad.CriteriaProgress)); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index aa1d52cee..cb337b1f4 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -228,7 +228,6 @@ namespace Game.Entities } SetUnitFlag2(UnitFlags2.RegeneratePower); - SetHoverHeight(1.0f); // default for players in 3.0.3 SetWatchedFactionIndex(0xFFFFFFFF); diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 814c0e27e..f48bb8e6c 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -1410,6 +1410,8 @@ namespace Game.Entities SetUnitFlag(UnitFlags.Mount); + CalculateHoverHeight(); + Player player = ToPlayer(); if (player != null) { @@ -1461,6 +1463,8 @@ namespace Game.Entities if (thisPlayer != null) thisPlayer.SendMovementSetCollisionHeight(thisPlayer.GetCollisionHeight(), UpdateCollisionHeightReason.Mount); + CalculateHoverHeight(); + // dismount as a vehicle if (IsTypeId(TypeId.Player) && GetVehicleKit() != null) { diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 3df7b8634..36d6a3b3c 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1894,10 +1894,12 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.NativeXDisplayScale), displayScale); } - // Set Gender by modelId + // Set Gender by ModelInfo CreatureModelInfo modelInfo = Global.ObjectMgr.GetCreatureModelInfo(displayId); if (modelInfo != null) SetGender((Gender)modelInfo.gender); + + CalculateHoverHeight(); } public void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting = false) @@ -1973,6 +1975,32 @@ namespace Game.Entities uint GetCosmeticMountDisplayId() { return m_unitData.CosmeticMountDisplayID; } public void SetCosmeticMountDisplayId(uint mountDisplayId) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.CosmeticMountDisplayID), mountDisplayId); } + void CalculateHoverHeight() + { + float hoverHeight = SharedConst.DefaultPlayerHoverHeight; + float displayScale = SharedConst.DefaultPlayerDisplayScale; + + uint displayId = IsMounted() ? GetMountDisplayId() : GetDisplayId(); + + // Get DisplayScale for creatures + if (IsCreature()) + { + CreatureModel model = ToCreature().GetCreatureTemplate().GetModelWithDisplayId(displayId); + if (model != null) + displayScale = model.DisplayScale; + } + + var displayInfo = CliDB.CreatureDisplayInfoStorage.LookupByKey(displayId); + if (displayInfo != null) + { + var modelData = CliDB.CreatureModelDataStorage.LookupByKey(displayInfo.ModelID); + if (modelData != null) + hoverHeight = modelData.HoverHeight * modelData.ModelScale * displayInfo.CreatureModelScale * displayScale; + } + + SetHoverHeight(hoverHeight != 0 ? hoverHeight : SharedConst.DefaultPlayerHoverHeight); + } + public virtual float GetFollowAngle() { return MathFunctions.PiOver2; } public override ObjectGuid GetOwnerGUID() { return m_unitData.SummonedBy; } diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 9be54d7b8..d1ca009ca 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -1883,25 +1883,24 @@ namespace Game if (!fields.IsNull(49)) creature.Movement.InteractionPauseTimer = fields.Read(49); - creature.HoverHeight = fields.Read(50); - creature.ModHealth = fields.Read(51); - creature.ModHealthExtra = fields.Read(52); - creature.ModMana = fields.Read(53); - creature.ModManaExtra = fields.Read(54); - creature.ModArmor = fields.Read(55); - creature.ModDamage = fields.Read(56); - creature.ModExperience = fields.Read(57); - creature.RacialLeader = fields.Read(58); - creature.MovementId = fields.Read(59); - creature.CreatureDifficultyID = fields.Read(60); - creature.WidgetSetID = fields.Read(61); - creature.WidgetSetUnitConditionID = fields.Read(62); - creature.RegenHealth = fields.Read(63); - creature.MechanicImmuneMask = fields.Read(64); - creature.SpellSchoolImmuneMask = fields.Read(65); - creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(66); - creature.ScriptID = GetScriptId(fields.Read(67)); - creature.StringId = fields.Read(68); + creature.ModHealth = fields.Read(50); + creature.ModHealthExtra = fields.Read(51); + creature.ModMana = fields.Read(52); + creature.ModManaExtra = fields.Read(53); + creature.ModArmor = fields.Read(54); + creature.ModDamage = fields.Read(55); + creature.ModExperience = fields.Read(56); + creature.RacialLeader = fields.Read(57); + creature.MovementId = fields.Read(58); + creature.CreatureDifficultyID = fields.Read(59); + creature.WidgetSetID = fields.Read(60); + creature.WidgetSetUnitConditionID = fields.Read(61); + creature.RegenHealth = fields.Read(62); + creature.MechanicImmuneMask = fields.Read(63); + creature.SpellSchoolImmuneMask = fields.Read(64); + creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(65); + creature.ScriptID = GetScriptId(fields.Read(66)); + creature.StringId = fields.Read(67); creatureTemplateStorage[entry] = creature; } @@ -3005,12 +3004,6 @@ namespace Game CheckCreatureMovement("creature_template_movement", cInfo.Entry, cInfo.Movement); - if (cInfo.HoverHeight < 0.0f) - { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has wrong value ({1}) in `HoverHeight`", cInfo.Entry, cInfo.HoverHeight); - cInfo.HoverHeight = 1.0f; - } - if (cInfo.VehicleId != 0) { if (!CliDB.VehicleStorage.ContainsKey(cInfo.VehicleId))