/// <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 bool CheckTermination() { if (TerminationChecksQuestProgress) { if (Me.IsQuestObjectiveComplete(QuestId, QuestObjectiveIndex)) { return(true); } if (!UtilIsProgressRequirementsMet(QuestId, QuestRequirementInLog, QuestRequirementComplete)) { return(true); } } if (_behaviorRunTimer.ElapsedMilliseconds / 1000 >= TerminateAtMaxRunTimeSecs) { QBCLog.Info("Terminating due to 'max run time' expiry."); return(true); } return(false); }
/// <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); }