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. (cherry picked from commit fc1a0d936888395f114028af3337e7d674e0a43c)
This commit is contained in:
@@ -305,7 +305,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), m_grou
|
||||
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), _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;
|
||||
|
||||
@@ -2829,7 +2829,7 @@ void Creature::UpdateMovementFlags()
|
||||
if (!isInAir)
|
||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||
|
||||
SetSwim(GetMovementTemplate().IsSwimAllowed() && IsInWater());
|
||||
SetSwim(CanSwim() && IsInWater());
|
||||
}
|
||||
|
||||
CreatureMovementData const& Creature::GetMovementTemplate() const
|
||||
@@ -2840,6 +2840,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 = !HasUnitFlag(UNIT_FLAG_CAN_SWIM);
|
||||
|
||||
// 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())
|
||||
AddUnitFlag(UNIT_FLAG_CAN_SWIM);
|
||||
}
|
||||
|
||||
void Creature::AllLootRemovedFromCorpse()
|
||||
{
|
||||
if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
|
||||
@@ -3418,6 +3448,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);
|
||||
|
||||
@@ -111,7 +111,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(); }
|
||||
|
||||
@@ -369,6 +370,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:
|
||||
@@ -452,6 +459,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
|
||||
|
||||
@@ -2623,6 +2623,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SendMovementSetCollisionHeight(float height, WorldPackets::Movement::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;
|
||||
|
||||
@@ -3006,7 +3006,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();
|
||||
}
|
||||
@@ -11150,6 +11150,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
|
||||
@@ -12107,7 +12110,7 @@ bool Unit::CanSwim() const
|
||||
return true;
|
||||
if (HasUnitFlag2(UnitFlags2(0x1000000)))
|
||||
return false;
|
||||
if (IsPet() && HasUnitFlag(UNIT_FLAG_PET_IN_COMBAT))
|
||||
if (HasUnitFlag(UNIT_FLAG_PET_IN_COMBAT))
|
||||
return true;
|
||||
return HasUnitFlag(UnitFlags(UNIT_FLAG_RENAME | UNIT_FLAG_CAN_SWIM));
|
||||
}
|
||||
|
||||
@@ -1807,6 +1807,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
|
||||
|
||||
@@ -144,6 +144,9 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, b
|
||||
|
||||
if (movementInform && HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))
|
||||
{
|
||||
if (!owner->HasSwimmingFlagOutOfCombat())
|
||||
owner->RemoveUnitFlag(UNIT_FLAG_CAN_SWIM);
|
||||
|
||||
owner->SetSpawnHealth();
|
||||
owner->LoadCreaturesAddon();
|
||||
if (owner->IsVehicle())
|
||||
|
||||
@@ -657,7 +657,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
|
||||
|
||||
Reference in New Issue
Block a user