Пример #1
0
        NavTerrain GetNavTerrain(float x, float y, float z)
        {
            LiquidData    data;
            ZLiquidStatus liquidStatus = _sourceUnit.GetMap().getLiquidStatus(x, y, z, MapConst.MapAllLiquidTypes, out data);

            if (liquidStatus == ZLiquidStatus.NoWater)
            {
                return(NavTerrain.Ground);
            }

            switch (data.type_flags)
            {
            case MapConst.MapLiquidTypeWater:
            case MapConst.MapLiquidTypeOcean:
                return(NavTerrain.Water);

            case MapConst.MapLiquidTypeMagma:
                return(NavTerrain.Magma);

            case MapConst.MapLiquidTypeSlime:
                return(NavTerrain.Slime);

            default:
                return(NavTerrain.Ground);
            }
        }
Пример #2
0
        NavTerrainFlag GetNavTerrain(float x, float y, float z)
        {
            LiquidData    data;
            ZLiquidStatus liquidStatus = _sourceUnit.GetMap().getLiquidStatus(_sourceUnit.GetPhaseShift(), x, y, z, MapConst.MapAllLiquidTypes, out data);

            if (liquidStatus == ZLiquidStatus.NoWater)
            {
                return(NavTerrainFlag.Ground);
            }

            data.type_flags &= ~MapConst.MapLiquidTypeDarkWater;
            switch (data.type_flags)
            {
            case MapConst.MapLiquidTypeWater:
            case MapConst.MapLiquidTypeOcean:
                return(NavTerrainFlag.Water);

            case MapConst.MapLiquidTypeMagma:
            case MapConst.MapLiquidTypeSlime:
                return(NavTerrainFlag.MagmaSlime);

            default:
                return(NavTerrainFlag.Ground);
            }
        }
