diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 7832f7d39d..ab4e01ad20 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -267,7 +267,7 @@ m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTi m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), _cyclicSplinePathId(0), -m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false) +m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _isMissingSwimmingFlagOutOfCombat(false) { m_valuesCount = UNIT_END; @@ -2722,6 +2722,36 @@ CreatureMovementData const& Creature::GetMovementTemplate() const return GetCreatureTemplate()->Movement; } +bool Creature::CanSwim() const +{ + if (Unit::CanSwim()) + return true; + + if (IsPet()) + return true; + + return false; +} + +bool Creature::CanEnterWater() const +{ + if (CanSwim()) + return true; + + return GetMovementTemplate().IsSwimAllowed(); +} + +void Creature::RefreshSwimmingFlag(bool recheck) +{ + if (!_isMissingSwimmingFlagOutOfCombat || recheck) + _isMissingSwimmingFlagOutOfCombat = !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); + + // Check if the creature has UNIT_FLAG_SWIMMING and add it if it's missing + // Creatures must be able to chase a target in water if they can enter water + if (_isMissingSwimmingFlagOutOfCombat && CanEnterWater()) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); +} + void Creature::AllLootRemovedFromCorpse() { if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient()) @@ -3014,8 +3044,7 @@ void Creature::UpdateMovementFlags() if (!isInAir) RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); - if (GetMovementTemplate().IsSwimAllowed()) - SetSwim(IsInWater()); + SetSwim(CanSwim() && IsInWater()); } void Creature::SetObjectScale(float scale) @@ -3250,6 +3279,8 @@ void Creature::AtEngage(Unit* target) if (!(GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_MOUNTED_COMBAT_ALLOWED)) Dismount(); + RefreshSwimmingFlag(); + MovementGeneratorType const movetype = GetMotionMaster()->GetCurrentMovementGeneratorType(); if (movetype == WAYPOINT_MOTION_TYPE || movetype == POINT_MOTION_TYPE || (IsAIEnabled && AI()->IsEscorted())) SetHomePosition(GetPosition()); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 19531e186b..6403677325 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -95,7 +95,8 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma CreatureMovementData const& GetMovementTemplate() const; bool CanWalk() const { return GetMovementTemplate().IsGroundAllowed(); } - bool CanSwim() const override { return GetMovementTemplate().IsSwimAllowed() || IsPet(); } + 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 SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true) override; @@ -366,6 +367,12 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma void AtEngage(Unit* target) override; void AtDisengage() override; + bool HasSwimmingFlagOutOfCombat() const + { + return !_isMissingSwimmingFlagOutOfCombat; + } + void RefreshSwimmingFlag(bool recheck = false); + protected: bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0); bool InitEntry(uint32 entry, CreatureData const* data = nullptr); @@ -446,6 +453,8 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma } _spellFocusInfo; CreatureTextRepeatGroup m_textRepeat; + + bool _isMissingSwimmingFlagOutOfCombat; }; class TC_GAME_API AssistDelayEvent : public BasicEvent diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 6f4da8208e..35d88415c5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2374,6 +2374,7 @@ class TC_GAME_API Player : public Unit, public GridObject void SendMovementSetCollisionHeight(float height, UpdateCollisionHeightReason reason); bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } + bool CanEnterWater() const override { return true; } std::string GetMapAreaAndZoneString() const; std::string GetCoordsMapAreaAndZoneString() const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 144e84b8c7..aa19689fcd 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3130,7 +3130,7 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const bool Unit::isInAccessiblePlaceFor(Creature const* c) const { if (IsInWater()) - return c->CanSwim(); + return c->CanEnterWater(); else return c->CanWalk() || c->CanFly(); } @@ -13271,9 +13271,9 @@ bool Unit::CanSwim() const return true; if (HasFlag(UNIT_FIELD_FLAGS_2, 0x1000000)) return false; - if (IsPet() && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT)) + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT)) return true; - return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME | UNIT_FLAG_UNK_15); + return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME | UNIT_FLAG_SWIMMING); } void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 9d297ec469..fc622d0fe1 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1672,6 +1672,7 @@ class TC_GAME_API Unit : public WorldObject virtual bool CanFly() const = 0; bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY); } bool IsFalling() const; + virtual bool CanEnterWater() const = 0; virtual bool CanSwim() const; float GetHoverOffset() const diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index 3d196641b0..05b82a79bc 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -135,7 +135,7 @@ enum UnitFlags : uint32 UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3 UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1 UNIT_FLAG_CANNOT_SWIM = 0x00004000, // 2.0.8 - UNIT_FLAG_UNK_15 = 0x00008000, + UNIT_FLAG_SWIMMING = 0x00008000, // shows swim animation in water UNIT_FLAG_NOT_ATTACKABLE_2 = 0x00010000, UNIT_FLAG_PACIFIED = 0x00020000, // 3.0.3 ok UNIT_FLAG_STUNNED = 0x00040000, // 3.0.3 ok diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index a8e0b273f1..31af5cd8c1 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -81,6 +81,9 @@ void HomeMovementGenerator::DoFinalize(Creature* owner) { if (_arrived) { + if (!owner->HasSwimmingFlagOutOfCombat()) + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); + owner->ClearUnitState(UNIT_STATE_EVADE); owner->SetWalk(true); owner->LoadCreaturesAddon(); diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index b0bb77175a..b3ef3d54eb 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -658,7 +658,7 @@ void PathGenerator::CreateFilter() includeFlags |= NAV_GROUND; // walk // creatures don't take environmental damage - if (creature->CanSwim()) + if (creature->CanEnterWater()) includeFlags |= (NAV_WATER | NAV_MAGMA_SLIME); // swim } else // assume Player diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 70d239cf75..0efa002ce7 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -135,7 +135,7 @@ EnumName const unitFlags[MAX_UNIT_FLAGS] = CREATE_NAMED_ENUM(UNIT_FLAG_PVP), CREATE_NAMED_ENUM(UNIT_FLAG_SILENCED), CREATE_NAMED_ENUM(UNIT_FLAG_CANNOT_SWIM), - CREATE_NAMED_ENUM(UNIT_FLAG_UNK_15), + CREATE_NAMED_ENUM(UNIT_FLAG_SWIMMING), CREATE_NAMED_ENUM(UNIT_FLAG_NOT_ATTACKABLE_2), CREATE_NAMED_ENUM(UNIT_FLAG_PACIFIED), CREATE_NAMED_ENUM(UNIT_FLAG_STUNNED), diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp index 780d1e4525..e55d170e78 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp @@ -533,7 +533,7 @@ public: me->RestoreFaction(); CombatAI::Reset(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); } void SpellHit(Unit* pCaster, SpellInfo const* pSpell) override @@ -628,7 +628,7 @@ public: } me->SetImmuneToPC(false); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); player->CastSpell(me, SPELL_DUEL, false); player->CastSpell(player, SPELL_DUEL_FLAG, true); diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp index 139cb6b4ed..e8830c1f6b 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp @@ -280,10 +280,10 @@ class spell_varos_centrifuge_shield : public SpellScriptLoader if (Unit* caster = GetCaster()) { // flags taken from sniffs - if (caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_IMMUNE_TO_NPC|UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_UNK_6)) + if (caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_UNK_6)) { caster->ToCreature()->SetReactState(REACT_PASSIVE); - caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_UNK_6); + caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_UNK_6); caster->SetImmuneToAll(true, true); } } @@ -294,7 +294,7 @@ class spell_varos_centrifuge_shield : public SpellScriptLoader if (Unit* caster = GetCaster()) { caster->ToCreature()->SetReactState(REACT_AGGRESSIVE); - caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15|UNIT_FLAG_UNK_6); + caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_UNK_6); caster->SetImmuneToAll(false); } }