Core/Creatures: implemented most movement related static flags and migrated existing movement data into static flags
* 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 Port From (https://github.com/TrinityCore/TrinityCore/commit/c541eda54d7e0dddeec329a6beac2948e0b0a40b)
This commit is contained in:
@@ -27,8 +27,6 @@ namespace Game.Entities
|
||||
// Regenerate health
|
||||
bool _regenerateHealth; // Set on creation
|
||||
|
||||
bool _isMissingCanSwimFlagOutOfCombat;
|
||||
|
||||
uint? _defaultMountDisplayIdOverride;
|
||||
int _creatureImmunitiesId;
|
||||
uint _gossipMenuId;
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace Game.Entities
|
||||
|
||||
SetFaction(cInfo.Faction);
|
||||
|
||||
ObjectManager.ChooseCreatureFlags(cInfo, out ulong npcFlags, out uint unitFlags, out uint unitFlags2, out uint unitFlags3, data);
|
||||
ObjectManager.ChooseCreatureFlags(cInfo, out ulong npcFlags, out uint unitFlags, out uint unitFlags2, out uint unitFlags3, _staticFlags, data);
|
||||
|
||||
if (cInfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.Worldevent))
|
||||
npcFlags |= Global.GameEventMgr.GetNPCFlag(this);
|
||||
@@ -399,7 +399,7 @@ namespace Game.Entities
|
||||
|
||||
SetIsCombatDisallowed(cInfo.FlagsExtra.HasFlag(CreatureFlagsExtra.CannotEnterCombat));
|
||||
|
||||
InitializeMovementFlags();
|
||||
InitializeMovementCapabilities();
|
||||
|
||||
LoadCreaturesAddon();
|
||||
LoadCreaturesSparringHealth();
|
||||
@@ -419,7 +419,6 @@ namespace Game.Entities
|
||||
_staticFlags = flags;
|
||||
|
||||
// Apply all other side effects of flag changes
|
||||
SetTemplateRooted(flags.HasFlag(CreatureStaticFlags.Sessile));
|
||||
m_updateFlag.NoBirthAnim = flags.HasFlag(CreatureStaticFlags4.NoBirthAnim);
|
||||
}
|
||||
|
||||
@@ -437,7 +436,7 @@ namespace Game.Entities
|
||||
GetAI().JustAppeared();
|
||||
}
|
||||
|
||||
UpdateMovementFlags();
|
||||
UpdateMovementCapabilities();
|
||||
|
||||
switch (m_deathState)
|
||||
{
|
||||
@@ -1062,8 +1061,6 @@ namespace Game.Entities
|
||||
if (!HasFlag(CreatureStaticFlags2.AllowMountedCombat))
|
||||
Dismount();
|
||||
|
||||
RefreshCanSwimFlag();
|
||||
|
||||
if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
|
||||
{
|
||||
UpdateSpeed(UnitMoveType.Run);
|
||||
@@ -1783,19 +1780,6 @@ namespace Game.Entities
|
||||
SetHealth((m_deathState == DeathState.Alive || m_deathState == DeathState.JustRespawned) ? curhealth : 0);
|
||||
}
|
||||
|
||||
void LoadTemplateRoot()
|
||||
{
|
||||
SetTemplateRooted(GetMovementTemplate().IsRooted());
|
||||
}
|
||||
|
||||
public bool IsTemplateRooted() { return _staticFlags.HasFlag(CreatureStaticFlags.Sessile); }
|
||||
|
||||
public void SetTemplateRooted(bool rooted)
|
||||
{
|
||||
_staticFlags.ApplyFlag(CreatureStaticFlags.Sessile, rooted);
|
||||
SetControlled(rooted, UnitState.Root);
|
||||
}
|
||||
|
||||
public override bool HasQuest(uint questId)
|
||||
{
|
||||
return Global.ObjectMgr.GetCreatureQuestRelations(GetEntry()).HasQuest(questId);
|
||||
@@ -2021,7 +2005,7 @@ namespace Game.Entities
|
||||
if (m_formation != null && m_formation.GetLeader() == this)
|
||||
m_formation.FormationReset(true);
|
||||
|
||||
bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater();
|
||||
bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater() && !HasUnitState(UnitState.Root);
|
||||
SetHover(false, false);
|
||||
SetDisableGravity(false, false);
|
||||
|
||||
@@ -2041,7 +2025,7 @@ namespace Game.Entities
|
||||
ResetPlayerDamageReq();
|
||||
|
||||
SetCannotReachTarget(false);
|
||||
UpdateMovementFlags();
|
||||
UpdateMovementCapabilities();
|
||||
|
||||
ClearUnitState(UnitState.AllErasable);
|
||||
|
||||
@@ -2050,7 +2034,7 @@ namespace Game.Entities
|
||||
CreatureData creatureData = GetCreatureData();
|
||||
CreatureTemplate cInfo = GetCreatureTemplate();
|
||||
|
||||
ObjectManager.ChooseCreatureFlags(cInfo, out ulong npcFlags, out uint unitFlags, out uint unitFlags2, out uint unitFlags3, creatureData);
|
||||
ObjectManager.ChooseCreatureFlags(cInfo, out ulong npcFlags, out uint unitFlags, out uint unitFlags2, out uint unitFlags3, _staticFlags, creatureData);
|
||||
|
||||
if (cInfo.FlagsExtra.HasAnyFlag(CreatureFlagsExtra.Worldevent))
|
||||
npcFlags |= Global.GameEventMgr.GetNPCFlag(this);
|
||||
@@ -2500,7 +2484,7 @@ namespace Game.Entities
|
||||
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);
|
||||
@@ -2525,23 +2509,15 @@ namespace Game.Entities
|
||||
CreatureAddon creatureAddon = GetCreatureAddon();
|
||||
if (creatureAddon == null)
|
||||
return false;
|
||||
|
||||
|
||||
uint mountDisplayId = _defaultMountDisplayIdOverride.GetValueOrDefault(creatureAddon.mount);
|
||||
if ( mountDisplayId != 0)
|
||||
if (mountDisplayId != 0)
|
||||
Mount(creatureAddon.mount);
|
||||
|
||||
SetStandState((UnitStandStateType)creatureAddon.standState);
|
||||
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);
|
||||
|
||||
@@ -2686,52 +2662,38 @@ namespace Game.Entities
|
||||
|
||||
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.MapId != GetMapId(); }
|
||||
|
||||
void InitializeMovementFlags()
|
||||
public void InitializeMovementCapabilities()
|
||||
{
|
||||
LoadTemplateRoot();
|
||||
SetHover(GetMovementTemplate().IsHoverInitiallyEnabled());
|
||||
SetDisableGravity(IsFloating());
|
||||
SetControlled(IsSessile(), UnitState.Root);
|
||||
|
||||
// It does the same, for now
|
||||
UpdateMovementFlags();
|
||||
// If an amphibious creatures was swimming while engaged, disable swimming again
|
||||
if (IsAmphibious() && !_staticFlags.HasFlag(CreatureStaticFlags.CanSwim))
|
||||
RemoveUnitFlag(UnitFlags.CanSwim);
|
||||
|
||||
UpdateMovementCapabilities();
|
||||
}
|
||||
|
||||
public void UpdateMovementFlags()
|
||||
public void UpdateMovementCapabilities()
|
||||
{
|
||||
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
|
||||
if (m_playerMovingMe != null)
|
||||
return;
|
||||
|
||||
// Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
|
||||
if (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoMoveFlagsUpdate))
|
||||
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 = (MathFunctions.fuzzyGt(GetPositionZ(), ground + (canHover ? m_unitData.HoverHeight : 0.0f) + MapConst.GroundHeightTolerance) || MathFunctions.fuzzyLt(GetPositionZ(), ground - MapConst.GroundHeightTolerance)); // 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(AuraType.Hover) && GetMovementTemplate().Ground != CreatureGroundMovementType.Hover)
|
||||
SetHover(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCanFly(false);
|
||||
SetDisableGravity(false);
|
||||
if (IsAlive() && (CanHover() || HasAuraType(AuraType.Hover)))
|
||||
SetHover(true);
|
||||
}
|
||||
|
||||
bool isInAir = (MathFunctions.fuzzyGt(GetPositionZ(), ground + GetHoverOffset() + MapConst.GroundHeightTolerance) || MathFunctions.fuzzyLt(GetPositionZ(), ground - MapConst.GroundHeightTolerance)); // Can be underground too, prevent the falling
|
||||
if (!isInAir)
|
||||
SetFall(false);
|
||||
|
||||
SetSwim(CanSwim() && IsInWater());
|
||||
// Some Amphibious creatures toggle swimming while engaged
|
||||
if (IsAmphibious() && !HasUnitFlag(UnitFlags.CantSwim) && !HasUnitFlag(UnitFlags.CanSwim))
|
||||
if (!IsSwimPrevented() || (GetVictim() != null && !GetVictim().IsOnOceanFloor()))
|
||||
SetUnitFlag(UnitFlags.CanSwim);
|
||||
|
||||
SetSwim(IsInWater() && CanSwim());
|
||||
}
|
||||
|
||||
public CreatureMovementData GetMovementTemplate()
|
||||
@@ -2754,29 +2716,7 @@ namespace Game.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CanEnterWater()
|
||||
{
|
||||
if (CanSwim())
|
||||
return true;
|
||||
|
||||
return GetMovementTemplate().IsSwimAllowed();
|
||||
}
|
||||
|
||||
public void RefreshCanSwimFlag(bool recheck = false)
|
||||
{
|
||||
if (!_isMissingCanSwimFlagOutOfCombat || recheck)
|
||||
_isMissingCanSwimFlagOutOfCombat = !HasUnitFlag(UnitFlags.CanSwim);
|
||||
|
||||
// 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(UnitFlags.CanSwim);
|
||||
}
|
||||
|
||||
public bool HasCanSwimFlagOutOfCombat()
|
||||
{
|
||||
return !_isMissingCanSwimFlagOutOfCombat;
|
||||
}
|
||||
public override bool CanEnterWater() { return CanSwim() || IsAmphibious(); }
|
||||
|
||||
public void AllLootRemovedFromCorpse()
|
||||
{
|
||||
@@ -3384,9 +3324,28 @@ namespace Game.Entities
|
||||
return GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.Guard);
|
||||
}
|
||||
|
||||
public bool CanWalk() { return GetMovementTemplate().IsGroundAllowed(); }
|
||||
public override bool CanFly() { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
|
||||
bool CanHover() { return GetMovementTemplate().Ground == CreatureGroundMovementType.Hover || IsHovering(); }
|
||||
// Returns true if CREATURE_STATIC_FLAG_AQUATIC is set which strictly binds the creature to liquids
|
||||
public bool IsAquatic() { return _staticFlags.HasFlag(CreatureStaticFlags.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
|
||||
public bool IsAmphibious() { return _staticFlags.HasFlag(CreatureStaticFlags.Amphibious); }
|
||||
|
||||
// Returns true if CREATURE_STATIC_FLAG_FLOATING is set which is disabling the gravity of the creature on spawn and reset
|
||||
public bool IsFloating() { return _staticFlags.HasFlag(CreatureStaticFlags.Floating); }
|
||||
|
||||
// Returns true if CREATURE_STATIC_FLAG_SESSILE is set which permanently roots the creature in place
|
||||
public bool IsSessile() { return _staticFlags.HasFlag(CreatureStaticFlags.Sessile); }
|
||||
|
||||
// Returns true if CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER is set which does not allow the creature to go below liquid surfaces
|
||||
public bool CannotPenetrateWater() { return _staticFlags.HasFlag(CreatureStaticFlags3.CannotPenetrateWater); }
|
||||
|
||||
// Returns true if CREATURE_STATIC_FLAG_3_CANNOT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged
|
||||
public bool IsSwimDisabled() { return _staticFlags.HasFlag(CreatureStaticFlags3.CannotSwim); }
|
||||
|
||||
// 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
|
||||
public bool IsSwimPrevented() { return _staticFlags.HasFlag(CreatureStaticFlags4.PreventSwim); }
|
||||
|
||||
public override bool CanFly() { return IsFlying() || HasUnitMovementFlag(MovementFlag.CanFly); }
|
||||
|
||||
public bool IsDungeonBoss() { return (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.DungeonBoss)); }
|
||||
public override bool IsAffectedByDiminishingReturns() { return base.IsAffectedByDiminishingReturns() || GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.AllDiminish); }
|
||||
|
||||
@@ -279,38 +279,28 @@ namespace Game.Entities
|
||||
|
||||
public class CreatureMovementData
|
||||
{
|
||||
public CreatureGroundMovementType Ground;
|
||||
public CreatureFlightMovementType Flight;
|
||||
public bool Swim;
|
||||
public bool Rooted;
|
||||
public bool HoverInitiallyEnabled;
|
||||
public CreatureChaseMovementType Chase;
|
||||
public CreatureRandomMovementType Random;
|
||||
public uint InteractionPauseTimer;
|
||||
|
||||
public CreatureMovementData()
|
||||
{
|
||||
Ground = CreatureGroundMovementType.Run;
|
||||
Flight = CreatureFlightMovementType.None;
|
||||
Swim = true;
|
||||
Rooted = false;
|
||||
Chase = CreatureChaseMovementType.Run;
|
||||
Random = CreatureRandomMovementType.Walk;
|
||||
InteractionPauseTimer = WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer);
|
||||
}
|
||||
|
||||
public bool IsGroundAllowed() { return Ground != CreatureGroundMovementType.None; }
|
||||
public bool IsSwimAllowed() { return Swim; }
|
||||
public bool IsFlightAllowed() { return Flight != CreatureFlightMovementType.None; }
|
||||
public bool IsRooted() { return Rooted; }
|
||||
|
||||
public CreatureChaseMovementType GetChase() { return Chase; }
|
||||
public CreatureRandomMovementType GetRandom() { return Random; }
|
||||
|
||||
public bool IsHoverInitiallyEnabled() { return HoverInitiallyEnabled; }
|
||||
|
||||
public uint GetInteractionPauseTimer() { return InteractionPauseTimer; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Ground: {Ground}, Swim: {Swim}, Flight: {Flight} {(Rooted ? ", Rooted" : "")}, Chase: {Chase}, Random: {Random}, InteractionPauseTimer: {InteractionPauseTimer}";
|
||||
return $"HoverInitiallyEnabled: {HoverInitiallyEnabled}, Chase: {Chase}, Random: {Random}, InteractionPauseTimer: {InteractionPauseTimer}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3752,7 +3752,18 @@ namespace Game.Entities
|
||||
|
||||
public float GetMapWaterOrGroundLevel(float x, float y, float z, ref float ground)
|
||||
{
|
||||
return GetMap().GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ref ground, IsTypeMask(TypeMask.Unit) ? !ToUnit().HasAuraType(AuraType.WaterWalk) : false, GetCollisionHeight());
|
||||
bool swimming = true;
|
||||
Creature creature = ToCreature();
|
||||
if (creature != null)
|
||||
swimming = !creature.CannotPenetrateWater() && !creature.HasAuraType(AuraType.WaterWalk);
|
||||
else
|
||||
{
|
||||
Unit unit = ToUnit();
|
||||
if (unit != null)
|
||||
swimming = !unit.HasAuraType(AuraType.WaterWalk);
|
||||
}
|
||||
|
||||
return GetMap().GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ref ground, swimming, GetCollisionHeight());
|
||||
}
|
||||
|
||||
public float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = MapConst.DefaultHeightSearch)
|
||||
|
||||
@@ -750,7 +750,7 @@ namespace Game.Entities
|
||||
SendMessageToSet(packet, true);
|
||||
}
|
||||
|
||||
if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UnitState.Root) && !ToCreature().IsTemplateRooted())
|
||||
if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UnitState.Root))
|
||||
{
|
||||
if (IsGravityDisabled())
|
||||
SetAnimTier(AnimTier.Fly);
|
||||
@@ -1138,7 +1138,7 @@ namespace Game.Entities
|
||||
SendMessageToSet(packet, true);
|
||||
}
|
||||
|
||||
if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UnitState.Root) && !ToCreature().IsTemplateRooted())
|
||||
if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UnitState.Root))
|
||||
{
|
||||
if (IsGravityDisabled())
|
||||
SetAnimTier(AnimTier.Fly);
|
||||
@@ -1186,12 +1186,25 @@ namespace Game.Entities
|
||||
{
|
||||
return IsWithinDistInMap(target, distance) && !HasInArc(MathFunctions.TwoPi - arc, target);
|
||||
}
|
||||
public bool IsInAccessiblePlaceFor(Creature c)
|
||||
public bool IsInAccessiblePlaceFor(Creature creature)
|
||||
{
|
||||
if (IsInWater())
|
||||
return c.CanEnterWater();
|
||||
else
|
||||
return c.CanWalk() || c.CanFly();
|
||||
// Aquatic creatures are not allowed to leave liquids
|
||||
if (!IsInWater() && creature.IsAquatic())
|
||||
return false;
|
||||
|
||||
// Underwater special case. Some creatures may not go below liquid surfaces
|
||||
if (IsUnderWater() && creature.CannotPenetrateWater())
|
||||
return false;
|
||||
|
||||
// Water checks
|
||||
if (IsInWater() && !creature.CanEnterWater())
|
||||
return false;
|
||||
|
||||
// Some creatures are tied to the ocean floor and cannot chase swimming targets.
|
||||
if (!IsOnOceanFloor() && creature.IsUnderWater() && creature.HasUnitFlag(UnitFlags.CantSwim))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false) { NearTeleportTo(new Position(x, y, z, orientation), casting); }
|
||||
@@ -1274,7 +1287,7 @@ namespace Game.Entities
|
||||
SetStunned(false);
|
||||
break;
|
||||
case UnitState.Root:
|
||||
if (HasAuraType(AuraType.ModRoot) || HasAuraType(AuraType.ModRoot2) || HasAuraType(AuraType.ModRootDisableGravity) || GetVehicle() != null || (IsCreature() && ToCreature().IsTemplateRooted()))
|
||||
if (HasAuraType(AuraType.ModRoot) || HasAuraType(AuraType.ModRoot2) || HasAuraType(AuraType.ModRootDisableGravity) || GetVehicle() != null || (IsCreature() && ToCreature().IsSessile()))
|
||||
return;
|
||||
|
||||
ClearUnitState(state);
|
||||
|
||||
@@ -412,10 +412,6 @@ namespace Game.Entities
|
||||
|
||||
AddUnitState(UnitState.Charmed);
|
||||
|
||||
Creature creature = ToCreature();
|
||||
if (creature != null)
|
||||
creature.RefreshCanSwimFlag();
|
||||
|
||||
if (!IsPlayer() || !charmer.IsPlayer())
|
||||
{
|
||||
// AI will schedule its own change if appropriate
|
||||
|
||||
Reference in New Issue
Block a user