Пример #3
0
        void BuildPolyPath(Vector3 startPos, Vector3 endPos)
        {
            // *** getting start/end poly logic ***

            float distToStartPoly = 0;
            float distToEndPoly   = 0;

            float[] startPoint = { startPos.Y, startPos.Z, startPos.X };
            float[] endPoint   = { endPos.Y, endPos.Z, endPos.X };

            ulong startPoly = GetPolyByLocation(startPoint, ref distToStartPoly);
            ulong endPoly   = GetPolyByLocation(endPoint, ref distToEndPoly);

            // we have a hole in our mesh
            // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
            // its up to caller how he will use this info
            if (startPoly == 0 || endPoly == 0)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (startPoly == 0 || endPoly == 0)\n");
                BuildShortcut();
                bool path = _sourceUnit.IsTypeId(TypeId.Unit) && _sourceUnit.ToCreature().CanFly();

                bool waterPath = _sourceUnit.IsTypeId(TypeId.Unit) && _sourceUnit.ToCreature().CanSwim();
                if (waterPath)
                {
                    // Check both start and end points, if they're both in water, then we can *safely* let the creature move
                    for (uint i = 0; i < _pathPoints.Length; ++i)
                    {
                        ZLiquidStatus status = _sourceUnit.GetMap().getLiquidStatus(_pathPoints[i].X, _pathPoints[i].Y, _pathPoints[i].Z, MapConst.MapAllLiquidTypes);
                        // One of the points is not in the water, cancel movement.
                        if (status == ZLiquidStatus.NoWater)
                        {
                            waterPath = false;
                            break;
                        }
                    }
                }

                pathType = (path || waterPath) ? (PathType.Normal | PathType.NotUsingPath) : PathType.NoPath;
                return;
            }

            // we may need a better number here
            bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);

            if (farFromPoly)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . farFromPoly distToStartPoly={0:F3} distToEndPoly={1:F3}\n", distToStartPoly, distToEndPoly);

                bool buildShotrcut = false;
                if (_sourceUnit.IsTypeId(TypeId.Unit))
                {
                    Creature owner = _sourceUnit.ToCreature();

                    Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos;
                    if (_sourceUnit.GetMap().IsUnderWater(p.X, p.Y, p.Z))
                    {
                        Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . underWater case\n");
                        if (owner.CanSwim())
                        {
                            buildShotrcut = true;
                        }
                    }
                    else
                    {
                        Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . flying case\n");
                        if (owner.CanFly())
                        {
                            buildShotrcut = true;
                        }
                    }
                }

                if (buildShotrcut)
                {
                    BuildShortcut();
                    pathType = (PathType.Normal | PathType.NotUsingPath);
                    return;
                }
                else
                {
                    float[] closestPoint = new float[3];
                    // we may want to use closestPointOnPolyBoundary instead
                    bool posOverPoly = false;
                    if (Detour.dtStatusSucceed(_navMeshQuery.closestPointOnPoly(endPoly, endPoint, closestPoint, ref posOverPoly)))
                    {
                        Detour.dtVcopy(endPoint, closestPoint);
                        SetActualEndPosition(new Vector3(endPoint[2], endPoint[0], endPoint[1]));
                    }

                    pathType = PathType.Incomplete;
                }
            }

            // *** poly path generating logic ***

            // start and end are on same polygon
            // just need to move in straight line
            if (startPoly == endPoly)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (startPoly == endPoly)\n");

                BuildShortcut();

                _pathPolyRefs[0] = startPoly;
                _polyLength      = 1;

                pathType = farFromPoly ? PathType.Incomplete : PathType.Normal;
                Log.outDebug(LogFilter.Maps, "BuildPolyPath . path type {0}\n", pathType);
                return;
            }

            // look for startPoly/endPoly in current path
            /// @todo we can merge it with getPathPolyByPosition() loop
            bool startPolyFound = false;
            bool endPolyFound   = false;
            uint pathStartIndex = 0;
            uint pathEndIndex   = 0;

            if (_polyLength != 0)
            {
                for (; pathStartIndex < _polyLength; ++pathStartIndex)
                {
                    // here to carch few bugs
                    if (_pathPolyRefs[pathStartIndex] == 0)
                    {
                        Log.outError(LogFilter.Maps, "Invalid poly ref in BuildPolyPath. _polyLength: {0}, pathStartIndex: {1}," +
                                     " startPos: {2}, endPos: {3}, mapid: {4}", _polyLength, pathStartIndex, startPos, endPos, _sourceUnit.GetMapId());
                        break;
                    }

                    if (_pathPolyRefs[pathStartIndex] == startPoly)
                    {
                        startPolyFound = true;
                        break;
                    }
                }

                for (pathEndIndex = _polyLength - 1; pathEndIndex > pathStartIndex; --pathEndIndex)
                {
                    if (_pathPolyRefs[pathEndIndex] == endPoly)
                    {
                        endPolyFound = true;
                        break;
                    }
                }
            }

            if (startPolyFound && endPolyFound)
            {
                Log.outDebug(LogFilter.Maps, "BuildPolyPath : (startPolyFound && endPolyFound)\n");

                // we moved along the path and the target did not move out of our old poly-path
                // our path is a simple subpath case, we have all the data we need
                // just "cut" it out

                _polyLength = pathEndIndex - pathStartIndex + 1;
                Array.Copy(_pathPolyRefs, pathStartIndex, _pathPolyRefs, 0, _polyLength);
            }
            else if (startPolyFound && !endPolyFound)
            {
                Log.outDebug(LogFilter.Maps, "BuildPolyPath : (startPolyFound && !endPolyFound)\n");

                // we are moving on the old path but target moved out
                // so we have atleast part of poly-path ready

                _polyLength -= pathStartIndex;

                // try to adjust the suffix of the path instead of recalculating entire length
                // at given interval the target cannot get too far from its last location
                // thus we have less poly to cover
                // sub-path of optimal path is optimal

                // take ~80% of the original length
                /// @todo play with the values here
                uint prefixPolyLength = (uint)(_polyLength * 0.8f + 0.5f);
                Array.Copy(_pathPolyRefs, pathStartIndex, _pathPolyRefs, 0, prefixPolyLength);

                ulong suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];

                // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
                float[] suffixEndPoint = new float[3];
                bool    posOverPoly    = false;
                if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, ref posOverPoly)))
                {
                    // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
                    // try to recover by using prev polyref
                    --prefixPolyLength;
                    suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];
                    if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, ref posOverPoly)))
                    {
                        // suffixStartPoly is still invalid, error state
                        BuildShortcut();
                        pathType = PathType.NoPath;
                        return;
                    }
                }

                // generate suffix
                uint suffixPolyLength = 0;

                uint dtResult;
                if (_straightLine)
                {
                    float   hit       = 0;
                    float[] hitNormal = new float[3];

                    dtResult = _navMeshQuery.raycast(
                        suffixStartPoly,
                        suffixEndPoint,
                        endPoint,
                        _filter,
                        ref hit,
                        hitNormal,
                        _pathPolyRefs,
                        ref suffixPolyLength,
                        74 - (int)prefixPolyLength);

                    // raycast() sets hit to FLT_MAX if there is a ray between start and end
                    if (hit != float.MaxValue)
                    {
                        // the ray hit something, return no path instead of the incomplete one
                        pathType = PathType.NoPath;
                        return;
                    }
                }
                else
                {
                    dtResult = _navMeshQuery.findPath(
                        suffixStartPoly,    // start polygon
                        endPoly,            // end polygon
                        suffixEndPoint,     // start position
                        endPoint,           // end position
                        _filter,            // polygon search filter
                        _pathPolyRefs,
                        ref suffixPolyLength,
                        74 - (int)prefixPolyLength);
                }

                if (suffixPolyLength == 0 || Detour.dtStatusFailed(dtResult))
                {
                    // this is probably an error state, but we'll leave it
                    // and hopefully recover on the next Update
                    // we still need to copy our preffix
                    Log.outError(LogFilter.Maps, "{0}'s Path Build failed: 0 length path", _sourceUnit.GetGUID().ToString());
                }

                Log.outDebug(LogFilter.Maps, "m_polyLength={0} prefixPolyLength={1} suffixPolyLength={2} \n", _polyLength, prefixPolyLength, suffixPolyLength);

                // new path = prefix + suffix - overlap
                _polyLength = prefixPolyLength + suffixPolyLength - 1;
            }
            else
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (!startPolyFound && !endPolyFound)\n");

                // either we have no path at all . first run
                // or something went really wrong . we aren't moving along the path to the target
                // just generate new path

                // free and invalidate old path data
                Clear();

                uint dtResult;
                if (_straightLine)
                {
                    float   hit       = 0;
                    float[] hitNormal = new float[3];

                    dtResult = _navMeshQuery.raycast(
                        startPoly,
                        startPoint,
                        endPoint,
                        _filter,
                        ref hit,
                        hitNormal,
                        _pathPolyRefs,
                        ref _polyLength,
                        74);

                    // raycast() sets hit to FLT_MAX if there is a ray between start and end
                    if (hit != float.MaxValue)
                    {
                        // the ray hit something, return no path instead of the incomplete one
                        pathType = PathType.NoPath;
                        return;
                    }
                }
                else
                {
                    dtResult = _navMeshQuery.findPath(
                        startPoly,     // start polygon
                        endPoly,       // end polygon
                        startPoint,    // start position
                        endPoint,      // end position
                        _filter,       // polygon search filter
                        _pathPolyRefs, // [out] path
                        ref _polyLength,
                        74);           // max number of polygons in output path
                }

                if (_polyLength == 0 || Detour.dtStatusFailed(dtResult))
                {
                    // only happens if we passed bad data to findPath(), or navmesh is messed up
                    Log.outError(LogFilter.Maps, "{0}'s Path Build failed: 0 length path", _sourceUnit.GetGUID().ToString());
                    BuildShortcut();
                    pathType = PathType.NoPath;
                    return;
                }
            }

            // by now we know what type of path we can get
            if (_pathPolyRefs[_polyLength - 1] == endPoly && !pathType.HasAnyFlag(PathType.Incomplete))
            {
                pathType = PathType.Normal;
            }
            else
            {
                pathType = PathType.Incomplete;
            }

            // generate the point-path out of our up-to-date poly-path
            BuildPointPath(startPoint, endPoint);
        }
