public static RunStatus MoveToNearestMarker(Vector3 near) { if (SkipAheadCache.bSkipAheadAGo) { SkipAheadCache.RecordSkipAheadCachePoint(); } lastMoveResult = Navigator.MoveTo(GetNearestUnvisitedMarker(near).Position); //DbHelper.Logger.DBLog.InfoFormat(TrinityLogLevel.Normal, LogCategory.ProfileTag, "Moving to inspect nameHash {0} at {1} distance {2:0} mr: {3}", //m.MarkerNameHash, m.Position, ZetaDia.Me.Position.Distance2D(m.Position), lastMoveResult); return(RunStatus.Success); }
private RunStatus GilesMoveToLocation(object ret) { // First check if we can skip ahead because we recently moved here if (NoSkip == null || NoSkip.ToLower() != "true") { if (SkipAheadCache.CheckPositionForSkipping(Position)) { Logger.DBLog.DebugFormat("Finished Path {0} earlier due to SkipAreaCache find!", Position.ToString()); skippingAhead = true; } if (skippingAhead) { m_IsDone = true; return(RunStatus.Success); } } // Now use Trinity movement to try a direct movement towards that location var NavTarget = Position; var MyPos = Bot.Character.Data.Position; if (!ZetaDia.WorldInfo.IsGenerated && Vector3.Distance(MyPos, NavTarget) > 250) { NavTarget = MathEx.CalculatePointFrom(MyPos, NavTarget, Vector3.Distance(MyPos, NavTarget) - 250); } if (useNavigator != null && useNavigator.ToLower() == "false") { Navigator.PlayerMover.MoveTowards(NavTarget); } else { //Special cache for skipping locations visited. if (Bot.Settings.Debug.SkipAhead) { SkipAheadCache.RecordSkipAheadCachePoint(PathPrecision); } Navigator.MoveTo(NavTarget); } return(RunStatus.Success); }
internal RunStatus TargetMoveTo(CacheObject obj) { #region DebugInfo if (Bot.Settings.Debug.DebugStatusBar) { string Action = "[Move-"; switch (obj.targetType.Value) { case TargetType.Avoidance: Action += "Avoid] "; break; case TargetType.Fleeing: Action += "Flee] "; break; case TargetType.Backtrack: Action += "BackTrack] "; break; case TargetType.LineOfSight: Action += "LOS] "; break; case TargetType.Unit: if (Bot.NavigationCache.groupRunningBehavior && Bot.NavigationCache.groupingCurrentUnit != null && Bot.NavigationCache.groupingCurrentUnit == obj) { Action += "Grouping] "; } else { Action += "Combat] "; } break; case TargetType.Item: case TargetType.Gold: case TargetType.Globe: Action += "Pickup] "; break; case TargetType.Interactable: Action += "Interact] "; break; case TargetType.Container: Action += "Open] "; break; case TargetType.Destructible: case TargetType.Barricade: Action += "Destroy] "; break; case TargetType.Shrine: Action += "Click] "; break; } Bot.Targeting.Handler.UpdateStatusText(Action); } #endregion // Are we currently incapacitated? If so then wait... if (Bot.Character.Data.bIsIncapacitated || Bot.Character.Data.bIsRooted) { return(RunStatus.Running); } //Ignore skip ahead cache for LOS movements.. if (Bot.Settings.Debug.SkipAhead && obj.targetType.Value != TargetType.LineOfSight) { SkipAheadCache.RecordSkipAheadCachePoint(); } // Some stuff to avoid spamming usepower EVERY loop, and also to detect stucks/staying in one place for too long bool bForceNewMovement = false; //Herbfunk: Added this to prevent stucks attempting to move to a target blocked. (Case: 3 champs behind a wall, within range but could not engage due to being on the other side.) #region Non Movement Counter Reached if (NonMovementCounter > Bot.Settings.Plugin.MovementNonMovementCount) { Logger.Write(LogLevel.Movement, "non movement counter reached {0}", NonMovementCounter); if (obj.Actortype.HasValue && obj.Actortype.Value.HasFlag(ActorType.Item)) { if (NonMovementCounter > 250) { //Are we stuck? if (!Navigation.MGP.CanStandAt(Bot.Character.Data.Position)) { Logger.DBLog.InfoFormat("Character is stuck inside non-standable location.. attempting townportal cast.."); ZetaDia.Me.UseTownPortal(); NonMovementCounter = 0; return(RunStatus.Running); } } //Check if we can walk to this location from current location.. if (!Navigation.CanRayCast(Bot.Character.Data.Position, CurrentTargetLocation, UseSearchGridProvider: true)) { obj.RequiresLOSCheck = true; obj.BlacklistLoops = 50; Logger.Write(LogLevel.Movement, "Ignoring Item {0} -- due to RayCast Failure!", obj.InternalName); Bot.Targeting.Cache.bForceTargetUpdate = true; return(RunStatus.Running); } } else if (ObjectCache.CheckTargetTypeFlag(obj.targetType.Value, TargetType.LineOfSight | TargetType.Backtrack)) { Logger.Write(LogLevel.Movement, "Line of Sight Movement Stalled!"); Bot.NavigationCache.LOSmovementObject = null; Bot.Targeting.Cache.bForceTargetUpdate = true; NonMovementCounter = 0; // Reset the emergency loop counter and return success return(RunStatus.Running); } else { Logger.Write(LogLevel.Movement, "Ignoring obj {0} ", obj.InternalName + " _ SNO:" + obj.SNOID); obj.BlacklistLoops = 50; obj.RequiresLOSCheck = true; Bot.Targeting.Cache.bForceTargetUpdate = true; NonMovementCounter = 0; // Reset the emergency loop counter and return success return(RunStatus.Running); } } #endregion //update misc movement info (rotation, state, flags, etc) Bot.NavigationCache.RefreshMovementCache(); //Do a priority check for nearby obstacle objects. Bot.NavigationCache.ObstaclePrioritizeCheck(15f); #region Evaluate Last Action // Position didn't change last update.. check if we are stuck! if (DateTime.Now.Subtract(lastPositionChange).TotalMilliseconds > 150 && (!Bot.NavigationCache.IsMoving || Bot.NavigationCache.currentMovementState == MovementState.WalkingInPlace || Bot.NavigationCache.currentMovementState.Equals(MovementState.None))) { bForceNewMovement = true; if (DateTime.Now.Subtract(LastMovementDuringCombat).TotalMilliseconds >= 250) { LastMovementDuringCombat = DateTime.Now; BlockedMovementCounter++; // Tell target finder to prioritize close-combat targets incase we were bodyblocked #region TargetingPriortize switch (BlockedMovementCounter) { case 2: case 3: if (Bot.NavigationCache.groupRunningBehavior) { Logger.Write(LogLevel.Movement, "Grouping Behavior stopped due to blocking counter"); Bot.NavigationCache.GroupingFinishBehavior(); Bot.NavigationCache.groupingSuspendedDate = DateTime.Now.AddMilliseconds(4000); Bot.Targeting.Cache.bForceTargetUpdate = true; return(RunStatus.Running); } if (!ObjectCache.CheckTargetTypeFlag(obj.targetType.Value, TargetType.AvoidanceMovements)) { //Finally try raycasting to see if navigation is possible.. if (obj.Actortype.HasValue && (obj.Actortype.Value == ActorType.Gizmo || obj.Actortype.Value == ActorType.Monster)) { Vector3 hitTest; // No raycast available, try and force-ignore this for a little while, and blacklist for a few seconds if (Navigator.Raycast(Bot.Character.Data.Position, obj.Position, out hitTest)) { if (hitTest != Vector3.Zero) { obj.RequiresLOSCheck = true; obj.BlacklistLoops = 10; Logger.Write(LogLevel.Movement, "Ignoring object " + obj.InternalName + " due to not moving and raycast failure!", true); Bot.Targeting.Cache.bForceTargetUpdate = true; return(RunStatus.Running); } } } else if (obj.targetType.Value == TargetType.Item) { obj.BlacklistLoops = 10; Bot.Targeting.Cache.bForceTargetUpdate = true; } } else { if (!Navigation.CanRayCast(Bot.Character.Data.Position, CurrentTargetLocation, NavCellFlags.AllowWalk)) { Logger.Write(LogLevel.Movement, "Cannot continue with avoidance movement due to raycast failure!"); BlockedMovementCounter = 0; Bot.NavigationCache.CurrentGPArea.BlacklistLastSafespot(); Bot.NavigationCache.vlastSafeSpot = Vector3.Zero; Bot.Targeting.Cache.bForceTargetUpdate = true; return(RunStatus.Running); } } break; } #endregion return(RunStatus.Running); } } else { // Movement has been made, so count the time last moved! LastMovementDuringCombat = DateTime.Now; } #endregion // See if we want to ACTUALLY move, or are just waiting for the last move command... if (!bForceNewMovement && IsAlreadyMoving && CurrentTargetLocation == LastTargetLocation && DateTime.Now.Subtract(LastMovementCommand).TotalMilliseconds <= 100) { return(RunStatus.Running); } // If we're doing avoidance, globes or backtracking, try to use special abilities to move quicker #region SpecialMovementChecks if (ObjectCache.CheckTargetTypeFlag(obj.targetType.Value, Bot.Settings.Combat.CombatMovementTargetTypes)) { Skill MovementPower; Vector3 MovementVector = Bot.Character.Class.FindCombatMovementPower(out MovementPower, obj.Position); if (MovementVector != Vector3.Zero) { ZetaDia.Me.UsePower(MovementPower.Power, MovementVector, Bot.Character.Data.iCurrentWorldID, -1); MovementPower.OnSuccessfullyUsed(); // Store the current destination for comparison incase of changes next loop LastTargetLocation = CurrentTargetLocation; // Reset total body-block count, since we should have moved //if (DateTime.Now.Subtract(Bot.Targeting.Cache.Environment.lastForcedKeepCloseRange).TotalMilliseconds>=2000) BlockedMovementCounter = 0; return(RunStatus.Running); } //Special Whirlwind Code if (Bot.Character.Class.AC == ActorClass.Barbarian && Bot.Character.Class.HotBar.HotbarPowers.Contains(SNOPower.Barbarian_Whirlwind)) { // Whirlwind against everything within range (except backtrack points) if (Bot.Character.Data.dCurrentEnergy >= 10 && Bot.Targeting.Cache.Environment.iAnythingWithinRange[(int)RangeIntervals.Range_20] >= 1 && obj.DistanceFromTarget <= 12f && (!Bot.Character.Class.HotBar.HotbarPowers.Contains(SNOPower.Barbarian_Sprint) || Bot.Character.Class.HotBar.HasBuff(SNOPower.Barbarian_Sprint)) && (ObjectCache.CheckTargetTypeFlag(obj.targetType.Value, TargetType.AvoidanceMovements | TargetType.Gold | TargetType.Globe) == false) && (obj.targetType.Value != TargetType.Unit || (obj.targetType.Value == TargetType.Unit && !obj.IsTreasureGoblin && (!Bot.Settings.Class.bSelectiveWhirlwind || Bot.Targeting.Cache.Environment.bAnyNonWWIgnoreMobsInRange || !CacheIDLookup.hashActorSNOWhirlwindIgnore.Contains(obj.SNOID))))) { // Special code to prevent whirlwind double-spam, this helps save fury bool bUseThisLoop = SNOPower.Barbarian_Whirlwind != Bot.Character.Class.LastUsedAbility.Power; if (!bUseThisLoop) { if (Bot.Character.Class.Abilities[SNOPower.Barbarian_Whirlwind].LastUsedMilliseconds >= 200) { bUseThisLoop = true; } } if (bUseThisLoop) { ZetaDia.Me.UsePower(SNOPower.Barbarian_Whirlwind, CurrentTargetLocation, Bot.Character.Data.iCurrentWorldID); Bot.Character.Class.Abilities[SNOPower.Barbarian_Whirlwind].OnSuccessfullyUsed(); } // Store the current destination for comparison incase of changes next loop LastTargetLocation = CurrentTargetLocation; BlockedMovementCounter = 0; return(RunStatus.Running); } } } #endregion // Now for the actual movement request stuff IsAlreadyMoving = true; UseTargetMovement(obj, bForceNewMovement); // Store the current destination for comparison incase of changes next loop LastMovementAttempted = DateTime.Now; LastTargetLocation = CurrentTargetLocation; //Check if we moved at least 5f.. if (LastPlayerLocation.Distance(Bot.Character.Data.Position) <= 5f) { NonMovementCounter++; } else { NonMovementCounter = 0; BlockedMovementCounter = 0; } //store player location LastPlayerLocation = Bot.Character.Data.Position; return(RunStatus.Running); }
public void MoveTowards(Vector3 vMoveToTarget) { if (Bot.Character.Class == null) { Logger.DBLog.InfoFormat("Bot did not properly initilize, stopping bot!"); BotMain.Stop(false, "Bot Init Failure"); return; } #region LogStucks // The below code is to help profile/routine makers avoid waypoints with a long distance between them. // Long-distances between waypoints is bad - it increases stucks, and forces the DB nav-server to be called. //if (vLastMoveTo==Vector3.Zero) vLastMoveTo=vMoveToTarget; if (vMoveToTarget != vLastMoveTo) { vLastMoveTo = vMoveToTarget; if (Bot.Settings.Debug.LogStuckLocations) { vLastMoveTo = vMoveToTarget; bLastWaypointWasTown = false; float fDistance = Vector3.Distance(vMoveToTarget, vLastMoveTo); // Logger.DBLog.InfoFormat if not in town, last waypoint wasn't FROM town, and the distance is >200 but <2000 (cos 2000+ probably means we changed map zones!) if (!ZetaDia.IsInTown && !bLastWaypointWasTown && fDistance >= 200 & fDistance <= 2000) { if (!hashDoneThisVector.Contains(vMoveToTarget)) { // Logger.DBLog.InfoFormat it string sLogFileName = Logger.LoggingPrefixString + " -- LongPaths.log"; FileStream LogStream = File.Open(Logger.LoggingFolderPath + sLogFileName, FileMode.Append, FileAccess.Write, FileShare.Read); using (StreamWriter LogWriter = new StreamWriter(LogStream)) { LogWriter.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + ":"); LogWriter.WriteLine("Profile Name=" + ProfileManager.CurrentProfile.Name); LogWriter.WriteLine("'From' Waypoint=" + vLastMoveTo + ". 'To' Waypoint=" + vMoveToTarget + ". Distance=" + fDistance.ToString(CultureInfo.InvariantCulture)); } //LogStream.Close(); hashDoneThisVector.Add(vMoveToTarget); } } } if (ZetaDia.IsInTown) { bLastWaypointWasTown = true; } } #endregion // Make sure GilesTrinity doesn't want us to avoid routine-movement if (Bot.Targeting.Cache.DontMove) { return; } // Store player current position Vector3 vMyCurrentPosition = ZetaDia.Me.Position; //Check GPC entry (backtracking cache) -- only when not in town! if (BackTrackCache.EnableBacktrackGPRcache && !ZetaDia.IsInTown) { if (DateTime.Now.Subtract(LastCombatPointChecked).TotalMilliseconds > 1250) { if (BackTrackCache.cacheMovementGPRs.Count == 0) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } else { //Add new point only if distance is 25f difference if (BackTrackCache.cacheMovementGPRs.Count == 1) { if (BackTrackCache.cacheMovementGPRs[0].CreationVector.Distance(vMyCurrentPosition) >= BackTrackCache.MinimumRangeBetweenMovementGPRs) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } } else { //Only if no GPCs currently are less than 20f from us.. if (!BackTrackCache.cacheMovementGPRs.Any(GPC => GPC.CreationVector.Distance(vMyCurrentPosition) < BackTrackCache.MinimumRangeBetweenMovementGPRs)) { BackTrackCache.StartNewGPR(vMyCurrentPosition); } } } //Reset Timer LastCombatPointChecked = DateTime.Now; } } //Special cache for skipping locations visited. if (Bot.Settings.Debug.SkipAhead) { SkipAheadCache.RecordSkipAheadCachePoint(); } // Store distance to current moveto target float fDistanceFromTarget; #region Unstucker // Do unstuckery things if (Bot.Settings.Debug.EnableUnstucker) { // Store the "real" (not anti-stuck) destination vOldMoveToTarget = vMoveToTarget; // See if we can reset the 10-limit unstuck counter, if >120 seconds since we last generated an unstuck location if (iTotalAntiStuckAttempts > 1 && DateTime.Now.Subtract(timeStartedUnstuckMeasure).TotalSeconds >= 120) { iTotalAntiStuckAttempts = 1; iTimesReachedStuckPoint = 0; vSafeMovementLocation = Vector3.Zero; } // See if we need to, and can, generate unstuck actions if (DateTime.Now.Subtract(timeCancelledUnstuckerFor).TotalSeconds > iCancelUnstuckerForSeconds && UnstuckChecker(vMyCurrentPosition)) { // Record the time we last apparently couldn't move for a brief period of time timeLastReportedAnyStuck = DateTime.Now; // See if there's any stuck position to try and navigate to generated by random mover vSafeMovementLocation = UnstuckHandler(vMyCurrentPosition, vOldMoveToTarget); if (vSafeMovementLocation == Vector3.Zero) { return; } } // See if we can clear the total unstuckattempts if we haven't been stuck in over 6 minutes. if (DateTime.Now.Subtract(timeLastReportedAnyStuck).TotalSeconds >= 360) { iTimesReachedMaxUnstucks = 0; } // Did we have a safe point already generated (eg from last loop through), if so use it as our current location instead if (vSafeMovementLocation != Vector3.Zero) { // Set our current movement target to the safe point we generated last cycle vMoveToTarget = vSafeMovementLocation; } // Get distance to current destination fDistanceFromTarget = Vector3.Distance(vMyCurrentPosition, vMoveToTarget); // Remove the stuck position if it's been reached, this bit of code also creates multiple stuck-patterns in an ever increasing amount if (vSafeMovementLocation != Vector3.Zero && fDistanceFromTarget <= 3f) { vSafeMovementLocation = Vector3.Zero; iTimesReachedStuckPoint++; // Do we want to immediately generate a 2nd waypoint to "chain" anti-stucks in an ever-increasing path-length? if (iTimesReachedStuckPoint <= iTotalAntiStuckAttempts) { Bot.NavigationCache.AttemptFindSafeSpot(out vSafeMovementLocation, Vector3.Zero, Bot.Settings.Plugin.AvoidanceFlags); vMoveToTarget = vSafeMovementLocation; } else { Logger.DBLog.DebugFormat("[Funky] Clearing old route and trying new path find to: " + vOldMoveToTarget.ToString()); // Reset the path and allow a whole "New" unstuck generation next cycle iTimesReachedStuckPoint = 0; // And cancel unstucking for 9 seconds so DB can try to navigate iCancelUnstuckerForSeconds = (9 * iTotalAntiStuckAttempts); if (iCancelUnstuckerForSeconds < 20) { iCancelUnstuckerForSeconds = 20; } timeCancelledUnstuckerFor = DateTime.Now; Navigator.Clear(); Navigator.MoveTo(vOldMoveToTarget, "original destination", false); return; } } } else { // Get distance to current destination fDistanceFromTarget = vMyCurrentPosition.Distance(vMoveToTarget); } // Is the built-in unstucker enabled or not? #endregion //Prioritize "blocking" objects. if (!Bot.Character.Data.bIsInTown) { Bot.NavigationCache.ObstaclePrioritizeCheck(); } #region MovementAbilities // See if we can use abilities like leap etc. for movement out of combat, but not in town and only if we can raycast. if (Bot.Settings.OutOfCombatMovement && !ZetaDia.IsInTown && !Bot.IsInNonCombatBehavior) { Skill MovementPower; Vector3 MovementVector = Bot.Character.Class.FindOutOfCombatMovementPower(out MovementPower, vMoveToTarget); if (MovementVector != Vector3.Zero) { ZetaDia.Me.UsePower(MovementPower.Power, MovementVector, Bot.Character.Data.iCurrentWorldID); MovementPower.OnSuccessfullyUsed(); return; } } // Allowed to use movement powers to move out-of-combat? #endregion //Send Movement Command! //ZetaDia.Me.Movement.MoveActor(vMoveToTarget); ZetaDia.Me.UsePower(SNOPower.Walk, vMoveToTarget, Bot.Character.Data.iCurrentWorldID); }