diff --git a/sql/updates/world/4.3.4/2025_08_03_01_world.sql b/sql/updates/world/4.3.4/2025_08_03_01_world.sql new file mode 100644 index 0000000000..db5b353ae8 --- /dev/null +++ b/sql/updates/world/4.3.4/2025_08_03_01_world.sql @@ -0,0 +1,5 @@ +ALTER TABLE `creature_template_movement` + ADD COLUMN `GravityInitiallyDisabled` TINYINT(1) NULL DEFAULT NULL AFTER `HoverInitiallyEnabled`; + +ALTER TABLE `creature_movement_override` + ADD COLUMN `GravityInitiallyDisabled` TINYINT(1) NULL DEFAULT NULL AFTER `HoverInitiallyEnabled`; diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 660fff047f..74172dfebb 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -76,7 +76,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.GravityInitiallyDisabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_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_", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index eb343c44bc..bac27977e0 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -62,7 +62,8 @@ VendorItemCount::VendorItemCount(uint32 _item, uint32 _count) : itemId(_item), count(_count), lastIncrementTime(GameTime::GetGameTime()) { } -CreatureMovementData::CreatureMovementData() : HoverInitiallyEnabled(false), Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { } +CreatureMovementData::CreatureMovementData() : HoverInitiallyEnabled(false), GravityInitiallyDisabled(false), + Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { } std::string CreatureMovementData::ToString() const @@ -72,7 +73,8 @@ std::string CreatureMovementData::ToString() const std::ostringstream str; str << std::boolalpha << ", HoverInitiallyEnabled: " << HoverInitiallyEnabled - << "Random: " << RandomStates[AsUnderlyingType(Random)]; + << ", GravityInitiallyDisabled: " << GravityInitiallyDisabled + << ", Random: " << RandomStates[AsUnderlyingType(Random)]; str << ", InteractionPauseTimer: " << InteractionPauseTimer; @@ -2667,7 +2669,8 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa void Creature::InitializeMovementCapabilities() { SetHover(GetMovementTemplate().IsHoverInitiallyEnabled()); - SetDisableGravity(IsFloating()); + SetDisableGravity(IsFloating() || GetMovementTemplate().IsGravityInitiallyDisabled()); + SetPlayHoverAnim(IsFloating()); SetControlled(IsSessile(), UNIT_STATE_ROOT); if (IsSwimPrevented()) diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index f8192d6c12..334fcb91c4 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -317,12 +317,14 @@ struct TC_GAME_API CreatureMovementData CreatureMovementData(); bool HoverInitiallyEnabled; + bool GravityInitiallyDisabled; CreatureRandomMovementType Random; uint32 InteractionPauseTimer; CreatureRandomMovementType GetRandom() const { return Random; } bool IsHoverInitiallyEnabled() const { return HoverInitiallyEnabled; } + bool IsGravityInitiallyDisabled() const { return GravityInitiallyDisabled; } uint32 GetInteractionPauseTimer() const { return InteractionPauseTimer; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 9ad720d552..b67ba5011e 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -422,11 +422,11 @@ void ObjectMgr::LoadCreatureTemplates() "family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, " // 47 48 49 50 51 52 53 54 55 56 57 58 59 60 "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " - // 61 62 63 64 65 66 67 68 - "ctm.HoverInitiallyEnabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, " - // 69 70 71 72 73 74 75 76 + // 61 62 63 64 65 66 67 68 69 + "ctm.HoverInitiallyEnabled, ctm.GravityInitiallyDisabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, " + // 70 71 72 73 74 75 76 77 "ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, " - // 77 78 79 80 81 82 83 + // 78 79 80 81 82 83 84 "flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId"); if (!result) @@ -519,29 +519,32 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.Movement.HoverInitiallyEnabled = fields[61].GetBool(); if (!fields[62].IsNull()) - creatureTemplate.Movement.Random = static_cast(fields[62].GetUInt8()); + creatureTemplate.Movement.GravityInitiallyDisabled = fields[62].GetBool(); if (!fields[63].IsNull()) - creatureTemplate.Movement.InteractionPauseTimer = fields[63].GetUInt32(); + creatureTemplate.Movement.Random = static_cast(fields[63].GetUInt8()); - creatureTemplate.HoverHeight = fields[64].GetFloat(); - creatureTemplate.ModHealth = fields[65].GetFloat(); - creatureTemplate.ModHealthExtra = fields[66].GetFloat(); - creatureTemplate.ModMana = fields[67].GetFloat(); - creatureTemplate.ModManaExtra = fields[68].GetFloat(); - creatureTemplate.ModArmor = fields[69].GetFloat(); - creatureTemplate.ModDamage = fields[70].GetFloat(); - creatureTemplate.ModExperience = fields[71].GetFloat(); + if (!fields[64].IsNull()) + creatureTemplate.Movement.InteractionPauseTimer = fields[64].GetUInt32(); - creatureTemplate.RacialLeader = fields[72].GetBool(); - creatureTemplate.movementId = fields[73].GetUInt32(); - creatureTemplate.RegenHealth = fields[74].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[75].GetUInt32(); - creatureTemplate.SpellSchoolImmuneMask = fields[76].GetUInt32(); - creatureTemplate.flags_extra = fields[77].GetUInt32(); - creatureTemplate.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[78].GetUInt32()), CreatureStaticFlags2(fields[79].GetUInt32()), - CreatureStaticFlags3(fields[80].GetUInt32()), CreatureStaticFlags4(fields[81].GetUInt32()), CreatureStaticFlags5(fields[82].GetUInt32())); - creatureTemplate.ScriptID = GetScriptId(fields[83].GetCString()); + creatureTemplate.HoverHeight = fields[65].GetFloat(); + creatureTemplate.ModHealth = fields[66].GetFloat(); + creatureTemplate.ModHealthExtra = fields[67].GetFloat(); + creatureTemplate.ModMana = fields[68].GetFloat(); + creatureTemplate.ModManaExtra = fields[69].GetFloat(); + creatureTemplate.ModArmor = fields[70].GetFloat(); + creatureTemplate.ModDamage = fields[71].GetFloat(); + creatureTemplate.ModExperience = fields[72].GetFloat(); + + creatureTemplate.RacialLeader = fields[73].GetBool(); + creatureTemplate.movementId = fields[74].GetUInt32(); + creatureTemplate.RegenHealth = fields[75].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32(); + creatureTemplate.SpellSchoolImmuneMask = fields[77].GetUInt32(); + creatureTemplate.flags_extra = fields[78].GetUInt32(); + creatureTemplate.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[79].GetUInt32()), CreatureStaticFlags2(fields[80].GetUInt32()), + CreatureStaticFlags3(fields[81].GetUInt32()), CreatureStaticFlags4(fields[82].GetUInt32()), CreatureStaticFlags5(fields[83].GetUInt32())); + creatureTemplate.ScriptID = GetScriptId(fields[84].GetCString()); } void ObjectMgr::LoadCreatureTemplateModels() @@ -1508,6 +1511,7 @@ void ObjectMgr::LoadCreatureMovementOverrides() QueryResult result = WorldDatabase.Query( "SELECT cmo.SpawnId," "COALESCE(cmo.HoverInitiallyEnabled, ctm.HoverInitiallyEnabled)," + "COALESCE(cmo.GravityInitiallyDisabled, ctm.GravityInitiallyDisabled)," "COALESCE(cmo.Random, ctm.Random)," "COALESCE(cmo.InteractionPauseTimer, ctm.InteractionPauseTimer) " "FROM creature_movement_override AS cmo " @@ -1534,8 +1538,10 @@ void ObjectMgr::LoadCreatureMovementOverrides() if (!fields[1].IsNull()) movement.HoverInitiallyEnabled = fields[1].GetBool(); if (!fields[2].IsNull()) - movement.Random = static_cast(fields[3].GetUInt8()); + movement.HoverInitiallyEnabled = fields[2].GetBool(); if (!fields[3].IsNull()) + movement.Random = static_cast(fields[3].GetUInt8()); + if (!fields[4].IsNull()) movement.InteractionPauseTimer = fields[4].GetUInt32(); CheckCreatureMovement("creature_movement_override", spawnId, movement);