Пример #4
0
        public override void UpdateUnderwaterState(Map m, float x, float y, float z)
        {
            LiquidData    liquid_status;
            ZLiquidStatus res = m.getLiquidStatus(GetPhaseShift(), x, y, z, MapConst.MapAllLiquidTypes, out liquid_status);

            if (res == 0)
            {
                m_MirrorTimerFlags &= ~(PlayerUnderwaterState.InWater | PlayerUnderwaterState.InLava | PlayerUnderwaterState.InSlime | PlayerUnderwaterState.InDarkWater);
                if (_lastLiquid != null && _lastLiquid.SpellID != 0)
                {
                    RemoveAurasDueToSpell(_lastLiquid.SpellID);
                }

                _lastLiquid = null;
                return;
            }
            uint liqEntry = liquid_status.entry;

            if (liqEntry != 0)
            {
                LiquidTypeRecord liquid = CliDB.LiquidTypeStorage.LookupByKey(liqEntry);
                if (_lastLiquid != null && _lastLiquid.SpellID != 0 && _lastLiquid != liquid)
                {
                    RemoveAurasDueToSpell(_lastLiquid.SpellID);
                }

                if (liquid != null && liquid.SpellID != 0)
                {
                    if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater))
                    {
                        if (!HasAura(liquid.SpellID))
                        {
                            CastSpell(this, liquid.SpellID, true);
                        }
                    }
                    else
                    {
                        RemoveAurasDueToSpell(liquid.SpellID);
                    }
                }

                _lastLiquid = liquid;
            }
            else if (_lastLiquid != null && _lastLiquid.SpellID != 0)
            {
                RemoveAurasDueToSpell(_lastLiquid.SpellID);
                _lastLiquid = null;
            }


            // All liquids type - check under water position
            if (liquid_status.type_flags.HasAnyFlag <uint>(MapConst.MapLiquidTypeWater | MapConst.MapLiquidTypeOcean | MapConst.MapLiquidTypeMagma | MapConst.MapLiquidTypeSlime))
            {
                if (res.HasAnyFlag(ZLiquidStatus.UnderWater))
                {
                    m_MirrorTimerFlags |= PlayerUnderwaterState.InWater;
                }
                else
                {
                    m_MirrorTimerFlags &= ~PlayerUnderwaterState.InWater;
                }
            }

            // Allow travel in dark water on taxi or transport
            if (liquid_status.type_flags.HasAnyFlag <uint>(MapConst.MapLiquidTypeDarkWater) && !IsInFlight() && GetTransport() == null)
            {
                m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater;
            }
            else
            {
                m_MirrorTimerFlags &= ~PlayerUnderwaterState.InDarkWater;
            }

            // in lava check, anywhere in lava level
            if (liquid_status.type_flags.HasAnyFlag <uint>(MapConst.MapLiquidTypeMagma))
            {
                if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater | ZLiquidStatus.WaterWalk))
                {
                    m_MirrorTimerFlags |= PlayerUnderwaterState.InLava;
                }
                else
                {
                    m_MirrorTimerFlags &= ~PlayerUnderwaterState.InLava;
                }
            }
            // in slime check, anywhere in slime level
            if (liquid_status.type_flags.HasAnyFlag <uint>(MapConst.MapLiquidTypeSlime))
            {
                if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater | ZLiquidStatus.WaterWalk))
                {
                    m_MirrorTimerFlags |= PlayerUnderwaterState.InSlime;
                }
                else
                {
                    m_MirrorTimerFlags &= ~PlayerUnderwaterState.InSlime;
                }
            }
        }
