Esempio n. 1
0
        /// <summary>
        /// Finds an optimal position for using Monk Tempest Rush out of combat
        /// </summary>
        /// <returns></returns>
        internal static Vector3 FindTempestRushTarget()
        {
            Vector3 target = PlayerMover.LastMoveToTarget;
            Vector3 myPos  = ZetaDia.Me.Position;

            if (Trinity.CurrentTarget != null && NavHelper.CanRayCast(myPos, target))
            {
                target = Trinity.CurrentTarget.Position;
            }

            float distance = target.Distance2D(myPos);

            if (distance < 30f)
            {
                double direction = MathUtil.FindDirectionRadian(myPos, target);
                target = MathEx.GetPointAt(myPos, 40f, (float)direction);
            }

            return(target);
        }
        /// <summary>
        /// Special handling for whether or not we want to cache an object that's not in LoS
        /// </summary>
        /// <param name="c_diaObject"></param>
        /// <param name="AddToCache"></param>
        /// <returns></returns>
        private static bool RefreshStepIgnoreLoS(bool AddToCache = false)
        {
            try
            {
                if (CurrentCacheObject.Type == GObjectType.Item || CurrentCacheObject.Type == GObjectType.Gold)
                {
                    return(true);
                }

                if (!DataDictionary.AlwaysRaycastWorlds.Contains(Trinity.Player.WorldID))
                {
                    // Bounty Objectives should always be on the weight list
                    if (CurrentCacheObject.IsBountyObjective)
                    {
                        return(true);
                    }

                    // Quest Monsters should get LoS white-listed
                    if (CurrentCacheObject.IsQuestMonster)
                    {
                        return(true);
                    }

                    // Always LoS Units during events
                    if (CurrentCacheObject.Type == GObjectType.Unit && Player.InActiveEvent)
                    {
                        return(true);
                    }
                }
                // Everything except items and the current target
                if (CurrentCacheObject.RActorGuid != LastTargetRactorGUID && CurrentCacheObject.Type != GObjectType.Unknown)
                {
                    if (CurrentCacheObject.Distance < 95)
                    {
                        using (new PerformanceLogger("RefreshLoS.2"))
                        {
                            // Get whether or not this RActor has ever been in a path line with AllowWalk. If it hasn't, don't add to cache and keep rechecking
                            if (!CacheData.HasBeenRayCasted.TryGetValue(CurrentCacheObject.RActorGuid, out c_HasBeenRaycastable) || DataDictionary.AlwaysRaycastWorlds.Contains(Trinity.Player.WorldID))
                            {
                                if (CurrentCacheObject.Distance >= 1f && CurrentCacheObject.Distance <= 5f)
                                {
                                    c_HasBeenRaycastable = true;
                                    if (!CacheData.HasBeenRayCasted.ContainsKey(CurrentCacheObject.RActorGuid))
                                    {
                                        CacheData.HasBeenRayCasted.Add(CurrentCacheObject.RActorGuid, c_HasBeenRaycastable);
                                    }
                                }
                                else if (Settings.Combat.Misc.UseNavMeshTargeting)
                                {
                                    Vector3 myPos = new Vector3(Player.Position.X, Player.Position.Y, Player.Position.Z + 8f);
                                    Vector3 cPos  = new Vector3(CurrentCacheObject.Position.X, CurrentCacheObject.Position.Y, CurrentCacheObject.Position.Z + 8f);
                                    cPos = MathEx.CalculatePointFrom(cPos, myPos, CurrentCacheObject.Radius + 1f);

                                    if (Single.IsNaN(cPos.X) || Single.IsNaN(cPos.Y) || Single.IsNaN(cPos.Z))
                                    {
                                        cPos = CurrentCacheObject.Position;
                                    }

                                    if (!NavHelper.CanRayCast(myPos, cPos))
                                    {
                                        AddToCache      = false;
                                        c_IgnoreSubStep = "UnableToRayCast";
                                    }
                                    else
                                    {
                                        c_HasBeenRaycastable = true;
                                        if (!CacheData.HasBeenRayCasted.ContainsKey(CurrentCacheObject.RActorGuid))
                                        {
                                            CacheData.HasBeenRayCasted.Add(CurrentCacheObject.RActorGuid, c_HasBeenRaycastable);
                                        }
                                    }
                                }
                                else
                                {
                                    if (c_ZDiff > 14f)
                                    {
                                        AddToCache      = false;
                                        c_IgnoreSubStep = "LoS.ZDiff";
                                    }
                                    else
                                    {
                                        c_HasBeenRaycastable = true;
                                        if (!CacheData.HasBeenRayCasted.ContainsKey(CurrentCacheObject.RActorGuid))
                                        {
                                            CacheData.HasBeenRayCasted.Add(CurrentCacheObject.RActorGuid, c_HasBeenRaycastable);
                                        }
                                    }
                                }
                            }
                        }
                        using (new PerformanceLogger("RefreshLoS.3"))
                        {
                            // Get whether or not this RActor has ever been in "Line of Sight" (as determined by Demonbuddy). If it hasn't, don't add to cache and keep rechecking
                            if (!CacheData.HasBeenInLoS.TryGetValue(CurrentCacheObject.RActorGuid, out c_HasBeenInLoS) || DataDictionary.AlwaysRaycastWorlds.Contains(Trinity.Player.WorldID))
                            {
                                // Ignore units not in LoS except bosses
                                if (!CurrentCacheObject.IsBoss && !c_diaObject.InLineOfSight)
                                {
                                    AddToCache      = false;
                                    c_IgnoreSubStep = "NotInLoS";
                                }
                                else
                                {
                                    c_HasBeenInLoS = true;
                                    if (!CacheData.HasBeenInLoS.ContainsKey(CurrentCacheObject.RActorGuid))
                                    {
                                        CacheData.HasBeenInLoS.Add(CurrentCacheObject.RActorGuid, c_HasBeenInLoS);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        AddToCache      = false;
                        c_IgnoreSubStep = "LoS-OutOfRange";
                    }


                    // always set true for bosses nearby
                    if (CurrentCacheObject.IsBoss || CurrentCacheObject.IsQuestMonster || CurrentCacheObject.IsBountyObjective)
                    {
                        AddToCache      = true;
                        c_IgnoreSubStep = "";
                    }
                    // always take the current target even if not in LoS
                    if (CurrentCacheObject.RActorGuid == LastTargetRactorGUID)
                    {
                        AddToCache      = true;
                        c_IgnoreSubStep = "";
                    }
                }

                // Simple whitelist for LoS
                if (DataDictionary.LineOfSightWhitelist.Contains(CurrentCacheObject.ActorSNO))
                {
                    AddToCache      = true;
                    c_IgnoreSubStep = "";
                }
                // Always pickup Infernal Keys whether or not in LoS
                if (DataDictionary.ForceToItemOverrideIds.Contains(CurrentCacheObject.ActorSNO))
                {
                    AddToCache      = true;
                    c_IgnoreSubStep = "";
                }
            }
            catch (Exception ex)
            {
                AddToCache      = true;
                c_IgnoreSubStep = "IgnoreLoSException";
                Logger.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "{0}", ex);
            }
            return(AddToCache);
        }
Esempio n. 3
0
        private static void Monk_MaintainTempestRush()
        {
            if (!Monk_TempestRushReady())
            {
                return;
            }

            if (Player.IsInTown || Zeta.Bot.Logic.BrainBehavior.IsVendoring)
            {
                return;
            }

            if (TownRun.IsTryingToTownPortal())
            {
                return;
            }

            if (TimeSinceUse(SNOPower.Monk_TempestRush) > 150)
            {
                return;
            }

            bool shouldMaintain = false;
            bool nullTarget     = CurrentTarget == null;

            if (!nullTarget)
            {
                // maintain for everything except items, doors, interactables... stuff we have to "click" on
                switch (CurrentTarget.Type)
                {
                case GObjectType.Unit:
                case GObjectType.Gold:
                case GObjectType.Avoidance:
                case GObjectType.Barricade:
                case GObjectType.Destructible:
                case GObjectType.HealthGlobe:
                case GObjectType.PowerGlobe:
                {
                    if (Settings.Combat.Monk.TROption == TempestRushOption.TrashOnly &&
                        (TargetUtil.AnyElitesInRange(40f) || CurrentTarget.IsBossOrEliteRareUnique))
                    {
                        shouldMaintain = false;
                    }
                    else
                    {
                        shouldMaintain = true;
                    }
                }
                break;
                }
            }
            else
            {
                shouldMaintain = true;
            }

            if (Settings.Combat.Monk.TROption != TempestRushOption.MovementOnly && SNOPowerUseTimer(SNOPower.Monk_TempestRush) && shouldMaintain)
            {
                Vector3 target = LastTempestRushLocation;

                const string locationSource = "LastLocation";

                if (target.Distance2D(ZetaDia.Me.Position) <= 1f)
                {
                    // rrrix edit: we can't maintain here
                    return;
                }

                if (target == Vector3.Zero)
                {
                    return;
                }

                float DestinationDistance = target.Distance2D(ZetaDia.Me.Position);

                target = TargetUtil.FindTempestRushTarget();

                if (DestinationDistance > 10f && NavHelper.CanRayCast(ZetaDia.Me.Position, target))
                {
                    Monk_TempestRushStatus(String.Format("Using Tempest Rush to maintain channeling, source={0}, V3={1} dist={2:0}", locationSource, target, DestinationDistance));

                    var usePowerResult = ZetaDia.Me.UsePower(SNOPower.Monk_TempestRush, target, CurrentWorldDynamicId, -1);
                    if (usePowerResult)
                    {
                        CacheData.AbilityLastUsed[SNOPower.Monk_TempestRush] = DateTime.UtcNow;
                    }
                }
            }
        }
Esempio n. 4
0
        // Special Zig-Zag movement for whirlwind/tempest
        /// <summary>
        /// Finds an optimal position for Barbarian Whirlwind, Monk Tempest Rush, or Demon Hunter Strafe
        /// </summary>
        /// <param name="origin"></param>
        /// <param name="ringDistance"></param>
        /// <param name="randomizeDistance"></param>
        /// <returns></returns>
        internal static Vector3 GetZigZagTarget(Vector3 origin, float ringDistance, bool randomizeDistance = false)
        {
            var     minDistance      = 20f;
            Vector3 myPos            = Player.Position;
            float   distanceToTarget = origin.Distance2D(myPos);

            Vector3 zigZagPoint = origin;

            bool  useTargetBasedZigZag = false;
            float maxDistance          = 25f;
            int   minTargets           = 2;

            if (Trinity.Player.ActorClass == ActorClass.Monk)
            {
                maxDistance          = 20f;
                minTargets           = 3;
                useTargetBasedZigZag = Trinity.Settings.Combat.Monk.TargetBasedZigZag;
            }
            if (Trinity.Player.ActorClass == ActorClass.Barbarian)
            {
                useTargetBasedZigZag = Trinity.Settings.Combat.Barbarian.TargetBasedZigZag;
            }

            int  eliteCount         = ObjectCache.Count(u => u.IsUnit && u.IsBossOrEliteRareUnique);
            bool shouldZigZagElites = ((Trinity.CurrentTarget.IsBossOrEliteRareUnique && eliteCount > 1) || eliteCount == 0);

            if (useTargetBasedZigZag && shouldZigZagElites && !AnyTreasureGoblinsPresent && ObjectCache.Count(o => o.IsUnit) >= minTargets)
            {
                bool attackInAoe  = Trinity.Settings.Combat.Misc.KillMonstersInAoE;
                var  clusterPoint = TargetUtil.GetBestClusterPoint(ringDistance, ringDistance, false, attackInAoe);
                if (clusterPoint.Distance2D(Player.Position) >= minDistance)
                {
                    Logger.Log(LogCategory.Movement, "Returning ZigZag: BestClusterPoint {0} r-dist={1} t-dist={2}", clusterPoint, ringDistance, clusterPoint.Distance2D(Player.Position));
                    return(clusterPoint);
                }


                var zigZagTargetList = new List <TrinityCacheObject>();
                if (attackInAoe)
                {
                    zigZagTargetList =
                        (from u in ObjectCache
                         where u.IsUnit && u.Distance < maxDistance
                         select u).ToList();
                }
                else
                {
                    zigZagTargetList =
                        (from u in ObjectCache
                         where u.IsUnit && u.Distance < maxDistance && !UnitOrPathInAoE(u)
                         select u).ToList();
                }

                if (zigZagTargetList.Count() >= minTargets)
                {
                    zigZagPoint = zigZagTargetList.OrderByDescending(u => u.Distance).FirstOrDefault().Position;
                    if (NavHelper.CanRayCast(zigZagPoint) && zigZagPoint.Distance2D(Player.Position) >= minDistance)
                    {
                        Logger.Log(LogCategory.Movement, "Returning ZigZag: TargetBased {0} r-dist={1} t-dist={2}", zigZagPoint, ringDistance, zigZagPoint.Distance2D(Player.Position));
                        return(zigZagPoint);
                    }
                }
            }

            Random  rndNum             = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), NumberStyles.HexNumber));
            float   highestWeightFound = float.NegativeInfinity;
            Vector3 bestLocation       = origin;

            // the unit circle always starts at 0 :)
            double min = 0;
            // the maximum size of a unit circle
            double max = 2 * Math.PI;
            // the number of times we will iterate around the circle to find points
            double piSlices = 16;

            // We will do several "passes" to make sure we can get a point that we can least zig-zag to
            // The total number of points tested will be piSlices * distancePasses.Count
            List <float> distancePasses = new List <float>();

            distancePasses.Add(ringDistance * 1 / 2); // Do one loop at 1/2 distance
            distancePasses.Add(ringDistance * 3 / 4); // Do one loop at 3/4 distance
            distancePasses.Add(ringDistance);         // Do one loop at exact distance

            foreach (float distance in distancePasses)
            {
                for (double direction = min; direction < max; direction += (Math.PI / piSlices))
                {
                    // Starting weight is 1
                    float pointWeight = 1f;

                    // Find a new XY
                    zigZagPoint = MathEx.GetPointAt(origin, distance, (float)direction);
                    // Get the Z
                    zigZagPoint.Z = Trinity.MainGridProvider.GetHeight(zigZagPoint.ToVector2());

                    // Make sure we're actually zig-zagging our target, except if we're kiting

                    float targetCircle = CurrentTarget.Radius;
                    if (targetCircle <= 5f)
                    {
                        targetCircle = 5f;
                    }
                    if (targetCircle > 10f)
                    {
                        targetCircle = 10f;
                    }

                    bool intersectsPath = MathUtil.IntersectsPath(CurrentTarget.Position, targetCircle, myPos, zigZagPoint);
                    if (CombatBase.PlayerKiteDistance <= 0 && !intersectsPath)
                    {
                        continue;
                    }

                    // if we're kiting, lets not actualy run through monsters
                    if (CombatBase.PlayerKiteDistance > 0 && CacheData.MonsterObstacles.Any(m => m.Position.Distance(zigZagPoint) <= CombatBase.PlayerKiteDistance))
                    {
                        continue;
                    }

                    // Ignore point if any AoE in this point position
                    if (CacheData.TimeBoundAvoidance.Any(m => m.Position.Distance(zigZagPoint) <= m.Radius && Player.CurrentHealthPct <= AvoidanceManager.GetAvoidanceHealthBySNO(m.ActorSNO, 1)))
                    {
                        continue;
                    }

                    // Make sure this point is in LoS/walkable (not around corners or into a wall)
                    bool canRayCast = !Navigator.Raycast(Player.Position, zigZagPoint);
                    if (!canRayCast)
                    {
                        continue;
                    }

                    float distanceToPoint           = zigZagPoint.Distance2D(myPos);
                    float distanceFromTargetToPoint = zigZagPoint.Distance2D(origin);

                    // Lots of weight for points further away from us (e.g. behind our CurrentTarget)
                    pointWeight *= distanceToPoint;

                    // Add weight for any units in this point
                    int monsterCount = ObjectCache.Count(u => u.IsUnit && u.Position.Distance2D(zigZagPoint) <= Math.Max(u.Radius, 10f));
                    if (monsterCount > 0)
                    {
                        pointWeight *= monsterCount;
                    }

                    //Logger.Log(LogCategory.Movement, "ZigZag Point: {0} distance={1:0} distaceFromTarget={2:0} intersectsPath={3} weight={4:0} monsterCount={5}",
                    //    zigZagPoint, distanceToPoint, distanceFromTargetToPoint, intersectsPath, pointWeight, monsterCount);

                    // Use this one if it's more weight, or we haven't even found one yet, or if same weight as another with a random chance
                    if (pointWeight > highestWeightFound)
                    {
                        highestWeightFound = pointWeight;

                        if (Trinity.Settings.Combat.Misc.UseNavMeshTargeting)
                        {
                            bestLocation = new Vector3(zigZagPoint.X, zigZagPoint.Y, Trinity.MainGridProvider.GetHeight(zigZagPoint.ToVector2()));
                        }
                        else
                        {
                            bestLocation = new Vector3(zigZagPoint.X, zigZagPoint.Y, zigZagPoint.Z + 4);
                        }
                    }
                }
            }
            Logger.Log(LogCategory.Movement, "Returning ZigZag: RandomXY {0} r-dist={1} t-dist={2}", bestLocation, ringDistance, bestLocation.Distance2D(Player.Position));
            return(bestLocation);
        }