diff options
author | Ovahlord <dreadkiller@gmx.de> | 2024-02-29 14:43:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-29 14:43:37 +0100 |
commit | c541eda54d7e0dddeec329a6beac2948e0b0a40b (patch) | |
tree | 90bead53d03937a1c55f4c12cd7f370a8ca13d8d /src | |
parent | 792a4d6c8bab4a8e874c6f0e583f915d05b8d8b3 (diff) |
Core/Creatures: implemented most movement related static flags and migrated existing movement data into static flags (#29541)
* implemented CREATURE_STATIC_FLAG_AQUATIC - creatures cannot leave liquids
* implemented CREATURE_STATIC_FLAG_AMPHIBIOUS - creatures can enter and leave liquids but remain on the ocean floor when swimming is not enabled until engaged
* implemented CREATURE_STATIC_FLAG_FLOATING - creatures have their gravity on spawn / reset disabled
* implemented CREATURE_STATIC_FLAG_SESSILE - creatures are rooted in place
* implemented CREATURE_STATIC_FLAG_CAN_SWIM - creature can swim in liquids
* implemented CREATURE_STATIC_FLAG_3_CANNOT_SWIM - Amphibious creatures cannot toggle on swimming
* implemented CREATURE_STATIC_FLAG_3_CANNOT_TURN - Creatures cannot turn at all
* implemented CREATURE_STATIC_FLAG_4_PREVENT_SWIM - Amphibious creatures won't toggle on swimming until their victim starts leaving the ocean floor
* partially implemented CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER
* deprecated CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE as this flag was a hackfix to a wrong implementation that is now gone
Diffstat (limited to 'src')
17 files changed, 143 insertions, 241 deletions
diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 63d4c4cc872..2438bc1c1e1 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -62,7 +62,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_CREATURE_ADDON_BY_GUID, "SELECT guid FROM creature_addon WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, Classification, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, family, trainer_class, type, VehicleId, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, ExperienceModifier, RacialLeader, movementId, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, CreatureImmunitiesId, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, Classification, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, family, trainer_class, type, VehicleId, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, ExperienceModifier, RacialLeader, movementId, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, CreatureImmunitiesId, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?", 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); PrepareStatement(WORLD_SEL_CREATURE_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 creature 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 1b31295f5e8..79455004e33 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -55,25 +55,19 @@ #include <G3D/g3dmath.h> #include <sstream> -CreatureMovementData::CreatureMovementData() : Ground(CreatureGroundMovementType::Run), Flight(CreatureFlightMovementType::None), Swim(true), Rooted(false), Chase(CreatureChaseMovementType::Run), +CreatureMovementData::CreatureMovementData() : HoverInitiallyEnabled(false), Chase(CreatureChaseMovementType::Run), Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { } std::string CreatureMovementData::ToString() const { - char const* const GroundStates[] = { "None", "Run", "Hover" }; - char const* const FlightStates[] = { "None", "DisableGravity", "CanFly" }; - char const* const ChaseStates[] = { "Run", "CanWalk", "AlwaysWalk" }; + char const* const ChaseStates[] = { "Run", "CanWalk", "AlwaysWalk" }; char const* const RandomStates[] = { "Walk", "CanRun", "AlwaysRun" }; std::ostringstream str; str << std::boolalpha - << "Ground: " << GroundStates[AsUnderlyingType(Ground)] - << ", Swim: " << Swim - << ", Flight: " << FlightStates[AsUnderlyingType(Flight)] + << ", HoverInitiallyEnabled: " << HoverInitiallyEnabled << ", Chase: " << ChaseStates[AsUnderlyingType(Chase)] << ", Random: " << RandomStates[AsUnderlyingType(Random)]; - if (Rooted) - str << ", Rooted"; str << ", InteractionPauseTimer: " << InteractionPauseTimer; return str.str(); @@ -314,7 +308,7 @@ Creature::Creature(bool isWorldObject) : Unit(isWorldObject), MapObject(), m_Pla m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(UI64LIT(0)), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_creatureDifficulty(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), - _regenerateHealth(true), _isMissingCanSwimFlagOutOfCombat(false), _creatureImmunitiesId(0), _gossipMenuId(0), _sparringHealthPct(0) + _regenerateHealth(true), _creatureImmunitiesId(0), _gossipMenuId(0), _sparringHealthPct(0) { m_regenTimer = CREATURE_REGEN_INTERVAL; @@ -595,7 +589,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, uint64 npcFlags; uint32 unitFlags, unitFlags2, unitFlags3; - ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, data); + ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, _staticFlags, data); if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) npcFlags |= sGameEventMgr->GetNPCFlag(this); @@ -686,7 +680,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, SetIsCombatDisallowed((cInfo->flags_extra & CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT) != 0); - InitializeMovementFlags(); + InitializeMovementCapabilities(); LoadCreaturesAddon(); LoadCreaturesSparringHealth(); @@ -707,7 +701,6 @@ void Creature::ApplyAllStaticFlags(CreatureStaticFlagsHolder const& flags) _staticFlags = flags; // Apply all other side effects of flag changes - SetTemplateRooted(flags.HasFlag(CREATURE_STATIC_FLAG_SESSILE)); m_updateFlag.NoBirthAnim = flags.HasFlag(CREATURE_STATIC_FLAG_4_NO_BIRTH_ANIM); } @@ -724,7 +717,7 @@ void Creature::Update(uint32 diff) AI()->JustAppeared(); } - UpdateMovementFlags(); + UpdateMovementCapabilities(); switch (m_deathState) { @@ -1993,17 +1986,6 @@ void Creature::SetSpawnHealth() SetHealth((m_deathState == ALIVE || m_deathState == JUST_RESPAWNED) ? curhealth : 0); } -void Creature::LoadTemplateRoot() -{ - SetTemplateRooted(GetMovementTemplate().IsRooted()); -} - -void Creature::SetTemplateRooted(bool rooted) -{ - _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_SESSILE, rooted); - SetControlled(rooted, UNIT_STATE_ROOT); -} - bool Creature::hasQuest(uint32 quest_id) const { return sObjectMgr->GetCreatureQuestRelations(GetEntry()).HasQuest(quest_id); @@ -2253,7 +2235,7 @@ void Creature::setDeathState(DeathState s) if (m_formation && m_formation->GetLeader() == this) m_formation->FormationReset(true); - bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater(); + bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater() && !HasUnitState(UNIT_STATE_ROOT); SetHover(false, false); SetDisableGravity(false, false); @@ -2273,7 +2255,7 @@ void Creature::setDeathState(DeathState s) ResetPlayerDamageReq(); SetCannotReachTarget(false); - UpdateMovementFlags(); + UpdateMovementCapabilities(); ClearUnitState(UNIT_STATE_ALL_ERASABLE); @@ -2284,7 +2266,7 @@ void Creature::setDeathState(DeathState s) uint64 npcFlags; uint32 unitFlags, unitFlags2, unitFlags3; - ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, creatureData); + ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, _staticFlags, creatureData); if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) npcFlags |= sGameEventMgr->GetNPCFlag(this); @@ -2736,7 +2718,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const dist += GetCombatReach() + victim->GetCombatReach(); // to prevent creatures in air ignore attacks because distance is already too high... - if (GetMovementTemplate().IsFlightAllowed()) + if (CanFly()) return victim->IsInDist2d(&m_homePosition, dist); else return victim->IsInDist(&m_homePosition, dist); @@ -2768,14 +2750,6 @@ bool Creature::LoadCreaturesAddon() ReplaceAllVisFlags(UnitVisFlags(creatureAddon->visFlags)); SetAnimTier(AnimTier(creatureAddon->animTier), false); - //! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2: - //! If no inhabittype_fly (if no MovementFlag_DisableGravity or MovementFlag_CanFly flag found in sniffs) - //! Check using InhabitType as movement flags are assigned dynamically - //! basing on whether the creature is in air or not - //! Set MovementFlag_Hover. Otherwise do nothing. - if (CanHover()) - AddUnitMovementFlag(MOVEMENTFLAG_HOVER); - SetSheath(SheathState(creatureAddon->sheathState)); ReplaceAllPvpFlags(UnitPVPStateFlags(creatureAddon->pvpFlags)); @@ -2920,51 +2894,37 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa } } -void Creature::InitializeMovementFlags() +void Creature::InitializeMovementCapabilities() { - LoadTemplateRoot(); - // It does the same, for now - UpdateMovementFlags(); + SetHover(GetMovementTemplate().IsHoverInitiallyEnabled()); + SetDisableGravity(IsFloating()); + SetControlled(IsSessile(), UNIT_STATE_ROOT); + + // If an amphibious creatures was swimming while engaged, disable swimming again + if (IsAmphibious() && !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_CAN_SWIM)) + RemoveUnitFlag(UNIT_FLAG_CAN_SWIM); + + UpdateMovementCapabilities(); } -void Creature::UpdateMovementFlags() +void Creature::UpdateMovementCapabilities() { // Do not update movement flags if creature is controlled by a player (charm/vehicle) if (m_playerMovingMe) return; - // Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts - if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE) - return; - // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc) float ground = GetFloorZ(); - - bool canHover = CanHover(); - bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + (canHover ? *m_unitData->HoverHeight : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling - - if (GetMovementTemplate().IsFlightAllowed() && (isInAir || !GetMovementTemplate().IsGroundAllowed()) && !IsFalling()) - { - if (GetMovementTemplate().Flight == CreatureFlightMovementType::CanFly) - SetCanFly(true); - else - SetDisableGravity(true); - - if (!HasAuraType(SPELL_AURA_HOVER) && GetMovementTemplate().Ground != CreatureGroundMovementType::Hover) - SetHover(false); - } - else - { - SetCanFly(false); - SetDisableGravity(false); - if (IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER))) - SetHover(true); - } - + bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + GetHoverOffset() + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling if (!isInAir) RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); - SetSwim(CanSwim() && IsInWater()); + // Some Amphibious creatures toggle swimming while engaged + if (IsAmphibious() && !HasUnitFlag(UNIT_FLAG_CANT_SWIM) && !HasUnitFlag(UNIT_FLAG_CAN_SWIM)) + if (!IsSwimPrevented() || (GetVictim() && !GetVictim()->IsOnOceanFloor())) + SetUnitFlag(UNIT_FLAG_CAN_SWIM); + + SetSwim(IsInWater() && CanSwim()); } CreatureMovementData const& Creature::GetMovementTemplate() const @@ -2986,25 +2946,6 @@ bool Creature::CanSwim() const return false; } -bool Creature::CanEnterWater() const -{ - if (CanSwim()) - return true; - - return GetMovementTemplate().IsSwimAllowed(); -} - -void Creature::RefreshCanSwimFlag(bool recheck) -{ - if (!_isMissingCanSwimFlagOutOfCombat || recheck) - _isMissingCanSwimFlagOutOfCombat = !HasUnitFlag(UNIT_FLAG_CAN_SWIM); - - // Check if the creature has UNIT_FLAG_CAN_SWIM and add it if it's missing - // Creatures must be able to chase a target in water if they can enter water - if (_isMissingCanSwimFlagOutOfCombat && CanEnterWater()) - SetUnitFlag(UNIT_FLAG_CAN_SWIM); -} - void Creature::AllLootRemovedFromCorpse() { time_t now = GameTime::GetGameTime(); @@ -3633,8 +3574,6 @@ void Creature::AtEngage(Unit* target) if (!HasFlag(CREATURE_STATIC_FLAG_2_ALLOW_MOUNTED_COMBAT)) Dismount(); - RefreshCanSwimFlag(); - if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed { UpdateSpeed(MOVE_RUN); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index c2d0eda0dfe..156ead57fa6 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -94,9 +94,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void SelectWildBattlePetLevel(); void LoadEquipment(int8 id = 1, bool force = false); void SetSpawnHealth(); - void LoadTemplateRoot(); - bool IsTemplateRooted() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_SESSILE); } - void SetTemplateRooted(bool rooted); ObjectGuid::LowType GetSpawnId() const { return m_spawnId; } @@ -116,15 +113,29 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma bool IsTrigger() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) != 0; } bool IsGuard() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GUARD) != 0; } - void InitializeMovementFlags(); - void UpdateMovementFlags(); + void InitializeMovementCapabilities(); + void UpdateMovementCapabilities(); CreatureMovementData const& GetMovementTemplate() const; - bool CanWalk() const { return GetMovementTemplate().IsGroundAllowed(); } + + // Returns true if CREATURE_STATIC_FLAG_AQUATIC is set which strictly binds the creature to liquids + bool IsAquatic() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AQUATIC); } + // Returns true if CREATURE_STATIC_FLAG_AMPHIBIOUS is set which allows a creature to enter and leave liquids while sticking to the ocean floor. These creatures will become able to swim when engaged + bool IsAmphibious() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AMPHIBIOUS); } + // Returns true if CREATURE_STATIC_FLAG_FLOATING is set which is disabling the gravity of the creature on spawn and reset + bool IsFloating() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_FLOATING); } + // Returns true if CREATURE_STATIC_FLAG_SESSILE is set which permanently roots the creature in place + bool IsSessile() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_SESSILE); } + // Returns true if CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER is set which does not allow the creature to go below liquid surfaces + bool CannotPenetrateWater() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER); } + // Returns true if CREATURE_STATIC_FLAG_3_CANNOT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged + bool IsSwimDisabled() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM); } + // Returns true if CREATURE_STATIC_FLAG_4_PREVENT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged until the victim is no longer on the ocean floor + bool IsSwimPrevented() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_PREVENT_SWIM); } + bool CanSwim() const override; - bool CanEnterWater() const override; - bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); } - bool CanHover() const { return GetMovementTemplate().Ground == CreatureGroundMovementType::Hover || IsHovering(); } + bool CanEnterWater() const override { return (CanSwim() || IsAmphibious()); }; + bool CanFly() const override { return (IsFlying() || HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)); } MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; } void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } @@ -415,12 +426,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma uint32 CalculateDamageForSparring(Unit* attacker, uint32 damage); bool ShouldFakeDamageFrom(Unit* attacker); - bool HasCanSwimFlagOutOfCombat() const - { - return !_isMissingCanSwimFlagOutOfCombat; - } - void RefreshCanSwimFlag(bool recheck = false); - std::string GetDebugInfo() const override; void ExitVehicle(Position const* exitPosition = nullptr) override; @@ -535,8 +540,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma // Regenerate health bool _regenerateHealth; // Set on creation - bool _isMissingCanSwimFlagOutOfCombat; - Optional<uint32> _defaultMountDisplayIdOverride; int32 _creatureImmunitiesId; uint32 _gossipMenuId; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 8a3d8655069..79cdc6bdb8d 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -43,7 +43,7 @@ enum CreatureStaticFlags CREATURE_STATIC_FLAG_IMMUNE_TO_PC = 0x00000020, // UNIT_FLAG_IMMUNE_TO_PC CREATURE_STATIC_FLAG_IMMUNE_TO_NPC = 0x00000040, // UNIT_FLAG_IMMUNE_TO_NPC CREATURE_STATIC_FLAG_CAN_WIELD_LOOT = 0x00000080, - CREATURE_STATIC_FLAG_SESSILE = 0x00000100, // creature_template_movement.Rooted = 1 + CREATURE_STATIC_FLAG_SESSILE = 0x00000100, // Rooted movementflag, creature is permanently rooted in place CREATURE_STATIC_FLAG_UNINTERACTIBLE = 0x00000200, // UNIT_FLAG_UNINTERACTIBLE CREATURE_STATIC_FLAG_NO_AUTOMATIC_REGEN = 0x00000400, // Creatures with that flag uses no UNIT_FLAG2_REGENERATE_POWER CREATURE_STATIC_FLAG_DESPAWN_INSTANTLY = 0x00000800, // Creature instantly disappear when killed @@ -54,7 +54,7 @@ enum CreatureStaticFlags CREATURE_STATIC_FLAG_BOSS_MOB = 0x00010000, // CREATURE_TYPE_FLAG_BOSS_MOB, original description: Raid Boss Mob CREATURE_STATIC_FLAG_COMBAT_PING = 0x00020000, CREATURE_STATIC_FLAG_AQUATIC = 0x00040000, // aka Water Only, creature_template_movement.Ground = 0 - CREATURE_STATIC_FLAG_AMPHIBIOUS = 0x00080000, // creature_template_movement.Swim = 1 + CREATURE_STATIC_FLAG_AMPHIBIOUS = 0x00080000, // Creatures will be able to enter and leave water but can only move on the ocean floor when CREATURE_STATIC_FLAG_CAN_SWIM is not present CREATURE_STATIC_FLAG_NO_MELEE_FLEE = 0x00100000, // "No Melee (Flee)" Prevents melee (moves as-if feared, does not make creature passive) CREATURE_STATIC_FLAG_VISIBLE_TO_GHOSTS = 0x00200000, // CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS CREATURE_STATIC_FLAG_PVP_ENABLING = 0x00400000, // Old UNIT_FLAG_PVP_ENABLING, now UNIT_BYTES_2_OFFSET_PVP_FLAG from UNIT_FIELD_BYTES_2 @@ -64,7 +64,7 @@ enum CreatureStaticFlags CREATURE_STATIC_FLAG_ONLY_ATTACK_PVP_ENABLING = 0x04000000, // "Only attack targets that are PvP enabling" CREATURE_STATIC_FLAG_CALLS_GUARDS = 0x08000000, // Creature will summon a guard if player is within its aggro range (even if creature doesn't attack per se) CREATURE_STATIC_FLAG_CAN_SWIM = 0x10000000, // UnitFlags 0x8000 UNIT_FLAG_CAN_SWIM - CREATURE_STATIC_FLAG_FLOATING = 0x20000000, // creature_template_movement.Flight = 1 + CREATURE_STATIC_FLAG_FLOATING = 0x20000000, // sets DisableGravity movementflag on spawn/reset CREATURE_STATIC_FLAG_MORE_AUDIBLE = 0x40000000, // CREATURE_TYPE_FLAG_MORE_AUDIBLE CREATURE_STATIC_FLAG_LARGE_AOI = 0x80000000 // UnitFlags2 0x200000 }; @@ -340,7 +340,7 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_NO_XP = 0x00000040, // creature kill does not provide XP CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects - CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags + CREATURE_FLAG_EXTRA_UNUSED_9 = 0x00000200, CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x00000800, // creature will use offhand attacks CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor @@ -372,24 +372,6 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP }; -enum class CreatureGroundMovementType : uint8 -{ - None, - Run, - Hover, - - Max -}; - -enum class CreatureFlightMovementType : uint8 -{ - None, - DisableGravity, - CanFly, - - Max -}; - enum class CreatureChaseMovementType : uint8 { Run, @@ -412,22 +394,16 @@ struct TC_GAME_API CreatureMovementData { CreatureMovementData(); - CreatureGroundMovementType Ground; - CreatureFlightMovementType Flight; - bool Swim; - bool Rooted; + bool HoverInitiallyEnabled; CreatureChaseMovementType Chase; CreatureRandomMovementType Random; uint32 InteractionPauseTimer; - bool IsGroundAllowed() const { return Ground != CreatureGroundMovementType::None; } - bool IsSwimAllowed() const { return Swim; } - bool IsFlightAllowed() const { return Flight != CreatureFlightMovementType::None; } - bool IsRooted() const { return Rooted; } - CreatureChaseMovementType GetChase() const { return Chase; } CreatureRandomMovementType GetRandom() const { return Random; } + bool IsHoverInitiallyEnabled() const { return HoverInitiallyEnabled; } + uint32 GetInteractionPauseTimer() const { return InteractionPauseTimer; } std::string ToString() const; diff --git a/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp b/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp index 86b2bae5d5a..c04e7cedd5b 100644 --- a/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp +++ b/src/server/game/Entities/Creature/enuminfo_CreatureData.cpp @@ -40,7 +40,7 @@ TC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr case CREATURE_FLAG_EXTRA_NO_XP: return { "CREATURE_FLAG_EXTRA_NO_XP", "CREATURE_FLAG_EXTRA_NO_XP", "creature kill does not provide XP" }; case CREATURE_FLAG_EXTRA_TRIGGER: return { "CREATURE_FLAG_EXTRA_TRIGGER", "CREATURE_FLAG_EXTRA_TRIGGER", "trigger creature" }; case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" }; - case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" }; + case CREATURE_FLAG_EXTRA_UNUSED_9: return { "CREATURE_FLAG_EXTRA_UNUSED_9", "CREATURE_FLAG_EXTRA_UNUSED_9", "creature won't update movement flags" }; case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" }; case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return { "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK", "creature will use offhand attacks" }; case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" }; @@ -84,7 +84,7 @@ TC_API_EXPORT CreatureFlagsExtra EnumUtils<CreatureFlagsExtra>::FromIndex(size_t case 6: return CREATURE_FLAG_EXTRA_NO_XP; case 7: return CREATURE_FLAG_EXTRA_TRIGGER; case 8: return CREATURE_FLAG_EXTRA_NO_TAUNT; - case 9: return CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE; + case 9: return CREATURE_FLAG_EXTRA_UNUSED_9; case 10: return CREATURE_FLAG_EXTRA_GHOST_VISIBILITY; case 11: return CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK; case 12: return CREATURE_FLAG_EXTRA_NO_SELL_VENDOR; @@ -125,7 +125,7 @@ TC_API_EXPORT size_t EnumUtils<CreatureFlagsExtra>::ToIndex(CreatureFlagsExtra v case CREATURE_FLAG_EXTRA_NO_XP: return 6; case CREATURE_FLAG_EXTRA_TRIGGER: return 7; case CREATURE_FLAG_EXTRA_NO_TAUNT: return 8; - case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return 9; + case CREATURE_FLAG_EXTRA_UNUSED_9: return 9; case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return 10; case CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK: return 11; case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return 12; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index fa9ed374883..4cd114f170d 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3741,9 +3741,17 @@ float WorldObject::GetFloorZ() const float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const { - return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, - isType(TYPEMASK_UNIT) ? !static_cast<Unit const*>(this)->HasAuraType(SPELL_AURA_WATER_WALK) : false, - GetCollisionHeight()); + bool swimming = [&]() + { + if (Creature const* creature = ToCreature()) + return (!creature->CannotPenetrateWater() && !creature->HasAuraType(SPELL_AURA_WATER_WALK)); + else if (Unit const* unit = ToUnit()) + return !unit->HasAuraType(SPELL_AURA_WATER_WALK); + + return true; + }(); + + return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, swimming, GetCollisionHeight()); } float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 36a1d1545ed..2eb9b88538f 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3161,10 +3161,23 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const bool Unit::isInAccessiblePlaceFor(Creature const* c) const { - if (IsInWater()) - return c->CanEnterWater(); - else - return c->CanWalk() || c->CanFly(); + // Aquatic creatures are not allowed to leave liquids + if (!IsInWater() && c->IsAquatic()) + return false; + + // Underwater special case. Some creatures may not go below liquid surfaces + if (IsUnderWater() && c->CannotPenetrateWater()) + return false; + + // Water checks + if (IsInWater() && !c->CanEnterWater()) + return false; + + // Some creatures are tied to the ocean floor and cannot chase swimming targets. + if (!IsOnOceanFloor() && c->IsUnderWater() && c->HasUnitFlag(UNIT_FLAG_CANT_SWIM)) + return false; + + return true; } bool Unit::IsInWater() const @@ -10883,7 +10896,7 @@ void Unit::SetControlled(bool apply, UnitState state) SetStunned(false); break; case UNIT_STATE_ROOT: - if (HasAuraType(SPELL_AURA_MOD_ROOT) || HasAuraType(SPELL_AURA_MOD_ROOT_2) || HasAuraType(SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY) || GetVehicle() || (ToCreature() && ToCreature()->IsTemplateRooted())) + if (HasAuraType(SPELL_AURA_MOD_ROOT) || HasAuraType(SPELL_AURA_MOD_ROOT_2) || HasAuraType(SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY) || GetVehicle() || (ToCreature() && ToCreature()->IsSessile())) return; ClearUnitState(state); @@ -11224,9 +11237,6 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au AddUnitState(UNIT_STATE_CHARMED); - if (Creature* creature = ToCreature()) - creature->RefreshCanSwimFlag(); - if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER)) { // AI will schedule its own change if appropriate @@ -12681,7 +12691,7 @@ bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/) SendMessageToSet(packet.Write(), true); } - if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->IsTemplateRooted()) + if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT)) { if (IsGravityDisabled()) SetAnimTier(AnimTier::Fly); @@ -12907,7 +12917,7 @@ bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/) SendMessageToSet(packet.Write(), true); } - if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->IsTemplateRooted()) + if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT)) { if (IsGravityDisabled()) SetAnimTier(AnimTier::Fly); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5d1fbd9e64a..18eabd6f75f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1721,10 +1721,7 @@ class TC_GAME_API Unit : public WorldObject virtual bool CanEnterWater() const = 0; virtual bool CanSwim() const; - float GetHoverOffset() const - { - return HasUnitMovementFlag(MOVEMENTFLAG_HOVER) ? *m_unitData->HoverHeight : 0.0f; - } + float GetHoverOffset() const { return HasUnitMovementFlag(MOVEMENTFLAG_HOVER) ? *m_unitData->HoverHeight : 0.0f; } void RewardRage(uint32 baseRage); diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index 348a9f6d611..c675a39bd06 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -177,7 +177,7 @@ enum UnitFlags : uint32 UNIT_FLAG_DISALLOWED = (UNIT_FLAG_SERVER_CONTROLLED | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_RENAME | UNIT_FLAG_PREPARATION | /* UNIT_FLAG_UNK_6 | */ UNIT_FLAG_NOT_ATTACKABLE_1 | UNIT_FLAG_LOOTING | UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_PVP_ENABLING | - UNIT_FLAG_NON_ATTACKABLE_2 | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | + UNIT_FLAG_CANT_SWIM | UNIT_FLAG_CAN_SWIM | UNIT_FLAG_NON_ATTACKABLE_2 | UNIT_FLAG_PACIFIED | UNIT_FLAG_STUNNED | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_ON_TAXI | UNIT_FLAG_DISARMED | UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_POSSESSED | UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_UNK_28 | UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT | UNIT_FLAG_SHEATHE | UNIT_FLAG_IMMUNE), // SKIP @@ -227,7 +227,7 @@ enum UnitFlags2 : uint32 UNIT_FLAG2_DISALLOWED = (UNIT_FLAG2_FEIGN_DEATH | UNIT_FLAG2_IGNORE_REPUTATION | UNIT_FLAG2_COMPREHEND_LANG | UNIT_FLAG2_MIRROR_IMAGE | UNIT_FLAG2_FORCE_MOVEMENT | UNIT_FLAG2_DISARM_OFFHAND | UNIT_FLAG2_DISABLE_PRED_STATS | UNIT_FLAG2_ALLOW_CHANGING_TALENTS | UNIT_FLAG2_DISARM_RANGED | - /* UNIT_FLAG2_REGENERATE_POWER | */ UNIT_FLAG2_RESTRICT_PARTY_INTERACTION | + /* UNIT_FLAG2_REGENERATE_POWER | */ UNIT_FLAG2_RESTRICT_PARTY_INTERACTION | UNIT_FLAG2_CANNOT_TURN | UNIT_FLAG2_PREVENT_SPELL_CLICK | /* UNIT_FLAG2_INTERACT_WHILE_HOSTILE | */ /* UNIT_FLAG2_UNK2 | */ /* UNIT_FLAG2_PLAY_DEATH_ANIM | */ UNIT_FLAG2_ALLOW_CHEAT_SPELLS | UNIT_FLAG2_SUPPRESS_HIGHLIGHT_WHEN_TARGETED_OR_MOUSED_OVER | UNIT_FLAG2_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS | UNIT_FLAG2_LARGE_AOI | UNIT_FLAG2_GIGANTIC_AOI | UNIT_FLAG2_NO_ACTIONS | diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 70c1d64c309..75b4da4172c 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -363,13 +363,13 @@ void ObjectMgr::LoadCreatureTemplates() // "unit_class, unit_flags, unit_flags2, unit_flags3, " // 25 26 27 28 29 30 // "family, trainer_class, type, VehicleId, AIName, MovementType, " - // 31 32 33 34 35 36 37 38 - // "ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, ExperienceModifier, " - // 39 40 41 42 43 + // 31 32 33 34 35 + // "ctm.HoverInitiallyEnabled, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, ExperienceModifier, " + // 36 37 38 39 40 // "RacialLeader, movementId, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, " - // 44 45 + // 41 42 // "CreatureImmunitiesId, flags_extra, " - // 46 47 + // 43 44 // "ScriptName, StringId FROM creature_template WHERE entry = ? OR 1 = ?"); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_CREATURE_TEMPLATE); @@ -448,37 +448,29 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.VehicleId = fields[28].GetUInt32(); creatureTemplate.AIName = fields[29].GetString(); creatureTemplate.MovementType = uint32(fields[30].GetUInt8()); + if (!fields[31].IsNull()) - creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[31].GetUInt8()); + creatureTemplate.Movement.HoverInitiallyEnabled = fields[31].GetBool(); if (!fields[32].IsNull()) - creatureTemplate.Movement.Swim = fields[32].GetBool(); + creatureTemplate.Movement.Chase = static_cast<CreatureChaseMovementType>(fields[32].GetUInt8()); if (!fields[33].IsNull()) - creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[33].GetUInt8()); + creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[33].GetUInt8()); if (!fields[34].IsNull()) - creatureTemplate.Movement.Rooted = fields[34].GetBool(); - - if (!fields[35].IsNull()) - creatureTemplate.Movement.Chase = static_cast<CreatureChaseMovementType>(fields[35].GetUInt8()); - - if (!fields[36].IsNull()) - creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[36].GetUInt8()); + creatureTemplate.Movement.InteractionPauseTimer = fields[34].GetUInt32(); - if (!fields[37].IsNull()) - creatureTemplate.Movement.InteractionPauseTimer = fields[37].GetUInt32(); - - creatureTemplate.ModExperience = fields[38].GetFloat(); - creatureTemplate.RacialLeader = fields[39].GetBool(); - creatureTemplate.movementId = fields[40].GetUInt32(); - creatureTemplate.WidgetSetID = fields[41].GetInt32(); - creatureTemplate.WidgetSetUnitConditionID = fields[42].GetInt32(); - creatureTemplate.RegenHealth = fields[43].GetBool(); - creatureTemplate.CreatureImmunitiesId = fields[44].GetInt32(); - creatureTemplate.flags_extra = fields[45].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[46].GetString()); - creatureTemplate.StringId = fields[47].GetString(); + creatureTemplate.ModExperience = fields[35].GetFloat(); + creatureTemplate.RacialLeader = fields[36].GetBool(); + creatureTemplate.movementId = fields[37].GetUInt32(); + creatureTemplate.WidgetSetID = fields[38].GetInt32(); + creatureTemplate.WidgetSetUnitConditionID = fields[39].GetInt32(); + creatureTemplate.RegenHealth = fields[40].GetBool(); + creatureTemplate.CreatureImmunitiesId = fields[41].GetInt32(); + creatureTemplate.flags_extra = fields[42].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[43].GetString()); + creatureTemplate.StringId = fields[44].GetString(); } void ObjectMgr::LoadCreatureTemplateGossip() @@ -1171,20 +1163,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) void ObjectMgr::CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement) { - if (creatureMovement.Ground >= CreatureGroundMovementType::Max) - { - TC_LOG_ERROR("sql.sql", "`{}`.`Ground` wrong value ({}) for Id {}, setting to Run.", - table, uint32(creatureMovement.Ground), id); - creatureMovement.Ground = CreatureGroundMovementType::Run; - } - - if (creatureMovement.Flight >= CreatureFlightMovementType::Max) - { - TC_LOG_ERROR("sql.sql", "`{}`.`Flight` wrong value ({}) for Id {}, setting to None.", - table, uint32(creatureMovement.Flight), id); - creatureMovement.Flight = CreatureFlightMovementType::None; - } - if (creatureMovement.Chase >= CreatureChaseMovementType::Max) { TC_LOG_ERROR("sql.sql", "`{}`.`Chase` wrong value ({}) for Id {}, setting to Run.", @@ -1581,10 +1559,7 @@ void ObjectMgr::LoadCreatureMovementOverrides() // Load the data from creature_movement_override and if NULL fallback to creature_template_movement QueryResult result = WorldDatabase.Query( "SELECT cmo.SpawnId," - "COALESCE(cmo.Ground, ctm.Ground)," - "COALESCE(cmo.Swim, ctm.Swim)," - "COALESCE(cmo.Flight, ctm.Flight)," - "COALESCE(cmo.Rooted, ctm.Rooted)," + "COALESCE(cmo.HoverInitiallyEnabled, ctm.HoverInitiallyEnabled)," "COALESCE(cmo.Chase, ctm.Chase)," "COALESCE(cmo.Random, ctm.Random)," "COALESCE(cmo.InteractionPauseTimer, ctm.InteractionPauseTimer) " @@ -1610,19 +1585,13 @@ void ObjectMgr::LoadCreatureMovementOverrides() CreatureMovementData& movement = _creatureMovementOverrides[spawnId]; if (!fields[1].IsNull()) - movement.Ground = static_cast<CreatureGroundMovementType>(fields[1].GetUInt8()); + movement.HoverInitiallyEnabled = fields[1].GetBool(); if (!fields[2].IsNull()) - movement.Swim = fields[2].GetBool(); + movement.Chase = static_cast<CreatureChaseMovementType>(fields[2].GetUInt8()); if (!fields[3].IsNull()) - movement.Flight = static_cast<CreatureFlightMovementType>(fields[3].GetUInt8()); + movement.Random = static_cast<CreatureRandomMovementType>(fields[3].GetUInt8()); if (!fields[4].IsNull()) - movement.Rooted = fields[4].GetBool(); - if (!fields[5].IsNull()) - movement.Chase = static_cast<CreatureChaseMovementType>(fields[5].GetUInt8()); - if (!fields[6].IsNull()) - movement.Random = static_cast<CreatureRandomMovementType>(fields[6].GetUInt8()); - if (!fields[7].IsNull()) - movement.InteractionPauseTimer = fields[7].GetUInt32(); + movement.InteractionPauseTimer = fields[4].GetUInt32(); CheckCreatureMovement("creature_movement_override", spawnId, movement); } @@ -1659,7 +1628,7 @@ CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, C return cinfo->GetFirstInvisibleModel(); } -void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* unitFlags3, CreatureData const* data /*= nullptr*/) +void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* unitFlags3, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data /*= nullptr*/) { #define ChooseCreatureFlagSource(field) ((data && data->field.has_value()) ? *data->field : cInfo->field) @@ -1667,10 +1636,21 @@ void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFl *npcFlags = ChooseCreatureFlagSource(npcflag); if (unitFlags) + { *unitFlags = ChooseCreatureFlagSource(unit_flags); + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_CAN_SWIM)) + *unitFlags |= UNIT_FLAG_CAN_SWIM; + + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM)) + *unitFlags |= UNIT_FLAG_CANT_SWIM; + } if (unitFlags2) + { *unitFlags2 = ChooseCreatureFlagSource(unit_flags2); + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_TURN)) + *unitFlags2 |= UNIT_FLAG2_CANNOT_TURN; + } if (unitFlags3) *unitFlags3 = ChooseCreatureFlagSource(unit_flags3); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 7a570135431..392fb9abaef 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1132,7 +1132,7 @@ class TC_GAME_API ObjectMgr CreatureModelInfo const* GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const; CreatureSummonedData const* GetCreatureSummonedData(uint32 entryId) const; static CreatureModel const* ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = nullptr); - static void ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* unitFlags3, CreatureData const* data = nullptr); + static void ChooseCreatureFlags(CreatureTemplate const* cInfo, uint64* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* unitFlags3, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data = nullptr); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id) const; CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const; GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid) const; diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index a62f0700f48..4c9a3648bc3 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -144,11 +144,9 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, b if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) { - if (!owner->HasCanSwimFlagOutOfCombat()) - owner->RemoveUnitFlag(UNIT_FLAG_CAN_SWIM); - if (owner->IsStateRestoredOnEvade()) { + owner->InitializeMovementCapabilities(); owner->SetSpawnHealth(); owner->LoadCreaturesAddon(); owner->LoadCreaturesSparringHealth(); diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index a5967cf5867..17ff6c7a864 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -179,7 +179,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con BuildShortcut(); bool path = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanFly(); - bool waterPath = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanSwim(); + bool waterPath = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanEnterWater(); if (waterPath) { // Check both start and end points, if they're both in water, then we can *safely* let the creature move @@ -653,7 +653,7 @@ void PathGenerator::CreateFilter() if (_source->GetTypeId() == TYPEID_UNIT) { Creature* creature = (Creature*)_source; - if (creature->CanWalk()) + if (!creature->IsAquatic()) includeFlags |= NAV_GROUND; // walk // creatures don't take environmental damage diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index e86637c6780..c9ceb470b9d 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2985,10 +2985,7 @@ void AuraEffect::HandleAuraModRootAndDisableGravity(AuraApplication const* aurAp target->SetControlled(apply, UNIT_STATE_ROOT); // Do not remove DisableGravity if there are more than this auraEffect of that kind on the unit or if it's a creature with DisableGravity on its movement template. - if (!apply - && (target->HasAuraType(GetAuraType()) - || target->HasAuraType(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY) - || (target->IsCreature() && target->ToCreature()->GetMovementTemplate().Flight == CreatureFlightMovementType::DisableGravity))) + if (!apply && (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY) || (target->IsCreature() && target->ToCreature()->IsFloating()))) return; if (target->SetDisableGravity(apply)) @@ -3009,10 +3006,7 @@ void AuraEffect::HandleAuraModStunAndDisableGravity(AuraApplication const* aurAp target->GetThreatManager().EvaluateSuppressed(); // Do not remove DisableGravity if there are more than this auraEffect of that kind on the unit or if it's a creature with DisableGravity on its movement template. - if (!apply - && (target->HasAuraType(GetAuraType()) - || target->HasAuraType(SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY) - || (target->IsCreature() && target->ToCreature()->GetMovementTemplate().Flight == CreatureFlightMovementType::DisableGravity))) + if (!apply && (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY) || (target->IsCreature() && target->ToCreature()->IsFloating()))) return; if (target->SetDisableGravity(apply)) diff --git a/src/server/scripts/EasternKingdoms/zone_dun_morogh_area_coldridge_valley.cpp b/src/server/scripts/EasternKingdoms/zone_dun_morogh_area_coldridge_valley.cpp index 541ec3c53b0..7ab449b9191 100644 --- a/src/server/scripts/EasternKingdoms/zone_dun_morogh_area_coldridge_valley.cpp +++ b/src/server/scripts/EasternKingdoms/zone_dun_morogh_area_coldridge_valley.cpp @@ -492,8 +492,6 @@ struct npc_joren_ironstock : public ScriptedAI void JustAppeared() override { - me->SetTemplateRooted(true); - _scheduler.Schedule(1s, [this](TaskContext task) { if (Creature* invader = me->SummonCreature(NPC_ROCKJAW_INVADER, Trinity::Containers::SelectRandomContainerElement(RockjawInvaderSpawnPoints), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 18s)) diff --git a/src/server/scripts/ExilesReach/zone_exiles_reach.cpp b/src/server/scripts/ExilesReach/zone_exiles_reach.cpp index 0ec3d94693f..e5f0e36616d 100644 --- a/src/server/scripts/ExilesReach/zone_exiles_reach.cpp +++ b/src/server/scripts/ExilesReach/zone_exiles_reach.cpp @@ -4460,7 +4460,7 @@ struct npc_briarpatch_prisoner : public ScriptedAI void JustAppeared() override { me->SetDisableGravity(true); - me->SetTemplateRooted(true); + me->SetControlled(true, UNIT_STATE_ROOT); me->CastSpell(me, SPELL_NECROTIC_RITUAL_DNT); } @@ -4470,7 +4470,7 @@ struct npc_briarpatch_prisoner : public ScriptedAI { me->RemoveAllAuras(); me->SetDisableGravity(false); - me->SetTemplateRooted(false); + me->SetControlled(false, UNIT_STATE_ROOT); me->GetMotionMaster()->MoveJump(BriarpatchPrisonerJumpToPosition, 7.9894905f, 19.29110336303710937f); Talk(SAY_GET_OUT_OF_HERE); _events.ScheduleEvent(EVENT_RUN_TO_PLAINS, 4s); @@ -6277,7 +6277,7 @@ struct npc_captain_garrick_q55879 : public ScriptedAI if (!boar) return; - boar->SetTemplateRooted(false); + boar->SetControlled(false, UNIT_STATE_ROOT); me->CastSpell(boar, SPELL_RIDE_VEHICLE_CAPTIAN_BOAR); } break; @@ -6372,7 +6372,7 @@ struct npc_giant_boar_vehicle_q55879 : public VehicleAI { if (apply && passenger->IsPlayer()) { - me->SetTemplateRooted(true); + me->SetControlled(true, UNIT_STATE_ROOT); passenger->SetMovedUnit(me); passenger->CastSpell(passenger, SPELL_PING_GARRICK_TO_RIDE_BOAR); // Ping Garrick to ride Boar (DNT) passenger->CastSpell(passenger, SPELL_UPDATE_PHASE_SHIFT); @@ -6388,7 +6388,7 @@ struct npc_giant_boar_vehicle_q55879 : public VehicleAI if (spellInfo->Id == SPELL_ENHANCED_BOAR_PING_VEHICLE) { me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_01); - me->SetTemplateRooted(true); + me->SetControlled(true, UNIT_STATE_ROOT); me->CastSpell(me, SPELL_ENHANCED_BOAR_CHARGE); _endOfScene = true; _events.ScheduleEvent(EVENT_GIANT_BOAR_SIZE_ONE, 4s); @@ -6434,7 +6434,7 @@ struct npc_giant_boar_vehicle_q55879 : public VehicleAI _events.ScheduleEvent(EVENT_GIANT_BOAR_UNROOT, 500ms); break; case EVENT_GIANT_BOAR_UNROOT: - me->SetTemplateRooted(false); + me->SetControlled(false, UNIT_STATE_ROOT); break; default: break; diff --git a/src/server/scripts/Kalimdor/zone_durotar.cpp b/src/server/scripts/Kalimdor/zone_durotar.cpp index 0a774e75a1e..4d959dce9c1 100644 --- a/src/server/scripts/Kalimdor/zone_durotar.cpp +++ b/src/server/scripts/Kalimdor/zone_durotar.cpp @@ -211,7 +211,6 @@ struct npc_durotar_tiki_target : public ScriptedAI void JustAppeared() override { me->SetReactState(REACT_PASSIVE); - me->SetTemplateRooted(true); DoCastSelf(TiKiTargetMask[urand(0, 2)]); DoCastSelf(SPELL_ARCANE_MISSILES_TRAINER); } |