diff options
author | Giacomo Pozzoni <giacomopoz@gmail.com> | 2021-01-10 10:18:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-10 10:18:51 +0100 |
commit | fc1a0d936888395f114028af3337e7d674e0a43c (patch) | |
tree | 2552ac79ed07810f8cc00995f965733ed24f02b5 | |
parent | 95a2b906b0bce6756c28334b6dadd051879c8587 (diff) |
Core/Unit: Fix movement hiccups in water (#24020)
* Core/Unit: Allow to define Units which can enter water but cannot swim
Allow to define Units which can enter water but cannot swim, i.e. crabs walking at the bottom of a sea.
* Add UNIT_FLAG_SWIMMING to creatures when entering combat
* Fix charmed creatures not entering water
* Always allow Creatures controlled by players to enter water
* Add swimming flag when possessing a unit and remove it properly at the end, even if the creature engaged combat before and after.
When adding/removing UNIT_FLAG_SWIMMING manually calling Creature::RefreshSwimmingFlag(true) might be required.
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 36 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 11 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 1 | ||||
-rw-r--r-- | src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Movement/PathGenerator.cpp | 2 |
7 files changed, 55 insertions, 6 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index e5704936af8..eac1f315e0a 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -250,7 +250,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_grou m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(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), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0), - _regenerateHealth(true), _regenerateHealthLock(false) + _regenerateHealth(true), _regenerateHealthLock(false), _isMissingSwimmingFlagOutOfCombat(false) { m_regenTimer = CREATURE_REGEN_INTERVAL; m_valuesCount = UNIT_END; @@ -2682,7 +2682,7 @@ void Creature::UpdateMovementFlags() if (!isInAir) RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); - SetSwim(GetMovementTemplate().IsSwimAllowed() && IsInWater()); + SetSwim(CanSwim() && IsInWater()); } CreatureMovementData const& Creature::GetMovementTemplate() const @@ -2693,6 +2693,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()) @@ -3297,6 +3327,8 @@ void Creature::AtEngage(Unit* target) if (!(GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_MOUNTED_COMBAT_ALLOWED)) Dismount(); + RefreshSwimmingFlag(); + 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 b39ed00484b..90881842f1d 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -97,7 +97,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, 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(); } @@ -356,6 +357,12 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma void AtEngage(Unit* target) override; void AtDisengage() override; + bool HasSwimmingFlagOutOfCombat() const + { + return !_isMissingSwimmingFlagOutOfCombat; + } + void RefreshSwimmingFlag(bool recheck = false); + std::string GetDebugInfo() const override; protected: @@ -439,6 +446,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma // Regenerate health bool _regenerateHealth; // Set on creation bool _regenerateHealthLock; // Dynamically set + + 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 4555c9ef48a..6d0ccc7bc37 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2165,6 +2165,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool SetHover(bool enable, bool packetOnly = false, bool updateAnimationTier = true) override; 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 d4b57c61487..ec7caa2fb1d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3131,7 +3131,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(); } @@ -11615,6 +11615,9 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au AddUnitState(UNIT_STATE_CHARMED); + if (Creature* creature = ToCreature()) + creature->RefreshSwimmingFlag(); + if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER)) { // AI will schedule its own change if appropriate @@ -12790,7 +12793,7 @@ 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_SWIMMING); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index dae93115775..bcafefc1dfd 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1639,6 +1639,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/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index cad38b6c698..2405f97cc59 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -144,6 +144,9 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, b if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) { + if (!owner->HasSwimmingFlagOutOfCombat()) + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING); + owner->SetSpawnHealth(); owner->LoadCreaturesAddon(); if (owner->IsVehicle()) diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 04d047fc008..84c29b30736 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -656,7 +656,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 |