diff --git a/Source/Framework/Constants/MapConst.cs b/Source/Framework/Constants/MapConst.cs index 917909dfe..9411e8a2f 100644 --- a/Source/Framework/Constants/MapConst.cs +++ b/Source/Framework/Constants/MapConst.cs @@ -121,6 +121,7 @@ namespace Framework.Constants WaterWalk = 0x02, InWater = 0x04, UnderWater = 0x08, + OceanFloor = 0x10, Swimming = InWater | UnderWater, InContact = Swimming | WaterWalk diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 66378f3d6..f3dad1b78 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -21,21 +21,31 @@ namespace Game.Entities { return m_movementInfo.HasMovementFlag(MovementFlag.DisableGravity); } + public bool IsWalking() { return m_movementInfo.HasMovementFlag(MovementFlag.Walking); } + public bool IsHovering() { return m_movementInfo.HasMovementFlag(MovementFlag.Hover); } + public bool IsStopped() { return !HasUnitState(UnitState.Moving); } + public bool IsMoving() { return m_movementInfo.HasMovementFlag(MovementFlag.MaskMoving); } + public bool IsTurning() { return m_movementInfo.HasMovementFlag(MovementFlag.MaskTurning); } + public virtual bool CanFly() { return false; } + public bool IsFlying() { return m_movementInfo.HasMovementFlag(MovementFlag.Flying | MovementFlag.DisableGravity); } + public bool IsFalling() { return m_movementInfo.HasMovementFlag(MovementFlag.Falling | MovementFlag.FallingFar) || MoveSpline.IsFalling(); } + public virtual bool CanEnterWater() { return false; } + public virtual bool CanSwim() { // Mirror client behavior, if this method returns false then client will not use swimming animation and for players will apply gravity as if there was no water @@ -50,15 +60,22 @@ namespace Game.Entities return HasUnitFlag(UnitFlags.Rename | UnitFlags.CanSwim); } + public bool IsInWater() { return GetLiquidStatus().HasAnyFlag(ZLiquidStatus.InWater | ZLiquidStatus.UnderWater); } + public bool IsUnderWater() { return GetLiquidStatus().HasFlag(ZLiquidStatus.UnderWater); } + public bool IsOnOceanFloor() + { + return GetLiquidStatus().HasFlag(ZLiquidStatus.OceanFloor); + } + void PropagateSpeedChange() { GetMotionMaster().PropagateSpeedChange(); } public float GetSpeed(UnitMoveType mtype) @@ -141,7 +158,7 @@ namespace Game.Entities { return MovementGeneratorType.Idle; } - + public void StopMoving() { ClearUnitState(UnitState.Moving); @@ -234,7 +251,7 @@ namespace Game.Entities //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST); init.Launch(); } - + public void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false) { var initializer = (MoveSplineInit init) => @@ -352,7 +369,7 @@ namespace Game.Entities { // Temporarily disabled for short lived auras that unapply before client had time to ACK applying //if (enable == HasUnitMovementFlag2(MovementFlag2.CanTurnWhileFalling)) - //return false; + //return false; if (enable) AddUnitMovementFlag2(MovementFlag2.CanTurnWhileFalling); @@ -680,7 +697,7 @@ namespace Game.Entities { return HasUnitMovementFlag(MovementFlag.Hover) ? m_unitData.HoverHeight : 0.0f; } - + public bool IsWithinBoundaryRadius(Unit obj) { if (obj == null || !IsInMap(obj) || !InSamePhase(obj)) @@ -870,9 +887,9 @@ namespace Game.Entities if (!HasAura(capability.ModSpellAuraID)) CastSpell(this, capability.ModSpellAuraID, new CastSpellExtraArgs(aurEff)); } + } } - } - + public override void ProcessPositionDataChanged(PositionFullTerrainStatus data) { ZLiquidStatus oldLiquidStatus = GetLiquidStatus(); @@ -1037,7 +1054,7 @@ namespace Game.Entities { // Temporarily disabled for short lived auras that unapply before client had time to ACK applying //if (enable == HasUnitMovementFlag(MovementFlag.FallingSlow)) - //return false; + //return false; if (enable) AddUnitMovementFlag(MovementFlag.FallingSlow); @@ -1176,7 +1193,7 @@ namespace Game.Entities { WorldLocation target = new(GetMapId(), pos); ToPlayer().TeleportTo(target, (TeleportToOptions.NotLeaveTransport | TeleportToOptions.NotLeaveCombat | TeleportToOptions.NotUnSummonPet | (casting ? TeleportToOptions.Spell : 0))); - } + } else { SendTeleportPacket(pos); @@ -1680,7 +1697,7 @@ namespace Game.Entities } public bool IsPlayingHoverAnim() { return _playHoverAnim; } - + void SetPlayHoverAnim(bool enable, bool sendUpdate = true) { if (IsPlayingHoverAnim() == enable) @@ -1754,7 +1771,7 @@ namespace Game.Entities public bool HasExtraUnitMovementFlag2(MovementFlags3 f) { return m_movementInfo.HasExtraMovementFlag2(f); } public MovementFlags3 GetExtraUnitMovementFlags2() { return m_movementInfo.GetExtraMovementFlags2(); } public void SetExtraUnitMovementFlags2(MovementFlags3 f) { m_movementInfo.SetExtraMovementFlags2(f); } - + //Spline public bool IsSplineEnabled() { @@ -1791,7 +1808,7 @@ namespace Game.Entities if (animTier.HasValue) SetAnimTier(animTier.Value); } - + UpdateSplinePosition(); } diff --git a/Source/Game/Maps/GridMap.cs b/Source/Game/Maps/GridMap.cs index 21891863a..4b9e0acbf 100644 --- a/Source/Game/Maps/GridMap.cs +++ b/Source/Game/Maps/GridMap.cs @@ -463,7 +463,7 @@ namespace Game.Maps return (_holes[cellRow * 16 * 8 + cellCol * 8 + holeRow] & (1 << holeCol)) != 0; } - + public float GetMinHeight(float x, float y) { if (_minHeightPlanes == null) @@ -598,14 +598,20 @@ namespace Game.Maps // For speed check as int values float delta = liquid_level - z; + ZLiquidStatus status = ZLiquidStatus.AboveWater; // Above water + if (delta > collisionHeight) // Under water - return ZLiquidStatus.UnderWater; + status = ZLiquidStatus.UnderWater; if (delta > 0.0f) // In water - return ZLiquidStatus.InWater; + status = ZLiquidStatus.InWater; if (delta > -0.1f) // Walk on water - return ZLiquidStatus.WaterWalk; - // Above water - return ZLiquidStatus.AboveWater; + status = ZLiquidStatus.WaterWalk; + + if (status != ZLiquidStatus.AboveWater) + if (MathF.Abs(ground_level - z) <= MapConst.GroundHeightTolerance) + status |= ZLiquidStatus.OceanFloor; + + return status; } public float GetHeight(float x, float y) { return _gridGetHeight(x, y); } diff --git a/Source/Game/Maps/TerrainManager.cs b/Source/Game/Maps/TerrainManager.cs index 73198cdb0..a6b51be81 100644 --- a/Source/Game/Maps/TerrainManager.cs +++ b/Source/Game/Maps/TerrainManager.cs @@ -551,14 +551,19 @@ namespace Game.Maps data.LiquidInfo.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType); float delta = wmoData.liquidInfo.Value.Level - z; + ZLiquidStatus status = ZLiquidStatus.AboveWater; if (delta > collisionHeight) - data.LiquidStatus = ZLiquidStatus.UnderWater; + status = ZLiquidStatus.UnderWater; else if (delta > 0.0f) - data.LiquidStatus = ZLiquidStatus.InWater; + status = ZLiquidStatus.InWater; else if (delta > -0.1f) - data.LiquidStatus = ZLiquidStatus.WaterWalk; - else - data.LiquidStatus = ZLiquidStatus.AboveWater; + status = ZLiquidStatus.WaterWalk; + + if (status != ZLiquidStatus.AboveWater) + if (MathF.Abs(wmoData.floorZ - z) <= MapConst.GroundHeightTolerance) + status |= ZLiquidStatus.OceanFloor; + + data.LiquidStatus = status; } // look up liquid data from grid map if (gmap != null && useGridLiquid) @@ -636,13 +641,23 @@ namespace Game.Maps float delta = liquid_level - z; - // Get position delta + ZLiquidStatus status = ZLiquidStatus.AboveWater; // Above water + if (delta > collisionHeight) // Under water - return ZLiquidStatus.UnderWater; + status = ZLiquidStatus.UnderWater; if (delta > 0.0f) // In water - return ZLiquidStatus.InWater; + status = ZLiquidStatus.InWater; if (delta > -0.1f) // Walk on water - return ZLiquidStatus.WaterWalk; + status = ZLiquidStatus.WaterWalk; + + if (status != ZLiquidStatus.AboveWater) + { + if (MathF.Abs(ground_level - z) <= MapConst.GroundHeightTolerance) + status |= ZLiquidStatus.OceanFloor; + + return status; + } + result = ZLiquidStatus.AboveWater; } }