Beispiel #1
0
        public JadeForestTakeNoPrisoners(Dictionary <string, string> args)
            : base(args)
        {
            QBCLog.BehaviorLoggingContext = this;

            try
            {
                VariantQuestIds = VariantQuestIds.Any() ? VariantQuestIds : new HashSet <int> {
                    29727
                };
                QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete;
                QuestRequirementInLog    = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog;
            }

            catch (Exception except)
            {
                // Maintenance problems occur for a number of reasons.  The primary two are...
                // * Changes were made to the behavior, and boundary conditions weren't properly tested.
                // * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes.
                // In any case, we pinpoint the source of the problem area here, and hopefully it
                // can be quickly resolved.
                QBCLog.Exception(except);
                IsAttributeProblem = true;
            }
        }
        /// <summary>
        /// Searches player's quest log and list of completed quests for a quest specified by
        /// QuestId and <see cref="VariantQuestIds"/>,
        /// and returns the id if found; otherwise returns first quest provided by QuestId/VariantQuestIds
        /// </summary>
        /// <returns></returns>
        protected int GetQuestId()
        {
            var questInLog = GetQuestInLog();

            if (questInLog != null)
            {
                return((int)questInLog.Id);
            }

            var completedQuests  = new HashSet <uint>(StyxWoW.Me.QuestLog.GetCompletedQuests());
            var completedQuestId = VariantQuestIds
                                   .FirstOrDefault(id => completedQuests.Contains((uint)id));

            if (completedQuestId != 0)
            {
                return(completedQuestId);
            }

            return(VariantQuestIds.Any() ? VariantQuestIds.Min() : 0);
        }
        protected override void EvaluateUsage_SemanticCoherency(XElement xElement)
        {
            UsageCheck_SemanticCoherency(xElement,
                                         ((UseWhenMeHasAuraId <= 0) &&
                                          (UseWhenMeMissingAuraId <= 0) &&
                                          (UseWhenMobCastingSpellId <= 0) &&
                                          (UseWhenMobHasAuraId <= 0) &&
                                          (UseWhenMobMissingAuraId <= 0) &&
                                          (UseWhenMobHasHealthPercent <= 0)),
                                         context => "One or more of the following attributes must be specified:\n"
                                         + "UseWhenMeHasAuraId, UseWhenMeMissingAuraId, UseWhenMobCastingSpellId,"
                                         + " UseWhenMobHasAuraId, UseWhenMobMissingAuraId, UseWhenMobHasHealthPercent");

            UsageCheck_SemanticCoherency(xElement,
                                         ((ItemAppliesAuraId <= 0) &&
                                          (!ItemUseAlwaysSucceeds) &&
                                          ((UseItemStrategy == UseItemStrategyType.UseItemOncePerTarget) ||
                                           (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend) ||
                                           (!VariantQuestIds.Any()))),
                                         context => string.Format("For a UseItemStrategy of {0}, ItemAppliesAuraId must be specified",
                                                                  UseItemStrategy));
        }
