Esempio n. 1
0
        /// <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);
        }
Esempio n. 3
0
        /// <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);
        }