Core/Unit: Fix movement hiccups in water
* 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.
This commit is contained in:
1 parent
6ba851e809
commit
5e3b57bae7
11 files changed
+60
-15
No files matched your search
@@ -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());
|
||||
|
||||
@@ -95,7 +95,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(); }
|
||||
bool SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true) override;
|
||||
@@ -366,6 +367,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);
|
||||
|
||||
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<Creature>, public Ma
|
||||
} _spellFocusInfo;
|
||||
|
||||
CreatureTextRepeatGroup m_textRepeat;
|
||||
|
||||
bool _isMissingSwimmingFlagOutOfCombat;
|
||||
};
|
||||
|
||||
class TC_GAME_API AssistDelayEvent : public BasicEvent
|
||||
|
||||
@@ -2374,6 +2374,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
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;
|
||||
|
||||
@@ -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*/)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -81,6 +81,9 @@ void HomeMovementGenerator<Creature>::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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -135,7 +135,7 @@ EnumName<UnitFlags> 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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user