Пример #5
0
        public override void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional <LiquidData> liquidData)
        {
            // process liquid auras using generic unit code
            base.ProcessTerrainStatusUpdate(status, liquidData);

            // player specific logic for mirror timers
            if (status != 0 && liquidData.HasValue)
            {
                // Breath bar state (under water in any liquid type)
                if (liquidData.Value.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.AllLiquids))
                {
                    if (status.HasAnyFlag(ZLiquidStatus.UnderWater))
                    {
                        m_MirrorTimerFlags |= PlayerUnderwaterState.InWater;
                    }
                    else
                    {
                        m_MirrorTimerFlags &= ~PlayerUnderwaterState.InWater;
                    }
                }

                // Fatigue bar state (if not on flight path or transport)
                if (liquidData.Value.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.DarkWater) && !IsInFlight() && !GetTransport())
                {
                    m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater;
                }
                else
                {
                    m_MirrorTimerFlags &= ~PlayerUnderwaterState.InDarkWater;
                }

                // Lava state (any contact)
                if (liquidData.Value.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.Magma))
                {
                    if (status.HasAnyFlag(ZLiquidStatus.InContact))
                    {
                        m_MirrorTimerFlags |= PlayerUnderwaterState.InLava;
                    }
                    else
                    {
                        m_MirrorTimerFlags &= ~PlayerUnderwaterState.InLava;
                    }
                }

                // Slime state (any contact)
                if (liquidData.Value.type_flags.HasAnyFlag(LiquidHeaderTypeFlags.Slime))
                {
                    if (status.HasAnyFlag(ZLiquidStatus.InContact))
                    {
                        m_MirrorTimerFlags |= PlayerUnderwaterState.InSlime;
                    }
                    else
                    {
                        m_MirrorTimerFlags &= ~PlayerUnderwaterState.InSlime;
                    }
                }
            }
            else
            {
                m_MirrorTimerFlags &= ~(PlayerUnderwaterState.InWater | PlayerUnderwaterState.InLava | PlayerUnderwaterState.InSlime | PlayerUnderwaterState.InDarkWater);
            }
        }