Beispiel #4
0
        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);
        }
        /// <summary>
        /// <para>This reports problems, and stops BT processing if there was a problem with attributes...
        /// We had to defer this action, as the 'profile line number' is not available during the element's
        /// constructor call.</para>
        /// <para>It also captures the user's configuration, and installs Behavior Tree hooks.  The items will
        /// be restored when the behavior terminates, or Honorbuddy is stopped.</para>
        /// </summary>
        /// <return>true, if the behavior should run; false, if it should not.</return>
        /// <param name="extraGoalTextDescription"></param>
        protected bool OnStart_QuestBehaviorCore(string extraGoalTextDescription = null)
        {
            // Semantic coherency / covariant dependency checks...
            UsageCheck_SemanticCoherency(Element, QuestObjectiveIndex > 0 && !VariantQuestIds.Any(),
                                         context => $"QuestObjectiveIndex of '{QuestObjectiveIndex}' specified, but no corresponding QuestId provided");

            UsageCheck_SemanticCoherency(Element,
                                         _providedQuestIdAndQuestVariantIds,
                                         context => "Cannot provide both a QuestId and VariantQuestIds at same time.");

            EvaluateUsage_SemanticCoherency(Element);

            // Deprecated attributes...
            EvaluateUsage_DeprecatedAttributes(Element);

            // This reports problems, and stops BT processing if there was a problem with attributes...
            // We had to defer this action, as the 'profile line number' is not available during the element's
            // constructor call.
            OnStart_HandleAttributeProblem();

            var questId = GetQuestId();

            // If the quest is complete, this behavior is already done...
            // So we don't want to falsely inform the user of things that will be skipped.
            // NB: Since the IsDone property may skip checking the 'progress conditions', we need to explicltly
            // check them here to see if we even need to start the behavior.
            if (!(IsDone || !UtilIsProgressRequirementsMet(questId, QuestRequirementInLog, QuestRequirementComplete)))
            {
                this.UpdateGoalText(questId, extraGoalTextDescription);

                // Start the timer to measure the behavior run time...
                _behaviorRunTimer.Restart();

                // Monitored Behaviors...
                if (QuestBehaviorCoreSettings.Instance.MonitoredBehaviors.Contains(GetType().Name))
                {
                    QBCLog.Debug("MONITORED BEHAVIOR: {0}", GetType().Name);
                    AudibleNotifyOn(true);
                }

                _configMemento = CreateConfigMemento();

                if (Targeting.Instance != null)
                {
                    Targeting.Instance.IncludeTargetsFilter += TargetFilter_IncludeTargets;
                    Targeting.Instance.RemoveTargetsFilter  += TargetFilter_RemoveTargets;
                    Targeting.Instance.WeighTargetsFilter   += TargetFilter_WeighTargets;
                }

                Query.InCompetitionReset();
                Utility.BlacklistsReset();

                _behaviorTreeHook_CombatMain   = BehaviorHookInstall("Combat_Main", CreateBehavior_CombatMain());
                _behaviorTreeHook_CombatOnly   = BehaviorHookInstall("Combat_Only", CreateBehavior_CombatOnly());
                _behaviorTreeHook_DeathMain    = BehaviorHookInstall("Death_Main", CreateBehavior_DeathMain());
                _behaviorTreeHook_QuestbotMain = BehaviorHookInstall("Questbot_Main", CreateBehavior_QuestbotMain());

                BlackspotManager.AddBlackspots(_temporaryBlackspots.GetBlackspots());

                if (_temporaryAvoidMobs != null)
                {
                    foreach (var avoidMobId in _temporaryAvoidMobs.GetAvoidMobIds())
                    {
                        // NB: ProfileManager.CurrentProfile.AvoidMobs will never be null
                        if (!ProfileManager.CurrentProfile.AvoidMobs.Contains(avoidMobId))
                        {
                            ProfileManager.CurrentProfile.AvoidMobs.Add(avoidMobId);
                        }
                    }
                }

                return(true);    // behavior should run
            }

            return(false);   // behavior should NOT run
        }
        private Composite SubBehavior_CombatWithViableMob()
        {
            return(new PrioritySelector(context => SelectedTarget = Me.CurrentTarget,
                                        // Recall pet, if necessary...
                                        new Decorator(context => (SelectedTarget.HealthPercent < RecallPetAtMobPercentHealth) &&
                                                      (Me.GotAlivePet && Me.Pet.GotTarget),
                                                      new ActionFail(context =>
            {
                QBCLog.Info("Recalling Pet from '{0}' (health: {1:F1})",
                            SelectedTarget.SafeName, SelectedTarget.HealthPercent);
                PetControl.SetStance_Passive();
                PetControl.Follow();
            })),

                                        // If we are beyond the max range allowed to use the item, move within range...
                                        new Decorator(context => SelectedTarget.Distance > MaxRangeToUseItem,
                                                      new ActionRunCoroutine(
                                                          interactUnitContext => UtilityCoroutine.MoveTo(
                                                              SelectedTarget.Location,
                                                              string.Format("within {0} feet of {1}", MaxRangeToUseItem, SelectedTarget.SafeName),
                                                              MovementBy,
                                                              (float)MaxRangeToUseItem))),

                                        // If time to use the item, do so...
                                        new Decorator(context => IsUseItemNeeded(SelectedTarget),
                                                      new PrioritySelector(
                                                          new ActionRunCoroutine(context => CommonCoroutines.StopMoving()),

                                                          // Halt combat until we are able to use the item...
                                                          new Decorator(context => ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) ||
                                                                                    (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)),
                                                                        new ActionFail(context =>
            {
                // We use LUA to stop casting, since SpellManager.StopCasting() doesn't seem to work...
                if (Me.IsCasting)
                {
                    Lua.DoString("SpellStopCasting()");
                }

                if (Me.IsAutoAttacking)
                {
                    Lua.DoString("StopAttack()");
                }

                TreeRoot.StatusText = string.Format("Combat halted--waiting for {0} to become usable.",
                                                    Utility.GetItemNameFromId(ItemId));
            })),

                                                          new Sequence(
                                                              new ActionRunCoroutine(ctx =>
                                                                                     UtilityCoroutine.UseItemOnTarget(
                                                                                         ItemId,
                                                                                         SelectedTarget,
                                                                                         () => BehaviorDone(string.Format("Terminating behavior due to missing {0}",
                                                                                                                          Utility.GetItemNameFromId(ItemId))))),
                                                              // Allow a brief time for WoWclient to apply aura to mob...
                                                              new WaitContinue(TimeSpan.FromMilliseconds(5000),
                                                                               context => ItemUseAlwaysSucceeds || SelectedTarget.HasAura(ItemAppliesAuraId),
                                                                               new ActionAlwaysSucceed()),
                                                              new ActionFail(context =>
            {
                _waitTimerAfterUsingItem.Reset();

                if (ItemUseAlwaysSucceeds || SelectedTarget.HasAura(ItemAppliesAuraId))
                {
                    // Count our success if no associated quest...
                    if (!VariantQuestIds.Any())
                    {
                        ++Counter;
                    }

                    // If we can only use the item once per target, blacklist this target from subsequent selection...
                    if ((UseItemStrategy == UseItemStrategyType.UseItemOncePerTarget) ||
                        (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend))
                    {
                        SelectedTarget.BlacklistForInteracting(TimeSpan.FromSeconds(InteractBlacklistTimeInSeconds));
                    }

                    // If we can't defend ourselves from the target, blacklist it for combat and move on...
                    if (Query.IsViable(SelectedTarget) &&
                        ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) ||
                         (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)))
                    {
                        SelectedTarget.BlacklistForCombat(TimeSpan.FromSeconds(InteractBlacklistTimeInSeconds));
                        BotPoi.Clear();
                        Me.ClearTarget();
                        SelectedTarget = null;
                    }
                }

                if ((ItemAppliesAuraId > 0) && !SelectedTarget.HasAura(ItemAppliesAuraId))
                {
                    var auraNamesOnMob = ((SelectedTarget.Auras.Keys.Count > 0)
                                                            ? string.Join(", ", SelectedTarget.Auras.Keys)
                                                            : "none");

                    QBCLog.Warning("{1} did not acquire expected AuraId, \"{2}\"--retrying.{0}"
                                   + "    Auras on {1}: {3}",
                                   Environment.NewLine,
                                   SelectedTarget.SafeName,
                                   Utility.GetSpellNameFromId(ItemAppliesAuraId),
                                   auraNamesOnMob);
                }
            }),

                                                              // Prevent combat, if we're not supposed to defend...
                                                              new Decorator(context => ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) ||
                                                                                        (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)),
                                                                            new ActionAlwaysSucceed())
                                                              )))
                                        ));
        }