public override async Task <bool> Execute() { // If we have the quest, drop it... if (HasQuest(QuestId)) { Me.QuestLog.AbandonQuestById((uint)QuestId); await Coroutine.Wait(Delay.LagDuration, () => !HasQuest(QuestId)); return(true); } // If we cannot 'see' the mob yet, move to the rough location... var questGiver = ObjectManager.GetObjectsOfType <WoWUnit>().FirstOrDefault(u => u.Entry == QuestGiverId); if (questGiver == null) { await UtilityCoroutine.MoveTo(QuestGiverRoughLocation, "Quest Giver"); return(true); } if (!Navigator.AtLocation(questGiver.Location)) { return(await UtilityCoroutine.MoveTo(questGiver.Location, questGiver.Name)); } await ScriptHelpers.PickupQuest(questGiver, (uint)QuestId); await Coroutine.Wait(Delay.LagDuration, () => HasQuest(QuestId)); return(false); }
private Composite StateBehaviorPS_PathRetreating() { return(new PrioritySelector( // If no Egress path, build it... new Decorator(context => Path_Egress == null, new Action(context => { Path_Egress = FollowPath.FindPath_Egress(Mob_ToAvoid); QBCLog.Info("Retreating back to safespot due to {0}.", Me.Combat ? "combat" : string.Format("{0} too close (dist: {1:F1})", Mob_ToAvoid.SafeName, Mob_ToAvoid.Distance)); })), // If we've come to the end of our egress path, move back to safe spot... new Decorator(context => !Path_Egress.Any(), new Action(context => { Path_Ingress = null; Path_Egress = null; State_MainBehavior = StateType_MainBehavior.MovingToSafespot; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(Path_Egress.Peek().Location), new Action(context => { Path_Egress.Dequeue(); })), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( Path_Egress.Peek().Location, "retreat", MovementBy)) )); }
private async Task <bool> UtilityCoroutine_MoveToStartPosition() { if (Navigator.AtLocation(WaitPoint)) { return(false); } return(await UtilityCoroutine.MoveTo(WaitPoint, "Moving to start position", MovementByType.NavigatorOnly)); }
private async Task <bool> MainCoroutine() { if (IsDone) { return(false); } if (TookPortal) { if (Me.IsMoving) { await CommonCoroutines.StopMoving(); } await Coroutine.Sleep(_postZoningDelay); BehaviorDone("Zoned into portal"); return(true); } if (Navigator.AtLocation(StartingPoint) && await WaitToRetry()) { return(true); } // Move to portal starting position... if (!Navigator.AtLocation(StartingPoint)) { if (!await UtilityCoroutine.MoveTo(StartingPoint, "Portal", MovementBy)) { QBCLog.Fatal("Unable to Navigate to StartingPoint"); } return(true); } if (await EnterPortal()) { return(true); } // Zoning failed, do we have any retries left? _retryCount += 1; if (_retryCount > MaxRetryCount) { var message = string.Format("Unable to go through portal in {0} attempts.", MaxRetryCount); // NB: Posting a 'fatal' message will stop the bot--which is what we want. QBCLog.Fatal(message); BehaviorDone(message); return(true); } RetryDelayTimer = new Stopwatch(); return(true); }
private async Task <bool> UtilityCoroutine_MoveAndUseCatapult() { if (!Query.IsInVehicle() || !IsViable(SelectedCatapult)) { return(false); } // Move vehicle into position... if (!Navigator.AtLocation(CurrentTask.PositionForLaunch)) { Navigator.MoveTo(CurrentTask.PositionForLaunch); return(true); } // Adjust heading... if (!WoWMathHelper.IsFacing(WoWMovement.ActiveMover.Location, GetVehicleFacing(), CurrentTask.PositionToLand, WoWMathHelper.DegreesToRadians(0.5f))) { // Handle heading... double neededHeading = WoWMathHelper.CalculateNeededFacing(Me.Location, CurrentTask.PositionToLand); neededHeading = WoWMathHelper.NormalizeRadian((float)neededHeading); QBCLog.Info("Adjusting firing heading"); Me.SetFacing((float)neededHeading); await Coroutine.Sleep(200); return(true); } // Adjust azimuth... double currentAzimuth = WoWMathHelper.NormalizeRadian(Lua.GetReturnVal <float>("return VehicleAimGetAngle();", 0)); double neededAzimuth = NormalizeAngleToPi(CurrentTask.NeededAzimuth); double azimuthChangeRequired = neededAzimuth - currentAzimuth; if (Math.Abs(azimuthChangeRequired) >= 0.01) { QBCLog.Info("Adjusting firing azimuth"); // NB: VehicleAimIncrement() handles negative values of 'increment' correctly... Lua.DoString("VehicleAimIncrement({0})", azimuthChangeRequired); await Coroutine.Sleep(200); return(true); } // Fire.. QBCLog.Info("Firing Catapult"); Lua.DoString(Lua_LaunchCommand); await Coroutine.Wait(3000, () => !Query.IsInVehicle()); return(true); }
/// <summary>Turns in a quest at object </summary> /// <param name="wowObject"> The turnin object. </param> /// <param name="questId"> The quest Id. If 0 (default) then first completed quest is turned in. </param> /// <param name="searchLocation">The search location of <paramref name="wowObject" />.</param> /// <param name="movementBy">The movement type to use.</param> /// <param name="navigationFailedAction"> /// The action to take if <paramref name="wowObject" /> or <paramref name="searchLocation"/> cant be navigated to /// </param> /// <param name="notFoundAction"> /// The action to take if <paramref name="wowObject" /> is not found at /// <paramref name="searchLocation" />. /// </param> /// <returns><c>true</c> if an action was taken; <c>false</c> otherwise</returns> /// <exception cref="Exception">A delegate callback throws an exception.</exception> public static async Task <bool> TurninQuest( WoWObject wowObject, WoWPoint searchLocation, uint questId = 0, MovementByType movementBy = MovementByType.FlightorPreferred, Action navigationFailedAction = null, Action notFoundAction = null) { if (wowObject == null) { if (!Navigator.AtLocation(searchLocation)) { if (await MoveTo(searchLocation, "Quest turnin search area", movementBy)) { return(true); } if (navigationFailedAction != null) { navigationFailedAction(); } return(false); } if (notFoundAction != null) { notFoundAction(); } else { TreeRoot.StatusText = "Waiting for the WoW object selected for quest turnin to spawn"; } return(true); } if (!wowObject.WithinInteractRange) { if (await MoveTo(wowObject.Location, wowObject.SafeName, movementBy)) { return(true); } if (navigationFailedAction != null) { navigationFailedAction(); } return(false); } return(await ScriptHelpers.TurninQuest(wowObject, questId)); }
private WoWPoint FindNextHotspot() { WoWPoint currentHotspot = _hotSpots.Peek(); // If we haven't reached the current hotspot, it is still the 'next' one... if (!Navigator.AtLocation(currentHotspot)) { return(currentHotspot); } // Otherwise, rotate to the next hotspot in the list... _hotSpots.Enqueue(currentHotspot); _hotSpots.Dequeue(); return(_hotSpots.Peek()); }
/// <summary>Determines whether <paramref name="myLoc" /> is within a tolerable proximity of <paramref name="location" />.</summary> /// <param name="myLoc">My loc.</param> /// <param name="location">The location.</param> /// <param name="tolerance">The tolerance. If <c>null</c>: Falls back to use <see cref="Navigator.AtLocation(Vector3,Vector3)"/>.</param> public static bool AtLocation(Vector3 myLoc, Vector3 location, float?tolerance) { if (!tolerance.HasValue) { return(Navigator.AtLocation(myLoc, location)); } float tol = tolerance.Value; // We are checking if point is in an upright cylinder whose center is positioned at 'location', // radius set to 'tolerance' and height set to max(4.5, 'tolerance') x 2. // This is the most suitable method when using mesh navigation because the mesh is often above or below the // actual ingame terrain so there's a need to clamp the tolerance along the Z axis to an amount that // is greater then the maximum terrain/mesh Z coord difference return(myLoc.Distance2DSquared(location) <= tol * tol && Math.Abs(myLoc.Z - location.Z) <= Math.Max(4.5f, tol)); }
/// <summary> /// Tries to find a cached surface path distance between the start/destination pair and returns <c>true</c> if successful /// </summary> /// <param name="start">The start.</param> /// <param name="destination">The destination.</param> /// <param name="distance">The surface path distance, zero if no cache found or NaN if no path could be fully generated</param> /// <returns><c>true</c> if a cache was found, <c>false</c> otherwise.</returns> internal static bool TryGet(WoWPoint start, WoWPoint destination, out float distance) { SurfacePathDistanceCache match = null; var now = DateTime.Now; // do we need to cleanup old caches? var doCleanup = now - s_lastCleanupTime > s_maxCacheTimeSpan; // iterate the path cache in revere so we can remove entries safely for (int idx = s_pathDistanceCache.Count - 1; idx >= 0; idx--) { var entry = s_pathDistanceCache[idx]; // check if we need the entry if (doCleanup && now - entry.TimeStamp > s_maxCacheTimeSpan) { s_pathDistanceCache.RemoveAt(idx); continue; } // check if we have a match if (match == null && Navigator.AtLocation(start, entry.Start) && Navigator.AtLocation(destination, entry.Destination)) { match = entry; // exit for loop now if not doing a cleanup pass if (!doCleanup) { break; } } } if (doCleanup) { s_lastCleanupTime = now; } if (match == null) { distance = 0; return(false); } distance = match.Distance; return(true); }
private Composite StateBehaviorPS_ReturningToBase() { return(new PrioritySelector( // Start over... new Decorator(context => !Query.IsInVehicle(), new Action(context => { BehaviorState = BehaviorStateType.MountingVehicle; })), // Exit vehicle... new Decorator(context => Navigator.AtLocation(PathEnd), new Action(context => { Lua.DoString("VehicleExit()"); })), // Move back to 'safe mounting' area... new Action(context => { TreeRoot.StatusText = "Moving back to safe area"; Flightor.MoveTo(PathEnd, (float)FlightorMinHeight); }) )); }
/// <summary> /// Mounts a vehicle /// </summary> /// <param name="searchLocation">The search location.</param> /// <param name="movementBy">The movement type.</param> /// <param name="extraVehicleQualifiers">The extra vehicle qualifiers.</param> /// <param name="vehicleIds">The vehicle ids.</param> /// <returns> /// <c>true</c> if any action was taken; <c>false</c> otherwise /// </returns> public static async Task <bool> MountVehicle( Vector3 searchLocation, MovementByType movementBy = MovementByType.FlightorPreferred, Func <WoWUnit, bool> extraVehicleQualifiers = null, params int[] vehicleIds) { if (Query.IsInVehicle()) { return(false); } var vehicle = Query.FindUnoccupiedVehicles(vehicleIds, extraVehicleQualifiers).FirstOrDefault(); if (vehicle == null) { if (!Navigator.AtLocation(searchLocation)) { return(await MoveTo(searchLocation, "Vehicle search area", movementBy)); } await (s_mountVehicleUserUpdateThrottle ?? (s_mountVehicleUserUpdateThrottle = new ThrottleCoroutineTask( TimeSpan.FromSeconds(10), async() => QBCLog.Info("Waiting for a vehicle to become available")))); return(true); } if (!vehicle.WithinInteractRange) { return(await MoveTo(vehicle.Location, vehicle.SafeName, movementBy, vehicle.InteractRange)); } if (await CommonCoroutines.Dismount("Getting inside vehicle")) { await Coroutine.Sleep(Delay.BeforeButtonClick); } vehicle.Interact(); await Coroutine.Sleep(Delay.AfterInteraction); return(true); }
private Composite StateBehaviorPS_ReturningToBase() { // If we are not returning home... return(new PrioritySelector( new Decorator(context => IsInTank(), new CompositeThrottle(Throttle.UserUpdate, new ActionFail(context => { TreeRoot.StatusText = "Returning to base"; }) )), new Decorator(context => !Navigator.AtLocation(Location_ReturnToSchnottz), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Location_ReturnToSchnottz, "Commander Schnottz", MovementBy))), new Decorator(context => Me.IsQuestComplete(QuestId), new Action(context => BehaviorDone("quest complete"))) )); }
private async Task <bool> EnterPortal() { var portalEntryTimer = new WaitTimer(MaxTimeToPortalEntry); portalEntryTimer.Reset(); QBCLog.DeveloperInfo("Portal Entry Timer Started"); while (true) { if (TookPortal) { return(true); } // If portal entry timer expired, deal with it... if (portalEntryTimer.IsFinished) { QBCLog.Warning( "Unable to enter portal within allotted time of {0}", Utility.PrettyTime(MaxTimeToPortalEntry)); break; } // If we are within 2 yards of calculated end point we should never reach... if (Me.Location.Distance(MovePoint) < 2) { QBCLog.Warning("Seems we missed the portal. Is Portal activated? Profile needs to pick better alignment?"); break; } // If we're not moving toward portal, get busy... if (!StyxWoW.Me.IsMoving || Navigator.AtLocation(StartingPoint)) { QBCLog.DeveloperInfo("Entering portal via {0}", MovePoint); WoWMovement.ClickToMove(MovePoint); } await Coroutine.Yield(); } return(false); }
private static async Task <bool> TryClickToMove( WoWPoint destination, NavType navType = NavType.Fly) { var activeMover = WoWMovement.ActiveMover; // NB: Do not 'dismount' for CtM. We may be using it for aerial navigation, also. if (await SetMountState(destination, navType)) { return(true); } // If Navigator can generate a parital path for us, take advantage of it... var tempDestination = Navigator.GeneratePath(activeMover.Location, destination) .Where(p => !Navigator.AtLocation(p)) .DefaultIfEmpty(destination) .FirstOrDefault(); WoWMovement.ClickToMove(tempDestination); return(true); }
// Returns: RunStatus.Success while movement is in progress; othwerise, RunStatus.Failure if no movement necessary private Composite UtilityBehavior_MoveWithinRange(LocationDelegate locationDelegate, MessageDelegate locationNameDelegate) { return(new Sequence( // Done, if we're already at destination... new DecoratorContinue(context => Navigator.AtLocation(locationDelegate(context)), new Decorator(context => Me.IsMoving, // This decorator failing indicates the behavior is complete new Action(delegate { WoWMovement.MoveStop(); }))), // Notify user of progress... new CompositeThrottle(TimeSpan.FromSeconds(1), new Action(context => { double destinationDistance = Me.Location.Distance(locationDelegate(context)); string locationName = locationNameDelegate(context) ?? locationDelegate(context).ToString(); Utility_NotifyUser(string.Format("Moving to {0} (distance: {1:F1})", locationName, destinationDistance)); })), new Action(context => { WoWPoint destination = locationDelegate(context); // Try to use Navigator to get there... MoveResult moveResult = Navigator.MoveTo(destination); // If Navigator fails, fall back to click-to-move... if ((moveResult == MoveResult.Failed) || (moveResult == MoveResult.PathGenerationFailed)) { WoWMovement.ClickToMove(destination); } return RunStatus.Success; // fall through }), new WaitContinue(_delay_WoWClientMovementThrottle, ret => false, new ActionAlwaysSucceed()) )); }
/// <summary>Gossips with the specified wow object. Hearthstone bind popups are automatically accepted</summary> /// <param name="wowObject">The wow object. Navigates to <paramref name="searchLocation" /> null </param> /// <param name="searchLocation">The search location of <paramref name="wowObject" />.</param> /// <param name="movementBy">The movement type to use.</param> /// <param name="navigationFailedAction"> /// The action to take if <paramref name="wowObject" /> or <paramref name="searchLocation"/> cant be navigated to /// </param> /// <param name="notFoundAction"> /// The action to take if <paramref name="wowObject" /> is not found at /// <paramref name="searchLocation" />. /// </param> /// <param name="noGossipFrameAction"> /// The action to take if interaction with <paramref name="wowObject" /> didn't open a /// gossip frame. /// </param> /// <param name="noMatchingGossipOptionAction"> /// <para>The action to take if the passed in gossip type and/or gossip indices </para> /// <para>doesn't match what was offered by <paramref name="wowObject" />.</para> /// </param> /// <param name="gossipEntryType"> /// <para>Type gossip entry type to select. Ignored if set to Unknown.</para> /// <para>If none of this type are found on current page then</para> /// <para> normal gossip types are clicked through in hopes of ending on a page with this gossip type</para> /// </param> /// <param name="gossipIndexes"> /// The gossip indexes to follow through. Has precedence over /// <paramref name="gossipEntryType" />. /// </param> /// <exception cref="Exception">A delegate callback throws an exception.</exception> public static async Task <bool> Gossip( WoWObject wowObject, WoWPoint searchLocation, MovementByType movementBy = MovementByType.FlightorPreferred, Action navigationFailedAction = null, Action notFoundAction = null, Action noGossipFrameAction = null, Action noMatchingGossipOptionAction = null, GossipEntry.GossipEntryType gossipEntryType = GossipEntry.GossipEntryType.Unknown, params int[] gossipIndexes) { if (wowObject == null) { if (!Navigator.AtLocation(searchLocation)) { if (await MoveTo(searchLocation, "Gossip object search area", movementBy)) { return(true); } navigationFailedAction?.Invoke(); return(false); } if (notFoundAction != null) { notFoundAction(); } else { TreeRoot.StatusText = "Waiting for the WoW object selected for gossip to spawn"; } return(true); } if (!wowObject.WithinInteractRange) { if (await MoveTo(wowObject.Location, wowObject.SafeName, movementBy)) { return(true); } navigationFailedAction?.Invoke(); return(false); } if (await CommonCoroutines.Dismount("Gossiping with " + wowObject.SafeName)) { await Coroutine.Sleep(Delay.BeforeButtonClick); } // If gossip frame is open then we must assume that it doesn't belong to the selected gossip object at this point if (GossipFrame.Instance.IsVisible) { GossipFrame.Instance.Close(); return(true); } Func <bool> isFrameReadyForInput = () => GossipFrame.Instance.IsVisible && (GossipFrame.Instance.GossipOptionEntries != null || (!gossipIndexes.Any() && gossipEntryType == GossipEntry.GossipEntryType.Unknown)); wowObject.Interact(); var openedGossipFrame = await Coroutine.Wait(3000, isFrameReadyForInput); if (!openedGossipFrame) { QBCLog.Warning("No gossip frame was opened after interacting with {0}", wowObject.SafeName); noGossipFrameAction?.Invoke(); return(false); } int gossipPage = 1; // Click through all the gossip indices for (var i = 0; i < gossipIndexes.Length; i++) { var index = gossipIndexes[i] - 1; var gossipEntry = GossipFrame.Instance.GossipOptionEntries.Where(g => g.Index == index) .Select(g => (GossipEntry?)g) .FirstOrDefault(); if (!gossipEntry.HasValue || gossipEntry.Value.Type == GossipEntry.GossipEntryType.Unknown) { QBCLog.Warning("{0} does not provide a gossip at index {1} on page {2}", wowObject.SafeName, index + 1, gossipPage); noMatchingGossipOptionAction?.Invoke(); return(false); } await ClickGossipOption(gossipEntry.Value, gossipPage); // make sure frame didn't close before we're done. if (!isFrameReadyForInput() && (i < gossipIndexes.Length - 1 || gossipEntryType != GossipEntry.GossipEntryType.Unknown)) { // This can happen if some external event causes object to stop offering gossip frame, such as NPC getting into combat. // Usually this can be fixed by interacting with object again at a later time. We let the caller handle this. QBCLog.Warning("Gossip frame for {0} closed unexpectedly.", wowObject.SafeName); return(true); } gossipPage++; } if (gossipEntryType != GossipEntry.GossipEntryType.Unknown) { if (!gossipIndexes.Any()) { while (true) { var gossipEntry = GossipFrame.Instance.GossipOptionEntries.FirstOrDefault(g => g.Type == gossipEntryType); // If no gossip indices were specified then we just click through more gossip, // hopefully it leads to the final gossip type if (gossipEntry.Type != gossipEntryType) { gossipEntry = GossipFrame.Instance.GossipOptionEntries.FirstOrDefault(g => g.Type == GossipEntry.GossipEntryType.Gossip); } if (gossipEntry.Type == GossipEntry.GossipEntryType.Unknown) { QBCLog.Warning("{0} does not provide a {0} gossip type", wowObject.SafeName, gossipEntryType); noMatchingGossipOptionAction?.Invoke(); return(false); } await ClickGossipOption(gossipEntry, gossipPage); if (!isFrameReadyForInput() && gossipEntry.Type != gossipEntryType) { // This can happen if some external event causes object to stop offering gossip frame, such as NPC getting into combat. // Usually this can be fixed by interacting with object again at a later time. We let the caller handle this. QBCLog.Warning("Gossip frame for {0} closed unexpectedly.", wowObject.SafeName); return(true); } if (gossipEntry.Type == gossipEntryType) { break; } gossipPage++; } } } // Set hearthstone automatically const string setHsPopupName = "CONFIRM_BINDER"; if (Lua.GetReturnVal <bool>($"return StaticPopup_Visible('{setHsPopupName}')", 0)) { uint hsId = StyxWoW.Me.HearthstoneAreaId; Lua.DoString( $"local _,frame = StaticPopup_Visible('{setHsPopupName}') if frame then StaticPopup_OnClick(frame, 1) end"); if (await Coroutine.Wait(5000, () => StyxWoW.Me.HearthstoneAreaId != hsId)) { await CommonCoroutines.SleepForRandomReactionTime(); var boundLocation = Lua.GetReturnVal <string>("return GetBindLocation()", 0); QBCLog.Info( "You are now bound at {0} Inn in {1}({2})", (Query.IsViable(wowObject) ? wowObject.SafeName : "the"), boundLocation, Me.HearthstoneAreaId); } } return(true); }
private Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update information for this BT visit... new Action(context => { HighWarlordDarion = ObjectManager.GetObjectsOfType <WoWUnit>(false, false).FirstOrDefault(u => u.Entry == 29173); if ((HighWarlordDarion != null) && (Me.CurrentTarget != HighWarlordDarion)) { HighWarlordDarion.Target(); } return RunStatus.Failure; }), new Switch <StateType_Behavior>(context => State_Behavior, #region State: DEFAULT new Action(context => // default case { QBCLog.MaintenanceError("State_Behavior({0}) is unhandled", State_Behavior); TreeRoot.Stop(); _isBehaviorDone = true; }), #endregion #region State: Wait for Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForWarlordDarion, new PrioritySelector( // Move into position to await Warlord arrival... new Decorator(context => !Navigator.AtLocation(Location_WaitToChatWithDarion), new Action(context => { TreeRoot.StatusText = "Moving into position to wait on High Warlord Darion to arrive"; Navigator.MoveTo(Location_WaitToChatWithDarion); })), // Warlord has arrived, go have a chat.. new Decorator(context => HighWarlordDarion != null, new Action(context => { State_Behavior = StateType_Behavior.ChattingToStartBattle; })), // If warlord is not here, go check the battlefield... new Decorator(context => !IsBattlefieldCheckedForDarion, new Action(context => { State_Behavior = StateType_Behavior.CheckingBattlefieldForWarlordDarion; })), new Action(context => { TreeRoot.StatusText = "Waiting for High Warlord Darion to arrive"; AntiAfk(); }) )), #endregion #region State: Check Battlefield for Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.CheckingBattlefieldForWarlordDarion, new PrioritySelector( // Move into position to await Warlord arrival... new Decorator(context => !Navigator.AtLocation(Location_WaitForBattleToComplete), new Action(context => { TreeRoot.StatusText = "Checking battlefield for High Warlord Darion"; Navigator.MoveTo(Location_WaitForBattleToComplete); })), // If we found Warlord on battlefield, wait for battle to complete... new Decorator(context => HighWarlordDarion != null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToComplete; })), // If warlord is not here, return to start point and wait... new Decorator(context => HighWarlordDarion == null, new Action(context => { IsBattlefieldCheckedForDarion = true; State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })) )), #endregion #region State: Chat with Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.ChattingToStartBattle, new PrioritySelector( // If the Warlord disappeared, go find him... new Decorator(context => HighWarlordDarion == null, new Action(context => { IsBattlefieldCheckedForDarion = false; State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // Move close enough to chat with Warlord... new Decorator(context => !HighWarlordDarion.WithinInteractRange, new Action(context => { TreeRoot.StatusText = "Moving to " + HighWarlordDarion.SafeName; Navigator.MoveTo(HighWarlordDarion.Location); })), // Chat with warlord... // When we interact with the warlord, he will present us with either: // 1) a Quest frame (with no gossip options) // 2) a Gossip frame (with gossip options) that we use to kick off the event // Both frames always *exist*, what matters is the one the Warlord presents us with. new Decorator(context => HighWarlordDarion.CanGossip, new PrioritySelector( new Decorator(context => !(GossipFrame.Instance.IsVisible || QuestFrame.Instance.IsVisible), new Action(context => { HighWarlordDarion.Interact(); })), // Process GossipFrame or QuestFrame, whichever was presented... new Sequence( // Simulate reading frame text... new WaitContinue(VariantTimeSpan(2500, 7000), context => false, new ActionAlwaysSucceed()), // If gossip frame showing, choose correct gossip option... new DecoratorContinue(context => GossipFrame.Instance.IsVisible && GossipFrame.Instance.GossipOptionEntries.Count() > 0, new Action(context => { GossipFrame.Instance.SelectGossipOption(0); })), new WaitContinue(VariantTimeSpan(1250, 3500), context => false, new ActionAlwaysSucceed()), // Close gossip frame if that was showing... new DecoratorContinue(context => GossipFrame.Instance.IsVisible, new Action(context => { GossipFrame.Instance.Close(); })), // Close quest frame if that was showing... new DecoratorContinue(context => QuestFrame.Instance.IsVisible, new Action(context => { QuestFrame.Instance.Close(); })), new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToStart; }) ) )), // Warlord doesn't want to chat, wait for battle to start... new Decorator(context => !HighWarlordDarion.CanGossip, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToStart; })) )), #endregion #region State: Wait for Battle to start new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForBattleToStart, new PrioritySelector( // If warlord disappeared, start over... new Decorator(context => HighWarlordDarion == null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // If Warlord is already on the battlefield, time to go... new Decorator(context => HighWarlordDarion.Location.Distance(Location_Battlefield.Location) <= Location_Battlefield.Radius, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToComplete; })), // If the warlord is not on the battlefield, follow him at a reasonable distance... new Decorator(context => HighWarlordDarion.Distance > DistanceToFollowWarlord, new Action(context => { TreeRoot.StatusText = string.Format("Following {0}", HighWarlordDarion.SafeName); Navigator.MoveTo(HighWarlordDarion.Location); })), // Move into position to await battle start... new Decorator(context => !HighWarlordDarion.IsMoving && !Navigator.AtLocation(Location_WaitToChatWithDarion), new Action(context => { TreeRoot.StatusText = "Waiting for Battle to start"; Navigator.MoveTo(Location_WaitToChatWithDarion); })) )), #endregion #region State: Wait for Battle to complete new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForBattleToComplete, new PrioritySelector( // If warlord disappeared, start over... new Decorator(context => HighWarlordDarion == null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // If the warlord is on the battlefield, wait at our safespot... new Decorator(context => HighWarlordDarion.Location.Distance(Location_Battlefield.Location) <= Location_Battlefield.Radius, new PrioritySelector( // Move to our position to wait for battle to be over... new Decorator(context => !Navigator.AtLocation(Location_WaitForBattleToComplete), new Action(context => { TreeRoot.StatusText = "Moving to safe spot"; Navigator.MoveTo(Location_WaitForBattleToComplete); })), // Wait for battle to be over... new Action(context => { TreeRoot.StatusText = "Waiting for battle to complete."; AntiAfk(); }))), // If the warlord has returned to his starting position, then start over... new Decorator(context => HighWarlordDarion.Location.Distance(Location_WaitToChatWithDarion) <= DistanceToFollowWarlord, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })) )) #endregion ) ))); }
private Composite StateBehaviorPS_MountingVehicle() { return(new PrioritySelector( new Decorator(context => Me.IsQuestComplete(QuestId), new Action(context => { BehaviorDone(); })), // If we're in the vehicle, wait for the ride out to hunting grounds to complete... new Decorator(context => IsInTank(), new PrioritySelector( SubBehaviorPS_InitializeVehicleAbilities(), new Action(context => { BehaviorState = BehaviorStateType.RidingOutToHuntingGrounds; }) )), // If vehicle is in "enter vehicle" animation, wait for the animation to complete... new Decorator(context => FindVehicle_OwnedByMe(MobId_SchnottzSiegeTankInstanced) != null, new PrioritySelector( new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} to become ready.", Utility.GetObjectNameFromId(MobId_SchnottzSiegeTankInstanced)); })), new ActionAlwaysSucceed() )), // Locate a vehicle to mount... new Decorator(context => !Query.IsViable(Vehicle), new PrioritySelector( new Action(context => { Vehicle = Query.FindMobsAndFactions(Utility.ToEnumerable(MobId_SchnottzSiegeTank)) .FirstOrDefault() as WoWUnit; if (Query.IsViable(Vehicle)) { Utility.Target(Vehicle); return RunStatus.Success; } return RunStatus.Failure; // fall through }), // No vehicle found, move to staging area... new Decorator(ctx => !Navigator.AtLocation(Location_VehicleStagingArea), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Location_VehicleStagingArea, "Vehicle Staging Area", MovementBy))), // Wait for vehicle to respawn... new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} to respawn.", Utility.GetObjectNameFromId(MobId_SchnottzSiegeTank)); })) )), // Move to vehicle and enter... new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0}", Vehicle.SafeName); })), new Decorator(context => !Vehicle.WithinInteractRange, new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Vehicle.Location, Vehicle.SafeName, MovementBy))), new Decorator(context => Me.IsMoving, new Action(context => { Navigator.PlayerMover.MoveStop(); })), new Decorator(context => Me.Mounted, new ActionRunCoroutine(context => UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.DismountOrCancelShapeshift))), new ActionFail(context => { // If we got booted out of a vehicle for some reason, reset the weapons... WeaponFireCannon = null; Utility.Target(Vehicle); Vehicle.Interact(); }), new Wait(TimeSpan.FromMilliseconds(10000), context => IsInTank(), new ActionAlwaysSucceed()), new ActionAlwaysSucceed() )); }
public Composite CreateBehavior_SelectTarget(BehaviorFailIfNoTargetsDelegate failIfNoTargets) { return( new PrioritySelector( // If we haven't engaged the mob when the auto-blacklist timer expires, give up on it and move on... new Decorator(ret => ((CurrentTarget != null) && (_currentTargetAutoBlacklistTimer.Elapsed > _currentTargetAutoBlacklistTime)), new Action(delegate { QBCLog.Warning("Taking too long to engage '{0}'--blacklisting", CurrentTarget.SafeName); CurrentTarget.LocallyBlacklist(_delay_AutoBlacklist); CurrentTarget = null; })), // If we don't have a current target, select a new one... // Once we select a target, its 'locked in' (unless it gets blacklisted). This prevents us // from running back and forth between two equidistant targets. new Decorator(ret => ((CurrentTarget == null) || !CurrentTarget.IsValid || CurrentTarget.IsLocallyBlacklisted()), new PrioritySelector(context => CurrentTarget = ViableTargets().FirstOrDefault(), // If we found next target, we're done... new Decorator(ret => (CurrentTarget != null), new Action(delegate { _huntingGroundWaitPoint = WoWPoint.Empty; if (CurrentTarget is WoWUnit) { CurrentTarget.ToUnit().Target(); } _currentTargetAutoBlacklistTime = CalculateAutoBlacklistTime(CurrentTarget); _currentTargetAutoBlacklistTimer.Reset(); _currentTargetAutoBlacklistTimer.Start(); })), // If we've exhausted mob/object supply in area, and we need to wait, do so... new Decorator(ret => !failIfNoTargets(), // Move back to hunting ground anchor -- new PrioritySelector( // If we've more than one hotspot, head to the next one... new Decorator(ret => (_hotSpots.Count() > 1), new Sequence(context => FindNextHotspot(), new Action(nextHotspot => TreeRoot.StatusText = "No targets--moving to hotspot " + (WoWPoint)nextHotspot), CreateBehavior_InternalMoveTo(() => FindNextHotspot()) )), // We find a point 'near' our anchor at which to wait... // This way, if multiple people are using the same profile at the same time, // they won't be standing on top of each other. new Decorator(ret => (_huntingGroundWaitPoint == WoWPoint.Empty), new Action(delegate { _huntingGroundWaitPoint = HuntingGroundAnchor.FanOutRandom(CollectionDistance * 0.25); TreeRoot.StatusText = "No targets--moving near hunting ground anchor point to wait"; _repopWaitingTime.Reset(); _repopWaitingTime.Start(); })), // Move to our selected random point... new Decorator(ret => !Navigator.AtLocation(_huntingGroundWaitPoint), CreateBehavior_InternalMoveTo(() => _huntingGroundWaitPoint)), // Tell user what's going on... new Sequence( new Action(delegate { TreeRoot.GoalText = this.GetType().Name + ": Waiting for Repops"; TreeRoot.StatusText = "No targets in area--waiting for repops. " + BuildTimeAsString(_repopWaitingTime.Elapsed); }), new WaitContinue(_delay_RepopWait, ret => false, new ActionAlwaysSucceed())) )) )), // Re-select target, if it was lost (perhaps, due to combat)... new Decorator(ret => ((CurrentTarget is WoWUnit) && (Me.CurrentTarget != CurrentTarget)), new Action(delegate { CurrentTarget.ToUnit().Target(); })) )); }
private async Task <bool> ScareSpiders() { // if not in a turret than move to one and interact with it if (!Query.IsInVehicle()) { var mustang = GetMustang(); if (mustang == null) { QBCLog.Warning("No mustang was found nearby"); return(false); } TreeRoot.StatusText = "Moving To Mustang"; if (mustang.DistanceSqr > 5 * 5) { return((await CommonCoroutines.MoveTo(mustang.Location)).IsSuccessful()); } await CommonCoroutines.LandAndDismount(); QBCLog.Info("Interacting with Mustang"); mustang.Interact(); return(true); } // Find the nearest spider and if none exist then move to the spawn location if (!Query.IsViable(_currentTarget) || !_currentTarget.IsAlive) { _currentTarget = ObjectManager.GetObjectsOfType <WoWUnit>() .Where(u => u.IsAlive && u.Entry == 44284 && !Blacklist.Contains(u, BlacklistFlags.Interact)) .OrderBy(u => u.DistanceSqr).FirstOrDefault(); if (_currentTarget == null) { if (!Navigator.AtLocation(_spiderSpawnLocation)) { return((await CommonCoroutines.MoveTo(_spiderSpawnLocation)).IsSuccessful()); } TreeRoot.StatusText = "Waiting for spiders to spawn"; return(true); } _noMoveBlacklistTimer.Reset(); _blacklistTimer.Reset(); QBCLog.Info("Locked on a new target. Distance {0}", _currentTarget.Distance); } TreeRoot.StatusText = "Scaring spider towards lumber mill"; var moveToPoint = WoWMathHelper.CalculatePointFrom(_lumberMillLocation, _currentTarget.Location, -6); if (moveToPoint.DistanceSqr((WoWMovement.ActiveMover ?? StyxWoW.Me).Location) > 4 * 4) { return((await CommonCoroutines.MoveTo(moveToPoint)).IsSuccessful()); } // spider not moving? blacklist and find a new target. if (_noMoveBlacklistTimer.ElapsedMilliseconds > 20000 && _currentTarget.Location.DistanceSqr(_spiderScareLoc) < 10 * 10) { Blacklist.Add(_currentTarget, BlacklistFlags.Interact, TimeSpan.FromMinutes(3), "Spider is not moving"); _currentTarget = null; } else if (_blacklistTimer.IsFinished) { Blacklist.Add(_currentTarget, BlacklistFlags.Interact, TimeSpan.FromMinutes(3), "Took too long"); _currentTarget = null; } else if (!_currentTarget.HasAura("Fear")) { await CommonCoroutines.StopMoving(); Me.SetFacing(_lumberMillLocation); await CommonCoroutines.SleepForLagDuration(); await Coroutine.Sleep(200); if (!_noMoveBlacklistTimer.IsRunning || _currentTarget.Location.DistanceSqr(_spiderScareLoc) >= 10 * 10) { _noMoveBlacklistTimer.Restart(); _spiderScareLoc = _currentTarget.Location; } Lua.DoString("CastSpellByID(83605)"); await Coroutine.Wait(3000, () => Query.IsViable(_currentTarget) && _currentTarget.HasAura("Fear")); } return(true); }
private async static Task <bool> FollowPath() { if (!AutoAnglerSettings.Instance.Poolfishing && !AutoAnglerBot.Instance.Profile.FishAtHotspot) { return(false); } if (!AutoAnglerBot.Instance.Profile.FishAtHotspot && (BotPoi.Current.Type == PoiType.Harvest || LootTargeting.Instance.FirstObject != null)) { return(false); } if (await CheckLootFrame()) { return(true); } // dks can refresh water walking while flying around. if (AutoAnglerSettings.Instance.UseWaterWalking && Me.Class == WoWClass.DeathKnight && !WaterWalking.IsActive && await WaterWalking.Cast()) { return(true); } var moveto = AutoAnglerBot.Instance.Profile.CurrentPoint; if (moveto == WoWPoint.Zero) { return(false); } if (AutoAnglerBot.Instance.Profile.FishAtHotspot && Navigator.AtLocation(moveto)) { return(false); } float precision = Me.IsFlying ? AutoAnglerSettings.Instance.PathPrecision : 3; if (Me.Location.Distance(moveto) <= precision) { AutoAnglerBot.Instance.Profile.CycleToNextPoint(); } if (AutoAnglerSettings.Instance.Fly) { if (!StyxWoW.Me.Mounted && Flightor.MountHelper.CanMount) { var zenFlightAura = StyxWoW.Me.GetAuraByName("Zen Flight"); if (zenFlightAura != null) { zenFlightAura.TryCancelAura(); await CommonCoroutines.SleepForLagDuration(); } Flightor.MountHelper.MountUp(); return(true); } Flightor.MoveTo(moveto); } else { if (!StyxWoW.Me.Mounted && Mount.ShouldMount(moveto) && Mount.CanMount()) { Mount.MountUp(() => moveto); } var result = Navigator.MoveTo(moveto); if (result != MoveResult.Failed && result != MoveResult.PathGenerationFailed) { InactivityDetector.Reset(); } } return(true); }
private Composite CreateMainBehavior() { return(new PrioritySelector( // If quest is done, behavior is done... new Decorator(context => IsDone, new Action(context => { _isBehaviorDone = true; QBCLog.Info("Finished"); })), // Stateful Operation: new Switch <StateType_MainBehavior>(context => State_MainBehavior, #region State: DEFAULT new Action(context => // default case { QBCLog.MaintenanceError("StateType_MainBehavior({0}) is unhandled", State_MainBehavior); TreeRoot.Stop(); _isBehaviorDone = true; }), #endregion #region State: Dropping Off Victim new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.DroppingOffVictim, new PrioritySelector( // If Watchman dropped off, go get another... new Decorator(context => !Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { WoWMovement.MoveStop(); _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // Move to drop off spot... new Decorator(context => Me.Location.Distance(PositionToMakeLandfall) > Navigator.PathPrecision, new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( PositionToMakeLandfall, "back to shore"))) )), #endregion #region State: Pathing Out to Victim new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathingOutToVictim, new PrioritySelector( // If our selected target is no good, find another... new Decorator(context => !IsViableDrowningWatchman(SelectedTarget), new Action(context => { QBCLog.Info("Finding new Drowning Watchman to save"); _currentPath = null; SelectedTarget = FindDrowningWatchman(); })), // Show user which target we're after... new Decorator(context => Me.CurrentTarget != SelectedTarget, new Action(context => { SelectedTarget.Target(); })), // If we don't have a path to victim, find one... new Decorator(context => _currentPath == null, new Action(context => { _currentPath = FindPath(Me.Location, SelectedTarget.Location); })), // If path completely consumed, we're done... new Decorator(context => _currentPath.Count() <= 0, new Action(context => { State_MainBehavior = StateType_MainBehavior.Rescuing; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(_currentPath.Peek()), new Action(context => { _currentPath.Dequeue(); })), // Follow the prescribed path... new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( _currentPath.Peek(), "out to Drowned Watcman")) )), #endregion #region State: Rescuing new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.Rescuing, new PrioritySelector( // If we've got the Watchman, start heading in... new Decorator(context => Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { _currentPath = null; State_MainBehavior = StateType_MainBehavior.PathingIntoShore; })), // If our selected target is no good, find another... new Decorator(context => !IsViableDrowningWatchman(SelectedTarget), new Action(context => { _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // Go get a fresh Drowning Watchman... UtilityBehavior_InteractWithMob(context => SelectedTarget) )), #endregion #region State: Pathing Into Shore new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathingIntoShore, new PrioritySelector( // If we don't have a path, find the correct one... new Decorator(context => _currentPath == null, new Action(context => { _currentPath = FindPath(Me.Location, PositionToMakeLandfall); })), // If path completely consumed, we're done... new Decorator(context => _currentPath.Count() <= 0, new Action(context => { State_MainBehavior = StateType_MainBehavior.DroppingOffVictim; })), // If we've lost the Watchman we rescued, go fetch another... new Decorator(context => !Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(_currentPath.Peek()), new Action(context => { _currentPath.Dequeue(); })), // Follow the prescribed path... new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( _currentPath.Peek(), "in to drop off Drowned Watchman")) )) #endregion ))); }
private Composite StateBehaviorPS_MovingToSafeSpot() { return(new PrioritySelector( // If a "Move Near" mob was specified, move to it... new Decorator(context => MobIdToMoveNear > 0, new PrioritySelector( new Decorator(context => Query.IsViable(Mob_ToMoveNear), new PrioritySelector( // Target the MoveToNpc, as feedback to the user... new ActionFail(context => { Utility.Target(Mob_ToMoveNear); }), // Move to mob... new Decorator(ctx => !Navigator.AtLocation(Mob_ToMoveNear.Location), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( Mob_ToMoveNear.Location, Mob_ToMoveNear.SafeName, MovementBy))) )), // Need to wait for Mob to respawn... new Decorator(context => !Query.IsViable(Mob_ToMoveNear), new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} to respawn", Utility.GetObjectNameFromId(MobIdToMoveNear)); })) )), // No "Move Near" mob, so use the provided Safe spot coordinates... new Decorator(context => MobIdToMoveNear <= 0 && !Navigator.AtLocation(SafespotLocation), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( SafespotLocation, "safe spot", MovementBy))), // Dismount once we've arrived at mob or destination... new Decorator(ctx => Me.Mounted, new ActionRunCoroutine(ctx => CommonCoroutines.LandAndDismount())), new Decorator(ctx => StyxWoW.Me.IsMoving, new Action(ctx => WoWMovement.MoveStop())), // Target and Face the AvoidNpc, as feedback to the user... new ActionFail( context => { Utility.Target(Mob_ToAvoid, true); }), // If AvoidNpc is not around, // or if AvoidNpc is prescribed distance away, and facing away from us, // we're done... new Decorator(context => IsSafeToMoveToDestination(Mob_ToAvoid), new Action(context => { FollowPath.DismissPetIfNeeded(); Path_Ingress = null; Path_Egress = null; State_MainBehavior = StateType_MainBehavior.PathIngressing; })), // Tell user what we're up to... new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for '{0}' to move {1:F1}/{2:F1} yards away, and pathing away from us.", Mob_ToAvoid.SafeName, Mob_ToAvoid.Distance, AvoidDistance); })) )); }
protected Composite CreateBehavior_QuestbotMain() { return(_root ?? (_root = new Decorator(ret => !IsDone && (!AllowCombat || !Me.Combat), new PrioritySelector( new Decorator(ret => !Path.Any() && Counter >= NumOfTimes, new Action(delegate { _isBehaviorDone = true; })), new Decorator(ret => !Path.Any(), new Action(delegate { Counter++; ParsePath(); })), new Decorator(ret => Navigator.AtLocation(Path.Peek()), new PrioritySelector( new Decorator(ret => Me.IsMoving && WaitTime > 0, new Sequence( new Action(ret => WoWMovement.MoveStop()), new Action(ret => TreeRoot.GoalText = "RunLikeHell pausing " + WaitTime + " ms"), new WaitContinue(TimeSpan.FromMilliseconds(WaitTime), ret => false, new ActionAlwaysSucceed()) ) ), new Decorator(ret => MobId != 0 && Mob.Distance > Range, new Action(delegate { TreeRoot.GoalText = "RunLikeHell wait for " + Mob.SafeName + " within " + Range + " yds"; })), new Action(delegate { Path.Dequeue(); })) ), new Action(delegate { if (NumOfTimes > 1) { TreeRoot.GoalText = "RunLikeHell[Lap " + Counter + "] to " + Path.Peek().ToString(); } else { TreeRoot.GoalText = "RunLikeHell to " + Path.Peek().ToString(); } if (UseCTM) { WoWMovement.ClickToMove(Path.Peek()); } else { Navigator.MoveTo(Path.Peek()); } return _lastStateReturn; }) ) ) )); }
private Composite StateBehaviorPS_PathIngressing() { return(new PrioritySelector( // If no Ingress path exists, build it... new Decorator(context => Path_Ingress == null, new Action(context => { Path_Ingress = FollowPath.FindPath_Ingress(); })), // If we've consumed our Ingress path (or the one we initially built is empty), we're done... new Decorator(context => !Path_Ingress.Any(), new Action(context => { State_MainBehavior = StateType_MainBehavior.DestinationReached; })), // If Mob_ToAvoid is too close or we get in combat, abandon current ingress, and retreat back to safespot... new Decorator(context => Query.IsViable(Mob_ToAvoid) && ((Mob_ToAvoid.Distance < FollowPath.EgressDistance) || Me.Combat), new Action(context => { Path_Ingress = null; Path_Egress = null; State_MainBehavior = StateType_MainBehavior.PathRetreating; })), new Switch <SafePathType.StrategyType>(context => FollowPath.Strategy, new Action(context => // default case { var message = string.Format("FollowPathStrategyType({0}) is unhandled", FollowPath.Strategy); QBCLog.MaintenanceError(message); TreeRoot.Stop(); BehaviorDone(message); }), new SwitchArgument <SafePathType.StrategyType>(SafePathType.StrategyType.StalkMobAtAvoidDistance, new Decorator(context => Query.IsViable(Mob_ToAvoid) && (Mob_ToAvoid.Distance < AvoidDistance), new PrioritySelector( new ActionRunCoroutine(context => CommonCoroutines.StopMoving()), new ActionAlwaysSucceed() ))), new SwitchArgument <SafePathType.StrategyType>(SafePathType.StrategyType.WaitForAvoidDistance, new PrioritySelector( // No addition action needed to implement strategy for now )) ), // If we've arrived at the current ingress waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(Path_Ingress.Peek().Location), new Action(context => { FollowPath.DismissPetIfNeeded(); Path_Ingress.Dequeue(); })), // Follow the prescribed ingress path, if its still safe to proceed... new Decorator(context => IsSafeToMoveToDestination(Mob_ToAvoid), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( Path_Ingress.Peek().Location, "follow ingress path", MovementBy))), // If mob is heading our direction, hold position... new Decorator(context => !IsSafeToMoveToDestination(Mob_ToAvoid), new Sequence( new Action(context => { TreeRoot.StatusText = string.Format("Holding position to evaluate {0}'s actions.", Mob_ToAvoid.SafeName); }), new ActionRunCoroutine(context => CommonCoroutines.StopMoving()) )) )); }
protected override Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update values for this BT node visit... new Action(context => { VehicleUnoccupied = FindUnoccupiedVehicle(); // Figure out our final destination (i.e., a location or a mob)... // NB: this can change as we travel. If our destination is a mob, // We can't "see" distant mobs until we get within 100 yards or so of them. // Until we close that distance, we'll head towards the provided location. // As soon as we "see" the mob, we'll switch to the mob as the destination. FinalDestination = Destination; FinalDestinationName = "destination"; if (MobIds.Count() > 0) { // If we can see our destination mob, calculate a path to it... var nearestMob = Query.FindMobsAndFactions(MobIds).OrderBy(u => u.Distance).FirstOrDefault() as WoWUnit; if (nearestMob != null) { // Target destination mob as feedback to the user... Utility.Target(nearestMob); FinalDestination = nearestMob.Location; FinalDestinationName = nearestMob.SafeName; } } return RunStatus.Failure; // fall thru }), // Proceed if we're not in combat, or are ignoring it... new Decorator(context => !Me.Combat || IgnoreCombat, new PrioritySelector( // If we were successfully mounted... // and within a few yards of our destination when we were dismounted, we must // assume we were auto-dismounted, and the behavior is complete... new Decorator(context => DidSuccessfullyMount && !IsInVehicle() && (WoWMovement.ActiveMover.Location.Distance(FinalDestination) < 15.0), new Action(context => { BehaviorDone(); })), // Enable combat while not in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) == 0 && !Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags |= BehaviorFlags.Combat)), // Disable combat while in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) != 0 && Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags &= ~BehaviorFlags.Combat)), // If we're not in a vehicle, go fetch one... new Decorator(context => !IsInVehicle() && Query.IsViable(VehicleUnoccupied), new Sequence( new CompositeThrottleContinue( Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0} {1}", VehicleUnoccupied.SafeName, Me.Combat ? "(ignoring combat)" : ""); })), new DecoratorContinue(context => VehicleUnoccupied.WithinInteractRange, new Action(context => { VehicleUnoccupied.Interact(); })), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( VehicleUnoccupied.Location, VehicleUnoccupied.SafeName, MovementBy)) )), // If we can't find a vehicle, terminate if requested... new CompositeThrottle( context => !IsInVehicle() && !Query.IsViable(VehicleUnoccupied), Throttle.UserUpdate, new Action(context => { if (!WaitForVehicle) { BehaviorDone(string.Format("No Vehicle, and WaitForVehicle=\"{0}\"", WaitForVehicle)); } else { TreeRoot.StatusText = "No vehicles in area--waiting for vehicle to become available."; } })), // Move vehicle to destination... new Decorator(context => IsInVehicle(), new PrioritySelector( // If we successfully mounted the vehicle, record the fact... new Decorator(context => !DidSuccessfullyMount, new Action(context => { DidSuccessfullyMount = true; })), new Decorator(context => !Navigator.AtLocation(FinalDestination), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( FinalDestination, FinalDestinationName, MovementBy))), new Decorator(context => WoWMovement.ActiveMover.IsMoving, new Action(context => { WoWMovement.MoveStop(); })), // Arrived at destination, use spell if necessary... // NB: We want to make certain movement is settled before we attempt // to cast spell, so we won't be interrupted. new SleepForLagDuration(), CreateSpellBehavior() )) )), // Squelch combat, if requested... new Decorator(context => IgnoreCombat, new ActionAlwaysSucceed()) ))); }
protected override Composite CreateBehavior() { return(_Root ?? (_Root = new PrioritySelector(context => !s_isBehaviorDone, #region MyHotSpot // Store our current location. new Decorator(context => MyHotSpot == WoWPoint.Empty, new Sequence( new DecoratorContinue(context => Me.IsMoving, new WaitContinue(TimeSpan.FromMilliseconds(2000), context => false, new ActionAlwaysSucceed()) ), new DecoratorContinue(context => !Me.IsMoving, new Action(context => MyHotSpot = Me.Location) ) ) ), #endregion #region MinLevel // Should we check for partymember minumum level ? new Decorator(context => (MinLevel > 0), new Sequence( // Someone is below MinLevel. new DecoratorContinue(context => !CheckLevel(), new Sequence( new Action(context => QBCLog.Info("Someone in your party is below level {0}.", MinLevel)), new Action(context => s_isBehaviorDone = true) ) ), // Everyone is equal or above MinLevel. new DecoratorContinue(context => CheckLevel(), new Action(context => MinLevel = 0) ) ) ), #endregion #region CheckRange // Should we wait for party members to be in range ? new Decorator(context => (CheckRange != 0), new Sequence( // Everyone isn't within interact range, lets wait abit before checking again. new DecoratorContinue(context => !CheckPartyRange(), new Sequence( new DecoratorContinue(context => !Navigator.AtLocation(MyHotSpot), new Sequence( new DecoratorContinue(context => Navigator.CanNavigateFully(Me.Location, MyHotSpot), new Action(context => Navigator.MoveTo(MyHotSpot)) ), new DecoratorContinue(context => !Navigator.CanNavigateFully(Me.Location, MyHotSpot), new Action(context => Flightor.MoveTo(MyHotSpot)) ) ) ), new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed()) ) ), // Everyone is within interact range. new DecoratorContinue(context => CheckPartyRange(), new Sequence( new Action(context => QBCLog.Info("Everyone is within range.")), new Action(context => CheckRange = 0) ) ) ) ), #endregion #region ChkExp // Disabled until I can find out a safer way to to it. /* * new Decorator(context => (ChkExp != 0), * new Sequence( * new DecoratorContinue(context => !AreWeDone(), * new Action(context => CheckExpansions()) * ), * new DecoratorContinue(context => AreWeDone(), * new Sequence( * new DecoratorContinue(context => !DoAllHaveExp(), * new Sequence( * new Action(context => QBCLog.Info("Everyone in your group doesn't have ExpansionLevel '{0}'", ChkExp)), * new Action(context => _isBehaviorDone = true) * ) * ), * new DecoratorContinue(context => DoAllHaveExp(), * new Sequence( * new Action(context => QBCLog.Info("Everyone has atleast ExpansionLevel '{0}'", ChkExp)), * new Action(context => ChkExp = 0) * ) * ) * ) * ) * ) * ), */ #endregion #region RemotePath // Load the remote profile... new Decorator(context => RemotePath != "", new Sequence( // You have included a RemotePath but not a ProfileName. new DecoratorContinue(context => ProfileName == "", new Sequence( new Action(context => QBCLog.Error("You need to include a ProfileName.")), new Action(context => s_isBehaviorDone = true) ) ), // Remote Profile doesn't exist. new DecoratorContinue(context => (ProfileName != "" && !UrlExists(NewRemoteProfilePath)), new Sequence( new Action(context => QBCLog.Error("Profile '{0}' does not exist.", ProfileName)), new Action(context => s_isBehaviorDone = true) ) ), // Everything is ok, Load the remote Profile new DecoratorContinue(context => (ProfileName != "" && UrlExists(NewRemoteProfilePath)), new Sequence( new Action(context => TreeRoot.StatusText = "Loading profile '" + ProfileName + "'"), new Action(context => QBCLog.Info("Loading profile '{0}'", ProfileName)), new Action(context => ProfileManager.LoadNew(new MemoryStream(new WebClient().DownloadData(NewRemoteProfilePath)))), new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed()), new Action(context => s_isBehaviorDone = true) ) ) ) ), #endregion #region ProfileName // Load the local profile... new Decorator(context => (ProfileName != "" && RemotePath == ""), new PrioritySelector( // Local Profile doesn't exist. new Decorator(context => !IsStoreProfile && !File.Exists(NewLocalProfilePath), new Sequence( new Action(context => QBCLog.Error("Profile '{0}' does not exist.", ProfileName)), new Action(context => s_isBehaviorDone = true) ) ), // Everything is ok, Load the local Profile. new Sequence( new Action(context => TreeRoot.StatusText = "Loading profile '" + ProfileName + "'"), new Action(context => QBCLog.Error("Loading profile '{0}'", ProfileName)), new Action(context => ProfileManager.LoadNew(NewLocalProfilePath, false)), new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed()), new Action(context => s_isBehaviorDone = true) ) ) ), #endregion #region Behavior Done // Everyone is within interact range and we shouldn't load a profile, then end the Quest Behavior. new Decorator(context => !s_isBehaviorDone, new Action(context => s_isBehaviorDone = true) ) #endregion ) )); }
private async Task <bool> StateCoroutine_MountingVehicle() { if (Me.IsQuestComplete(QuestId)) { BehaviorDone(); return(true); } if (IsInBalloon()) { await SubCoroutine_InitializeVehicleAbilities(); BehaviorState = BehaviorStateType.RidingOutToHuntingGrounds; return(true); } // Locate a vehicle to mount... if (!Query.IsViable(Vehicle)) { Vehicle = Query.FindMobsAndFactions(Utility.ToEnumerable(MobId_SteamwheedleRescueBalloon)) .FirstOrDefault() as WoWUnit; if (Query.IsViable(Vehicle)) { Utility.Target(Vehicle); return(true); } // No vehicle found, move to staging area... if (!Navigator.AtLocation(VehicleStagingArea)) { return(await UtilityCoroutine.MoveTo(VehicleStagingArea, "Vehicle Staging Area", MovementBy)); } await(_updateUser_MountingVehicle_waitingForSpawn ?? (_updateUser_MountingVehicle_waitingForSpawn = new ThrottleCoroutineTask( Throttle.UserUpdate, async() => TreeRoot.StatusText = string.Format("Waiting for {0} to respawn.", Utility.GetObjectNameFromId(MobId_SteamwheedleRescueBalloon))))); // Wait for vehicle to respawn... return(true); } // Wait for vehicle to respawn... await(_updateUser_MountingVehicle_movingToVehicle ?? (_updateUser_MountingVehicle_movingToVehicle = new ThrottleCoroutineTask( Throttle.UserUpdate, async() => TreeRoot.StatusText = string.Format("Moving to {0}", Vehicle.SafeName)))); if (!Vehicle.WithinInteractRange) { return(await UtilityCoroutine.MoveTo(Vehicle.Location, Vehicle.SafeName, MovementBy)); } if (Me.IsMoving) { await CommonCoroutines.StopMoving(); } if (Me.Mounted && await UtilityCoroutine.ExecuteMountStrategy( MountStrategyType.DismountOrCancelShapeshift)) { return(true); } // If we got booted out of a vehicle for some reason, reset the weapons... WeaponLifeRocket = null; WeaponPirateDestroyingBomb = null; WeaponEmergencyRocketPack = null; Utility.Target(Vehicle); await Coroutine.Sleep((int)Delay.AfterInteraction.TotalMilliseconds); Vehicle.Interact(); await Coroutine.Wait(10000, IsInBalloon); return(true); }
private async Task <bool> MainCoroutine() { // break if we are done or we are not in combat and targting is not empty, we want the botbase to clear path for us. if (IsDone || (!Me.Combat && Targeting.Instance.FirstUnit != null) || !Me.IsAlive) { return(false); } if (!Query.IsViable(SelectedNpc)) { SelectedNpc = GetNpc(); } if (!Query.IsViable(SelectedNpc) || !Me.IsActuallyInCombat && Targeting.Instance.FirstUnit == null) { // move to search area if (SearchLocation != Vector3.Zero && !Navigator.AtLocation(SearchLocation)) { await UtilityCoroutine.MoveTo(SearchLocation, "Search Area", MovementBy); } // Dismount after reaching search location. else if ((SearchLocation == Vector3.Zero || Navigator.AtLocation(SearchLocation)) && Me.Mounted) { await UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.Dismount); } else { TreeRoot.StatusText = "Waiting for NPC to spawn"; } return(true); } if (SelectedNpc.IsDead && SelectedNpc.TaggedByMe && !VariantQuestIds.Any()) { BehaviorDone(); return(true); } if (SelectedNpc.HasAura(ImmunityAuraId)) { if (BotPoi.Current.AsObject == SelectedNpc) { BotPoi.Clear("Mob is immune"); } var targetedMob = Targeting.Instance.FirstUnit; if (targetedMob != null && ImmunityBreakingMobIds.Contains((int)targetedMob.Entry)) { if (targetedMob.IsTargetingMeOrPet) { // move close enough to shielded NPC so that the exploding mobs will hit it when killed. var myMinDistance = Math.Max(2, MaxRange - targetedMob.MeleeRange); if (SelectedNpc.DistanceSqr > myMinDistance * myMinDistance) { TreeRoot.StatusText = string.Format("Moving closer to {0} before killing {1}", SelectedNpc.SafeName, targetedMob.SafeName); Navigator.MoveTo(SelectedNpc.Location); return(true); } // wait for exploding mob to get within range of shielded mob. if (targetedMob.Location.DistanceSquared(SelectedNpc.Location) > MaxRange * MaxRange) { TreeRoot.StatusText = string.Format( "Waiting for {0} to move withing range of {1}", targetedMob.SafeName, SelectedNpc.SafeName); return(true); } } } } return(false); }
public static async Task <bool> DoFishing() { if (AutoAnglerBot.Instance.Profile.FishAtHotspot && !Navigator.AtLocation(AutoAnglerBot.Instance.Profile.CurrentPoint)) { return(false); } if (AutoAnglerSettings.Instance.Poolfishing && BotPoi.Current.Type != PoiType.Harvest) { return(false); } if (await CheckLootFrame()) { return(true); } // refresh water walking if needed if (!Me.Mounted && WaterWalking.CanCast && !WaterWalking.IsActive && await WaterWalking.Cast()) { return(true); } if (AutoAnglerSettings.Instance.Poolfishing) { var pool = BotPoi.Current.AsObject as WoWGameObject; if (pool == null || !pool.IsValid) { BotPoi.Clear(); return(false); } if (await MoveToPool(pool)) { return(true); } } if (await EquipPole()) { return(true); } if (await EquipHat()) { return(true); } if (await Applylure()) { return(true); } if (await Applybait()) { return(true); } if (!AutoAnglerSettings.Instance.Poolfishing && AutoAnglerBot.Instance.ShouldFaceWaterNow) { AutoAnglerBot.Instance.ShouldFaceWaterNow = false; if (await FaceWater()) { return(true); } } if (Me.Mounted && await CommonCoroutines.Dismount("Fishing")) { return(true); } if (!await Coroutine.Wait(10000, () => !Me.IsFalling)) { AutoAnglerBot.Log("Falling for 10 seconds; I don't think this will end good."); return(false); } if (Me.IsSwimming) { await JumpOnWaterSurface(); } if (Me.IsMoving) { WoWMovement.MoveStop(); if (!await Coroutine.Wait(4000, () => !Me.IsMoving)) { return(false); } } // Checks if we got a bite and recasts if needed. if (await CheckFishLine()) { return(true); } return(false); }