예제 #1
0
        private async Task <bool> GetInVehicleLogic()
        {
            // currently we only support using an item to get into vehicle
            if (ItemId > 0)
            {
                if (Me.IsFalling)
                {
                    return(false);
                }
                var item = Me.BagItems.FirstOrDefault(i => i.Entry == ItemId);
                if (item == null)
                {
                    QBCLog.Fatal("No Item with ID {0} was found in bags", ItemId);
                    return(false);
                }

                item.Use();

                if (!await Coroutine.Wait(6000, Query.IsInVehicle))
                {
                    QBCLog.Warning("Could not get into vehicle by using {0}.", item.SafeName);
                    return(false);
                }
                CycleToNearestPointInPath();
                _flightTimer.Reset();
            }
            else
            {
                QBCLog.Fatal("Not in a vehicle");
            }
            await Ascend(3000);

            return(true);
        }
        public override void OnStart()
        {
            // 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();

            // 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.
            if (!IsDone)
            {
                PlayerQuest quest = StyxWoW.Me.QuestLog.GetQuestById((uint)QuestId);

                this.UpdateGoalText(QuestId);

                if (quest != null)
                {
                    if (!quest.IsCompleted)
                    {
                        QBCLog.Fatal("Quest({0}, \"{1}\") is not complete.", QuestId, QuestName);
                        _forcedDone = true;
                    }
                }

                else
                {
                    QBCLog.Warning("Quest({0}) is not in our log--skipping turn in.", QuestId);
                    _forcedDone = true;
                }
            }
        }
예제 #3
0
        private static void CheckWeaponStatus()
        {
            SetIDs();

            if (HasMainHand)
            {
                if (EnchantID != WeaponMainHandEnchantID)
                {
                    HandleEnchanting("main");
                    return;
                }

                if (HasOffHand && EnchantID != WeaponOffHandEnchantID)
                {
                    HandleEnchanting("off");
                    return;
                }

                // Leave
                if (s_Me.ZoneId == 139)
                {
                    CastDeathgate();
                    TakeDeathgate();
                    return;
                }

                IsBehaviorDone = true;
            }
            else
            {
                QBCLog.Warning("You have no main hand weapon equipped.");
                IsBehaviorDone = true;
            }
        }
        private async Task <bool> StateCoroutine_CompletingObjectives()
        {
            // If for some reason no longer in the vehicle, go fetch another...
            if (!IsInBalloon())
            {
                QBCLog.Warning("We've been jettisoned from vehicle unexpectedly--will try again.");
                BehaviorState = BehaviorStateType.MountingVehicle;
                return(true);
            }

            // If quest is complete, then head back...
            if (Me.IsQuestComplete(GetQuestId()))
            {
                BehaviorState = BehaviorStateType.ReturningToBase;
                return(true);
            }

            await(_updateUser_CompletingObjectives ?? (_updateUser_CompletingObjectives =
                                                           new ThrottleCoroutineTask(
                                                               Throttle.UserUpdate,
                                                               async() => TreeRoot.StatusText = "Completing Quest Objectives")));

            // Select new best target, if our current one is no longer useful...
            if (!IsViableForTargeting(SelectedTarget))
            {
                var questId = GetQuestId();
                if (!IsViableForTargeting(SelectedTarget) && !Me.IsQuestObjectiveComplete(questId, 1))
                {
                    SelectedTarget = FindBestTarget(MobId_Objective1_SteamwheedleSurvivor);
                    WeaponChoice   = WeaponLifeRocket;
                }

                if (!IsViableForTargeting(SelectedTarget) && !Me.IsQuestObjectiveComplete(questId, 2))
                {
                    SelectedTarget = FindBestTarget(MobId_Objective2_SouthseaBlockader);
                    WeaponChoice   = WeaponPirateDestroyingBomb;
                }
            }
            // Aim & Fire at the selected target...
            else
            {
                // If weapon aim cannot address selected target, blacklist target for a few seconds...
                if (!WeaponChoice.WeaponAim(SelectedTarget))
                {
                    _targetBlacklist.Add(SelectedTarget, TimeSpan.FromSeconds(5));
                    return(false);
                }

                // If weapon could not be fired, wait for it to become ready...
                if (!WeaponChoice.WeaponFire())
                {
                    return(false);
                }

                // Weapon was fired, blacklist target so we can choose another...
                _targetBlacklist.Add(SelectedTarget, TimeSpan.FromSeconds(15));
                await Coroutine.Sleep((int)Delay.AfterWeaponFire.TotalMilliseconds);
            }
            return(true);
        }
        private async Task <bool> MainBehavior()
        {
            QBCLog.Info("Using hearthstone; {0} out of {1} tries", ++_retries, MaxRetries);
            bool onCooldown = false;
            await UtilityCoroutine.UseHearthStone(
                UseGarrisonHearthstone,
                hearthOnCooldownAction : () => onCooldown = true,
                hearthCastFailedAction : reason =>
            {
                QBCLog.Warning("Hearth failed. Reason: {0}", reason);
                _retries++;
            });

            if (_retries >= MaxRetries)
            {
                BehaviorDone(string.Format("We have reached our max number of tries ({0}) without successfully hearthing", MaxRetries));
                return(true);
            }

            if (onCooldown && WaitOnCd)
            {
                TreeRoot.StatusText = "Waiting for hearthstone cooldown";
                return(true);
            }

            BehaviorDone();
            return(true);
        }
예제 #6
0
        private Composite CreateSpellBehavior()
        {
            string luaCastSpellCommand         = string.Format("CastSpellByID({0})", SpellId);
            string luaCooldownCommand          = string.Format("return GetSpellCooldown({0})", SpellId);
            string luaRetrieveSpellInfoCommand = string.Format("return GetSpellInfo({0})", SpellId);

            // If we have a spell to cast, one or more times...
            // NB: Since the spell we want to cast is associated with the vehicle, if we get auto-ejected
            // from the vehicle after we arrive at our destination, then there is no way to cast the spell.
            // If we get auto-ejected, we don't try to cast.
            return(new Decorator(context => IsInVehicle() && (SpellId > 0),
                                 new PrioritySelector(
                                     // Stop moving so we can cast...
                                     new Decorator(context => WoWMovement.ActiveMover.IsMoving,
                                                   new Action(context => { WoWMovement.MoveStop(); })),

                                     // If we cannot retrieve the spell info, its a bad SpellId...
                                     new Decorator(context => string.IsNullOrEmpty(Lua.GetReturnVal <string>(luaRetrieveSpellInfoCommand, 0)),
                                                   new Action(context =>
            {
                QBCLog.Warning("SpellId({0}) is not known--ignoring the cast", SpellId);
                CastCounter = NumOfTimes + 1;             // force 'done'
            })),

                                     // If the spell is on cooldown, we need to wait...
                                     new Decorator(context => Lua.GetReturnVal <double>(luaCooldownCommand, 1) > 0.0,
                                                   new Action(context => { TreeRoot.StatusText = "Waiting for cooldown"; })),

                                     // Cast the required spell...
                                     new Sequence(
                                         new Action(context =>
            {
                WoWSpell wowSpell = WoWSpell.FromId(SpellId);
                TreeRoot.StatusText = string.Format("Casting {0}", (wowSpell != null) ? wowSpell.Name : string.Format("SpellId({0})", SpellId));

                // NB: we use LUA to cast the spell.  As some vehicle abilities cause
                // a "Spell not learned" error.  Apparently, HB only keeps up with
                // permanent spells known by the toon, and not transient spells that become
                // available in vehicles.
                Lua.DoString(luaCastSpellCommand);
                ++CastCounter;

                // If we're objective bound, the objective needs to complete regardless of the counter...
                if ((QuestObjectiveIndex <= 0) && (CastCounter >= NumOfTimes))
                {
                    BehaviorDone();
                }
            }),
                                         new WaitContinue(TimeSpan.FromMilliseconds(CastTime), context => false, new ActionAlwaysSucceed())
                                         )
                                     )));
        }
        private Composite StateBehaviorPS_CompletingObjectives()
        {
            return(new PrioritySelector(
                       // If for some reason no longer in the vehicle, go fetch another...
                       new Decorator(context => !IsInTank(),
                                     new Action(context =>
            {
                QBCLog.Warning("We've been jettisoned from vehicle unexpectedly--will try again.");
                BehaviorState = BehaviorStateType.MountingVehicle;
            })),

                       // If quest is complete, then head back...
                       new Decorator(context => Me.IsQuestObjectiveComplete(QuestId, 1),
                                     new Action(context => { BehaviorState = BehaviorStateType.ReturningToBase; })),

                       new CompositeThrottle(Throttle.UserUpdate,
                                             new Action(context => { TreeRoot.StatusText = "Completing Quest Objectives"; })),

                       // Select new best target, if our current one is no longer useful...
                       new Decorator(context => !IsViableForTargeting(SelectedTarget),
                                     new ActionFail(context =>
            {
                SelectedTarget = FindBestTarget(MobId_Objective1_DecrepitWatcher);
                // fall through
            })),

                       // Aim & Fire at the selected target...
                       new Decorator(context => IsViableForTargeting(SelectedTarget),
                                     new Sequence(
                                         new Action(context =>
            {
                // If weapon aim cannot address selected target, blacklist target for a few seconds...
                if (!WeaponFireCannon.WeaponAim(SelectedTarget))
                {
                    _targetBlacklist.Add(SelectedTarget, TimeSpan.FromSeconds(5));
                    return RunStatus.Failure;
                }

                // If weapon could not be fired, wait for it to become ready...
                if (!WeaponFireCannon.WeaponFire())
                {
                    return RunStatus.Failure;
                }

                return RunStatus.Success;
            }),
                                         new WaitContinue(Delay.AfterWeaponFire, context => false, new ActionAlwaysSucceed())
                                         ))
                       ));
        }
        private void UtilReportUnrecognizedAttributes()
        {
            var unrecognizedAttributes = (from attributeName in Attributes.Keys
                                          where !_recognizedAttributes.Contains(attributeName)
                                          orderby attributeName
                                          select attributeName);

            foreach (string attributeName in unrecognizedAttributes)
            {
                QBCLog.Warning(QBCLog.BuildMessageWithContext(Element,
                                                              "Attribute '{1}' is not a recognized attribute--ignoring it.",
                                                              Environment.NewLine,
                                                              attributeName));
            }
        }
        private Composite StateBehaviorPS_RidingOutToHuntingGrounds()
        {
            return(new PrioritySelector(
                       // If for some reason no longer in the vehicle, go fetch another...
                       new Decorator(context => !IsInTank(),
                                     new Action(context =>
            {
                QBCLog.Warning("We've been jettisoned from vehicle unexpectedly--will try again.");
                BehaviorState = BehaviorStateType.MountingVehicle;
            })),

                       new Decorator(context => WeaponFireCannon.IsWeaponUsable(),
                                     new Action(context => { BehaviorState = BehaviorStateType.CompletingObjectives; })),

                       new CompositeThrottle(Throttle.UserUpdate,
                                             new Action(context => { TreeRoot.StatusText = "Riding out to hunting grounds"; }))
                       ));
        }
예제 #10
0
        public override void OnStart()
        {
            // 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();

            // 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.
            if (!IsDone)
            {
                PlayerQuest quest = StyxWoW.Me.QuestLog.GetQuestById((uint)QuestId);

                if (quest == null)
                {
                    QBCLog.Warning("Cannot find quest with QuestId({0}).", QuestId);
                    _isBehaviorDone = true;
                }

                else if (quest.IsCompleted && (Type != AbandonType.All))
                {
                    QBCLog.Warning("Quest({0}, \"{1}\") is Complete--skipping abandon.", QuestId, quest.Name);
                    _isBehaviorDone = true;
                }

                else if (!quest.IsFailed && (Type == AbandonType.Failed))
                {
                    QBCLog.Warning("Quest({0}, \"{1}\") has not Failed--skipping abandon.", QuestId, quest.Name);
                    _isBehaviorDone = true;
                }

                else
                {
                    TreeRoot.GoalText = string.Format("Abandoning QuestId({0}): \"{1}\"", QuestId, quest.Name);
                    StyxWoW.Me.QuestLog.AbandonQuestById((uint)QuestId);
                    QBCLog.Info("Quest({0}, \"{1}\") successfully abandoned", QuestId, quest.Name);

                    _waitTimerAfterAbandon.WaitTime = TimeSpan.FromMilliseconds(WaitTime);
                    _waitTimerAfterAbandon.Reset();
                }
            }
        }
예제 #11
0
        private static void NavigateToTeleporter()
        {
            // Upper teleporter - 207580
            // Lower teleporter - 207581
            Teleporter = ObjectManager.GetObjectsOfTypeFast <WoWObject>().FirstOrDefault(teleportPad => teleportPad.IsValid && teleportPad.Entry == 207580);

            if (Teleporter == null)
            {
                QBCLog.Warning("No teleporter found.");
                return;
            }

            if (Teleporter != null && Teleporter.Location.Distance(s_Me.Location) <= 3)
            {
                TookTeleporter = true;
                return;
            }

            Navigator.MoveTo(Teleporter.Location);
        }
        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);
        }
예제 #13
0
        public BasicVehicleBehaviour(Dictionary <string, string> args)
            : base(args)
        {
            QBCLog.BehaviorLoggingContext = this;

            try
            {
                QBCLog.Warning("*****\n"
                               + "* THIS BEHAVIOR IS DEPRECATED, and will be retired on July 31th 2012.\n"
                               + "*\n"
                               + "* BasicVehicleBehavior adds _no_ _additonal_ _value_ over the VehicleMover behavior.\n"
                               + "* Please update the profile to use the VehicleMover behavior."
                               + "*****");

                LocationDest             = GetAttributeAsNullable <Vector3>("", true, ConstrainAs.Vector3NonEmpty, new[] { "Dest" }) ?? Vector3.Zero;
                LocationMount            = GetAttributeAsNullable <Vector3>("Mount", true, ConstrainAs.Vector3NonEmpty, null) ?? Vector3.Zero;
                QuestId                  = GetAttributeAsNullable <int>("QuestId", false, ConstrainAs.QuestId(this), null) ?? 0;
                QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete;
                QuestRequirementInLog    = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog;
                SpellCastId              = GetAttributeAsNullable <int>("SpellId", false, ConstrainAs.SpellId, null) ?? 0;
                VehicleId                = GetAttributeAsNullable <int>("VehicleId", true, ConstrainAs.VehicleId, null) ?? 0;

                MountedPoint = Vector3.Zero;
            }

            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;
            }
        }
예제 #14
0
        private async Task <bool> StateCoroutine_RidingOutToHuntingGrounds()
        {
            // If for some reason no longer in the vehicle, go fetch another...
            if (!IsInBalloon())
            {
                QBCLog.Warning("We've been jettisoned from vehicle unexpectedly--will try again.");
                BehaviorState = BehaviorStateType.MountingVehicle;
                return(true);
            }
            // Ride to hunting grounds complete when spells are enabled...
            if (WeaponLifeRocket.IsWeaponUsable())
            {
                BehaviorState = BehaviorStateType.CompletingObjectives;
                return(true);
            }


            await(_updateUser_RidingOutToHuntingGrounds ?? (_updateUser_RidingOutToHuntingGrounds =
                                                                new ThrottleCoroutineTask(
                                                                    Throttle.UserUpdate,
                                                                    async() => TreeRoot.StatusText = "Riding out to hunting grounds")));

            return(false);
        }
        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())
                                                              )))
                                        ));
        }
        /// <summary>
        /// Behavior for forcing train/mail/vendor/repair
        /// Example usage: <CustomBehavior QuestId="14324" File="ForceSetVendor" VendorType="Train" />
        /// QuestId is optional, if you don't use it make sure you put this tag inside an 'If'
        /// </summary>
        public ForceSetVendor(Dictionary <string, string> args)
            : base(args)
        {
            QBCLog.BehaviorLoggingContext = this;

            try
            {
                // Deprecation warnings...
                if (args.ContainsKey("VendorType"))
                {
                    QBCLog.Warning("The VendorType attribute has been deprecated.\n"
                                   + "Please replace it with DoMail/DoRepair/DoSell/DoTrain='true'");
                }

                // QuestRequirement* attributes are explained here...
                //    http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors
                // ...and also used for IsDone processing.
                DoMail   = GetAttributeAsNullable <bool>("DoMail", false, null, null) ?? false;
                DoRepair = GetAttributeAsNullable <bool>("DoRepair", false, null, null) ?? false;
                DoSell   = GetAttributeAsNullable <bool>("DoSell", false, null, null) ?? false;
                DoTrain  = GetAttributeAsNullable <bool>("DoTrain", false, null, null) ?? false;
                QuestId  = GetAttributeAsNullable <int>("QuestId", false, ConstrainAs.QuestId(this), null) ?? 0;
                QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete;
                QuestRequirementInLog    = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog;

                // "VendorType" attribute is required if no Do* attribute is specified
                VendorType?type = GetAttributeAsNullable <VendorType>("VendorType", !(DoMail || DoRepair || DoSell || DoTrain), null, null);
                if (type.HasValue)
                {
                    switch (type.Value)
                    {
                    case VendorType.Mail:
                        DoMail = true;
                        break;

                    case VendorType.Repair:
                        DoRepair = true;
                        break;

                    case VendorType.Sell:
                        DoSell = true;
                        break;

                    case VendorType.Train:
                        DoTrain = true;
                        break;

                    default:
                        IsAttributeProblem = true;
                        throw (new NotImplementedException("Unexpected VendorType"));
                    }
                }
            }

            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;
            }
        }
        private T UtilTo <T>(string attributeName, string attributeValueAsString)
        {
            Type concreteType = typeof(T);

            // Booleans require special handling...
            if (concreteType == typeof(bool))
            {
                int tmpInt;

                if (int.TryParse(attributeValueAsString, NumberStyles.Integer, CultureInfo.InvariantCulture, out tmpInt))
                {
                    attributeValueAsString = (tmpInt != 0) ? "true" : "false";

                    QBCLog.Warning(QBCLog.BuildMessageWithContext(Element,
                                                                  "Attribute's '{1}' value was provided as an integer (saw '{2}')--a boolean was expected.{0}"
                                                                  + "The integral value '{2}' was converted to Boolean({3}).{0}"
                                                                  + "Please update to provide '{3}' for this value.",
                                                                  Environment.NewLine,
                                                                  attributeName,
                                                                  tmpInt,
                                                                  attributeValueAsString));
                }

                // Fall through for normal boolean conversion
            }


            // Enums require special handling...
            else if (concreteType.IsEnum)
            {
                T tmpValue = default(T);

                try
                {
                    tmpValue = (T)Enum.Parse(concreteType, attributeValueAsString);

                    if (!Enum.IsDefined(concreteType, tmpValue))
                    {
                        throw new ArgumentException();
                    }

                    // If the provided value is a number instead of Enum name, ask the profile writer to fix it...
                    // This is not fatal, so we let it go without flagging IsAttributeProblem.
                    int tmpInt;
                    if (int.TryParse(attributeValueAsString, NumberStyles.Integer, CultureInfo.InvariantCulture, out tmpInt))
                    {
                        QBCLog.Warning(QBCLog.BuildMessageWithContext(Element,
                                                                      "The '{1}' attribute's value '{2}' has been implicitly converted"
                                                                      + " to the corresponding enumeration '{3}'.{0}"
                                                                      + "Please use the enumeration name '{3}' instead of a number.",
                                                                      Environment.NewLine,
                                                                      attributeName,
                                                                      tmpInt,
                                                                      tmpValue.ToString()));
                    }
                }
                catch (Exception)
                {
                    QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                                "The value '{1}' is not a member of the {2} enumeration."
                                                                + "  Allowed values: {3}",
                                                                Environment.NewLine,
                                                                attributeValueAsString,
                                                                concreteType.Name,
                                                                string.Join(", ", Enum.GetNames(concreteType))));
                    throw;
                }

                return(tmpValue);
            }



            try
            { return((T)Convert.ChangeType(attributeValueAsString, concreteType, CultureInfo.InvariantCulture)); }
            catch (Exception except)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                            "The '{1}' attribute's value (saw '{2}') is malformed. ({3})",
                                                            Environment.NewLine,
                                                            attributeName,
                                                            attributeValueAsString,
                                                            except.GetType().Name));
                throw;
            }
        }
        private string UtilLocateKey(bool isAttributeRequired, string primaryName, string[] aliasNames)
        {
            // Register keys as recognized
            UtilRecognizeAttributeNames(primaryName, aliasNames);

            // Make sure the key was only specified once --
            // The 'dictionary' nature of Args assures that a key name will only be in the dictionary once.
            // However, if the key has been renamed, and an alias maintained for backward-compatibility,
            // then the user could specify the primary key name and one or more aliases as attributes.
            // If all the aliases provided the same value, then it is harmless, but we don't make the
            // distinction.  Instead, we encourage the user to use the preferred name of the key.  This
            // eliminates any possibility of the user specifying conflicting values for the 'same' attribute.
            if (UtilCountKeyNames(primaryName, aliasNames) > 1)
            {
                var keyNames = new List <string> {
                    primaryName
                };

                keyNames.AddRange(aliasNames);
                keyNames.Sort();

                QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                            "The attributes [{1}] are aliases for each other, and thus mutually exclusive.{0}"
                                                            + "Please specify the attribute by its preferred name '{2}'.",
                                                            Environment.NewLine,
                                                            ("'" + string.Join("', '", keyNames.ToArray()) + "'"),
                                                            primaryName));
                IsAttributeProblem = true;
                return(null);
            }


            // Prefer the primary name...
            if (!string.IsNullOrEmpty(primaryName) && Attributes.ContainsKey(primaryName))
            {
                return(primaryName);
            }

            if (aliasNames != null)
            {
                string keyName = (from aliasName in aliasNames
                                  where !string.IsNullOrEmpty(aliasName) && Attributes.ContainsKey(aliasName)
                                  select aliasName).FirstOrDefault();

                if (!string.IsNullOrEmpty(keyName))
                {
                    QBCLog.Warning(QBCLog.BuildMessageWithContext(Element,
                                                                  "Found attribute via its alias name '{1}'.{0}"
                                                                  + "Please update to use its primary name '{2}', instead.",
                                                                  Environment.NewLine,
                                                                  keyName,
                                                                  primaryName));
                    return(keyName);
                }
            }


            // Attribute is required, but cannot be located...
            if (isAttributeRequired)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                            "Attribute '{1}' is required, but was not provided.",
                                                            Environment.NewLine,
                                                            primaryName));
                IsAttributeProblem = true;
            }

            return(null);
        }
예제 #19
0
        private async Task <bool> MoveToEnd(bool exitVehicle, WoWUnit passenger = null)
        {
            if (!Query.IsInVehicle())
            {
                return(false);
            }

            if (Vehicle.Location.DistanceSquared(EndLocation) >= PrecisionSqr)
            {
                await UseSpeedBuff();

                Flightor.MoveTo(EndLocation);
                return(true);
            }

            if (exitVehicle)
            {
                Lua.DoString("VehicleExit()");
                await Coroutine.Sleep(2000);

                await Coroutine.Wait(20000, () => !Me.IsFalling);

                if (Me.Combat)
                {
                    QBCLog.Info("Getting in vehicle to drop combat");
                    return(await GetInVehicleLogic());
                }
                return(true);
            }

            if (!Query.IsViable(passenger))
            {
                return(false);
            }

            if (Vehicle.IsMoving)
            {
                await CommonCoroutines.StopMoving("Dropping off passenger.");

                await CommonCoroutines.SleepForLagDuration();
            }

            await Coroutine.Sleep(StyxWoW.Random.Next(5000, 6000));

            UseVehicleButton(DropPassengerButton);

            await CommonCoroutines.SleepForLagDuration();

            if (!await Coroutine.Wait(10000, () => !Query.IsViable(passenger) || !UnitIsRidingMyVehicle(passenger)))
            {
                QBCLog.Warning("Failed to drop passenger off");
                return(false);
            }
            if (Query.IsViable(passenger))
            {
                Blacklist.Add(passenger, BlacklistFlags.Interact, TimeSpan.FromMinutes(10), "Rescued");
            }

            // pause a sec to see if quest completes.
            if (await Coroutine.Wait(2000, () => Quest.IsCompleted))
            {
                return(true);
            }

            CycleToNearestPointInPath();
            return(true);
        }
예제 #20
0
        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 Composite StateBehaviorPS_CompletingObjectives()
        {
            return(new PrioritySelector(
                       // If for some reason no longer in the vehicle, go fetch another...
                       new Decorator(context => !Query.IsViable(DragonVehicle),
                                     new Action(context =>
            {
                QBCLog.Warning("We've been jettisoned from vehicle unexpectedly--will try again.");
                BehaviorState = BehaviorStateType.MountingVehicle;
            })),

                       // If quest is complete, then head back...
                       new Decorator(context => Me.IsQuestComplete(GetQuestId()),
                                     new Action(context => { BehaviorState = BehaviorStateType.ReturningToBase; })),

                       new CompositeThrottle(Throttle.UserUpdate,
                                             new ActionFail(context => { TreeRoot.StatusText = "Completing Quest Objectives"; })),

                       SubBehaviorPS_UpdatePathWaypoint(),
                       SubBehaviorPS_Heal(),

                       // We go after the Ballistas first...
                       // NB: Soldiers will be collateral damage of pursing Ballistas.
                       // If the soldiers don't complete after doing Ballistas, we'll clean up
                       // the Soldiers next.
                       new Decorator(context => !IsViableTarget(SelectedTarget),
                                     new PrioritySelector(
                                         // Try to find target...
                                         new ActionFail(context =>
            {
                SelectedTarget = FindMobToKill(!Me.IsQuestObjectiveComplete(GetQuestId(), 2)
                                                            ? MobId_ScarletBallista
                                                            : MobId_TirisfalCrusader);
            }),
                                         // If no target found, move toward next waypoint...
                                         new Decorator(context => !IsViableTarget(SelectedTarget),
                                                       new Action(context => { Flightor.MoveTo(PathPatrol.Peek(), (float)FlightorMinHeight); }))
                                         )),

                       new Action(context =>
            {
                // NB: We would've preferred to strafe in this algorithm; however,
                // strafing triggers Flightor's unstuck handler too much.  Probably because
                // this is a vehicle/transport, instead of a 'flying mount'.

                // Show the target we're pursuing...
                Utility.Target(SelectedTarget);

                var myLocation = WoWMovement.ActiveMover.Location;
                var selectedTargetLocation = SelectedTarget.Location;
                var distance2DSqrToTarget = myLocation.Distance2DSquared(selectedTargetLocation);

                // Deal with needed evasion...
                if (StationPoint.HasValue)
                {
                    if (myLocation.Distance(StationPoint.Value) > FlyingPathPrecision)
                    {
                        Flightor.MoveTo(StationPoint.Value);
                        return RunStatus.Success;
                    }

                    StationPoint = null;
                }

                // See if we need a new 'on station' location...
                if (!StationPoint.HasValue)
                {
                    // If our weapon is not ready or we can't see target, move around station until it is...
                    if (!Weapon_FrozenDeathbolt.IsWeaponReady() ||
                        (IsViableTarget(SelectedTarget) && !SelectedTarget.InLineOfSight) ||
                        IsIncomingMissile())
                    {
                        StationPoint = FindNewStationPoint(SelectedTarget);
                        return RunStatus.Success;
                    }
                }

                // If we are too far from selected target, close the distance...
                if (distance2DSqrToTarget > (TargetDistance2DMax * TargetDistance2DMax))
                {
                    Flightor.MoveTo(FindDistanceClosePoint(SelectedTarget, PathPatrol.Peek().Z));
                    return RunStatus.Success;
                }

                // If we are too close to selected target, put some distance between us...
                if (distance2DSqrToTarget < (TargetDistance2DMin * TargetDistance2DMin))
                {
                    Flightor.MoveTo(FindDistanceGainPoint(SelectedTarget, TargetDistance2DMin));
                    return RunStatus.Success;
                }

                // If weapon is not ready, just keep on station/evading...
                if (!Weapon_FrozenDeathbolt.IsWeaponReady())
                {
                    return RunStatus.Success;
                }

                // If the weapon cannot address the target, blacklist target and find another...
                if (!Weapon_FrozenDeathbolt.WeaponAim(SelectedTarget))
                {
                    _targetBlacklist.Add(SelectedTarget, TimeSpan.FromSeconds(5));
                }

                // If weapon cannot fire for some reason, try again...
                if (!Weapon_FrozenDeathbolt.WeaponFire())
                {
                    return RunStatus.Success;
                }

                return RunStatus.Failure;       // fall through
            }),
                       // NB: Need to delay a bit for the weapon to actually launch.  Otherwise
                       // it screws the aim up if we move again before projectile is fired.
                       new Sleep(ctx => Delay.LagDuration + Delay.AfterWeaponFire)
                       //new Wait(Delay.LagDuration, context => Weapon_FrozenDeathbolt.IsWeaponReady(), new ActionAlwaysSucceed())
                       ));
        }
예제 #22
0
        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 Composite CreateMainBehavior()
        {
            return(new PrioritySelector(

                       // If a mob targets us, kill it...
                       // We don't want to blindly move to destination and drag a bunch of mobs behind us...
                       new Decorator(context => (SelectedTarget = FindMobTargetingMeOrPet()) != null,
                                     UtilityBehavior_SpankMob(context => SelectedTarget)),


                       // Stateful Operation:
                       new Switch <StateType_MainBehavior>(context => State_MainBehavior,
                                                           #region State: DEFAULT
                                                           new Action(context => // default case
            {
                QBCLog.Error("BEHAVIOR MAINTENANCE PROBLEM: StateType_MainBehavior({0}) is unhandled", State_MainBehavior);
                TreeRoot.Stop();
                _isBehaviorDone = true;
            }),
                                                           #endregion


                                                           #region State: Assigning Task
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.AssigningTask,
                                                                                                       new PrioritySelector(
                                                                                                           // Captain Anson...
                                                                                                           new Decorator(context => !Task_CaptainAnson.IsTaskComplete(context),
                                                                                                                         new Action(context =>
            {
                CurrentTask = Task_CaptainAnson;
                State_MainBehavior = StateType_MainBehavior.AcquiringCatapult;
            })),

                                                                                                           // Captain Morris...
                                                                                                           new Decorator(context => !Task_CaptainMorris.IsTaskComplete(context),
                                                                                                                         new Action(context =>
            {
                CurrentTask = Task_CaptainMorris;
                State_MainBehavior = StateType_MainBehavior.AcquiringCatapult;
            })),

                                                                                                           // Done with all tasks, move back to sane position to continue profile...
                                                                                                           new Decorator(context => !Navigator.AtLocation(Location_CatapultFarm),
                                                                                                                         new Action(context => { Navigator.MoveTo(Location_CatapultFarm); })),

                                                                                                           new Action(context =>
            {
                QBCLog.Info("Finished");
                _isBehaviorDone = true;
            })
                                                                                                           )),
                                                           #endregion


                                                           #region State: Acquiring Catapult
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.AcquiringCatapult,
                                                                                                       new PrioritySelector(
                                                                                                           // If task complete, go get next task...
                                                                                                           new Decorator(context => CurrentTask.IsTaskComplete(context),
                                                                                                                         new Action(context => { State_MainBehavior = StateType_MainBehavior.AssigningTask; })),

                                                                                                           // If we're in the catapult, start using it...
                                                                                                           new Decorator(context => Query.IsInVehicle(),
                                                                                                                         new Action(context => { State_MainBehavior = StateType_MainBehavior.UsingCatapultToBoardBoat; })),

                                                                                                           // Notify user...
                                                                                                           new Action(context =>
            {
                QBCLog.Info("Appropriating a Catapult");
                return RunStatus.Failure;
            }),

                                                                                                           // If available catapult, take advantage of it...
                                                                                                           new Decorator(context => IsViable(SelectedCatapult) &&
                                                                                                                         (FindPlayersNearby(SelectedCatapult.Location, NonCompeteDistanceForCatapults).Count() <= 0),
                                                                                                                         UtilityBehavior_InteractWithMob(context => SelectedCatapult)),

                                                                                                           // Otherwise, spank machinist and take his catapult...
                                                                                                           new Decorator(context => IsViable(SelectedMachinist) &&
                                                                                                                         (FindPlayersNearby(SelectedMachinist.Location, NonCompeteDistanceForCatapults).Count() <= 0),
                                                                                                                         UtilityBehavior_SpankMob(context => SelectedMachinist)),

                                                                                                           // Find next catapult or machinist...
                                                                                                           // NB: Since it takes a couple of seconds for the catapult to appear after
                                                                                                           // we kill the machinist, we want to wait briefly.   Without this delay,
                                                                                                           // the toon will run off to another machinist, and come back when the Catapult
                                                                                                           // spawns from the machinist we just killed.  This makes us look very bottish,
                                                                                                           // and the delay prevents that.
                                                                                                           new Wait(TimeSpan.FromSeconds(3),
                                                                                                                    context => ((SelectedCatapult = FindCatapult()) != null),
                                                                                                                    new ActionAlwaysSucceed()),

                                                                                                           new Decorator(context => (SelectedMachinist = FindMachinist()) != null,
                                                                                                                         new ActionAlwaysSucceed()),

                                                                                                           // No catapults to be had, move to center of catapult farm and wait for respawns...
                                                                                                           new Decorator(context => !Navigator.AtLocation(Location_CatapultFarm),
                                                                                                                         new Action(context => { Navigator.MoveTo(Location_CatapultFarm); })),
                                                                                                           new Action(context => { QBCLog.Info("Waiting on more Catapults to respawn"); })
                                                                                                           )),
                                                           #endregion


                                                           #region State: Using Catapult to Board Boat
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.UsingCatapultToBoardBoat,
                                                                                                       new PrioritySelector(
                                                                                                           // If task complete, go fetch another...
                                                                                                           new Decorator(context => CurrentTask.IsTaskComplete(context),
                                                                                                                         new Action(context => { State_MainBehavior = StateType_MainBehavior.AssigningTask; })),

                                                                                                           // If we're no longer in catapult, either launch succeeded or we need to fetch another Catapult...
                                                                                                           new Decorator(context => !Query.IsInVehicle(),
                                                                                                                         new PrioritySelector(
                                                                                                                             // Allow time for Launch completion, and toon to land on boat...
                                                                                                                             new Wait(TimeSpan.FromSeconds(5),
                                                                                                                                      // TODO: Rewrite to use something else (probably IsOnTransport?)
                                                                                                                                      context => true /*Navigator.CanNavigateFully(Me.Location, CurrentTask.PositionToLand)*/,
                                                                                                                                      new ActionAlwaysFail()),

                                                                                                                             new Action(context =>
            {
                // If we can navigate to intended landing spot, we successfully boarded boat...
                // TODO: Rewrite to use something else (probably IsOnTransport?)
                if (/*Navigator.CanNavigateFully(Me.Location, CurrentTask.PositionToLand)*/ true)
                {
                    State_MainBehavior = StateType_MainBehavior.KillingCaptain;
                    return;
                }

                // Otherwise, we missed boarding boat, and need to try again...
                QBCLog.Warning("Failed in boarding {0}'s boat--trying again", CurrentTask.MobName);
                State_MainBehavior = StateType_MainBehavior.AcquiringCatapult;
            })
                                                                                                                             )),

                                                                                                           // If Catapult no longer viable, find a new one...
                                                                                                           new Decorator(context => !IsViable(SelectedCatapult),
                                                                                                                         new Decorator(context => (SelectedCatapult = FindCatapult()) == null,
                                                                                                                                       new Action(context => { State_MainBehavior = StateType_MainBehavior.AcquiringCatapult; }))),

                                                                                                           // Try to board boat...
                                                                                                           new ActionRunCoroutine(ctx => UtilityCoroutine_MoveAndUseCatapult())
                                                                                                           )),
                                                           #endregion


                                                           #region State: Kill the Captain
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.KillingCaptain,
                                                                                                       new PrioritySelector(
                                                                                                           // If task complete, exit boat...
                                                                                                           new Decorator(context => CurrentTask.IsTaskComplete(context),
                                                                                                                         new Action(context => { State_MainBehavior = StateType_MainBehavior.ExitingBoat; })),

                                                                                                           // Kill the Captain...
                                                                                                           new PrioritySelector(captainContext => FindUnitsFromIds(CurrentTask.MobId).FirstOrDefault(),
                                                                                                                                new Decorator(captainContext => captainContext != null,
                                                                                                                                              UtilityBehavior_SpankMob(captainContext => (WoWUnit)captainContext)),
                                                                                                                                new Decorator(captainContext => captainContext == null,
                                                                                                                                              new Action(captainContext => { QBCLog.Info("Waiting for {0} to respawn", CurrentTask.MobName); }))
                                                                                                                                )
                                                                                                           )),
                                                           #endregion


                                                           #region State: Exiting Boat
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.ExitingBoat,
                                                                                                       new PrioritySelector(
                                                                                                           new Action(context =>
            {
                QBCLog.Info("Exiting {0}'s boat", CurrentTask.MobName);
                return RunStatus.Failure;
            }),
                                                                                                           new Decorator(context => !Navigator.AtLocation(CurrentTask.PositionToLand),
                                                                                                                         new Action(context => { Navigator.MoveTo(CurrentTask.PositionToLand); })),

                                                                                                           new Action(context => { State_MainBehavior = StateType_MainBehavior.ExitBoatJumpDown; })
                                                                                                           )),
                                                           #endregion


                                                           #region State: Exit Boat Jump Down
                                                           new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.ExitBoatJumpDown,
                                                                                                       new PrioritySelector(
                                                                                                           new Action(context =>
            {
                QBCLog.Info("Jumping down off of {0}'s boat", CurrentTask.MobName);
                return RunStatus.Failure;
            }),
                                                                                                           // NB: There appear to be no mesh "jump links" in the mesh to get off boat.
                                                                                                           // So, we're left with using ClickToMove to jump down from boat decks.
                                                                                                           new Decorator(context => !Navigator.AtLocation(CurrentTask.PositionToJumpDownOffBoat),
                                                                                                                         new Action(context => { WoWMovement.ClickToMove(CurrentTask.PositionToJumpDownOffBoat); })),

                                                                                                           new Action(context => { State_MainBehavior = StateType_MainBehavior.AssigningTask; })
                                                                                                           ))
                                                           #endregion
                                                           )));
        }
예제 #24
0
        private Composite CreateCombatBehavior()
        {
            // NB: We'll be running right over some hostiles while in the barrel.
            // Even with a PullDistance set to one, HBcore and the CombatRoutine are going to try to pull these mobs.
            // Thus, this behavior runs at "higher than combat" priority, and prevents the CombatRoutine from executing
            // while this behavior is in progress.
            //
            // NB: We need to allow lower BT nodes to run when the behavior is finished; otherwise, HB will not
            // process the change of _isBehaviorDone state.
            return(new Decorator(context => !_isBehaviorDone,
                                 new PrioritySelector(context => _combatContext.Update(),

                                                      // If quest is done, behavior is done...
                                                      new Decorator(context => !UtilIsProgressRequirementsMet(QuestId, QuestRequirementInLog, QuestRequirementComplete),
                                                                    new Action(context =>
            {
                _isBehaviorDone = true;
                QBCLog.Info("Finished");
            })),

                                                      // If not in Keg Bomb Vehicle, move to it and get inside...
                                                      new Decorator(context => !Query.IsInVehicle() && (_combatContext.KegBomb != null),
                                                                    new PrioritySelector(
                                                                        new Decorator(context => _combatContext.KegBomb.Distance > _combatContext.KegBomb.InteractRange,
                                                                                      new Action(context => { Navigator.MoveTo(_combatContext.KegBomb.Location); })),
                                                                        new Decorator(context => Me.IsMoving,
                                                                                      new Action(context => { WoWMovement.MoveStop(); })),
                                                                        new Decorator(context => !Me.IsSafelyFacing(_combatContext.KegBomb),
                                                                                      new Action(context => { _combatContext.KegBomb.Face(); })),
                                                                        new Sequence(
                                                                            // N.B. we need to wait a bit before jumping in vehicle after a round -
                                                                            // due to a bug that prevents bot from leaving vehicle until a relog
                                                                            new WaitContinue(2, context => false, new ActionAlwaysSucceed()),
                                                                            new Action(context =>
            {
                _combatContext.ReInitialize();
                _combatContext.KegBomb.Interact();
                QBCLog.Info("Started barrel roll #{0}", ++_barrelRollCount);
                return RunStatus.Failure;
            })),
                                                                        new Wait(TimeSpan.FromMilliseconds(1000), context => false, new ActionAlwaysSucceed())
                                                                        )),

                                                      // If we are in the vehicle...
                                                      new Decorator(context => Query.IsInVehicle() && (_combatContext.KegBombVehicle != null),
                                                                    new PrioritySelector(
                                                                        // If we've been in the barrel too long, just blow it up...
                                                                        // Blacklist whatever target we were after, and try again
                                                                        new Decorator(context => (_combatContext.BarrelRollingTimer.ElapsedMilliseconds > BarrelRollingTimeBeforeRetrying) &&
                                                                                      !_combatContext.IsKegIgnited,
                                                                                      new Action(context =>
            {
                QBCLog.Warning("We've been in the barrel too long--we're blowing it up to try again");
                IgniteKeg(_combatContext);
                if (_combatContext.SelectedTarget != null)
                {
                    Blacklist.Add(_combatContext.SelectedTarget, BlacklistFlags.Combat, TimeSpan.FromMinutes(3));
                }
            })),

                                                                        // Select target, if not present...
                                                                        new Decorator(context => _combatContext.SelectedTarget == null,
                                                                                      new Action(context => ChooseTarget(_combatContext))),

                                                                        // If we have a target, guide barrel to target...
                                                                        new Decorator(context => _combatContext.SelectedTarget != null,
                                                                                      new Action(context =>
            {
                float neededFacing = WoWMathHelper.CalculateNeededFacing(_combatContext.KegBombVehicle.Location,
                                                                         _combatContext.SelectedTarget.Location);
                neededFacing = WoWMathHelper.NormalizeRadian(neededFacing);

                float neededRotation = Math.Abs(neededFacing - _combatContext.KegBombVehicle.RenderFacing);
                neededRotation = WoWMathHelper.NormalizeRadian(neededRotation);

                // If we need to rotate heading 'too hard' to hit the target, then we missed the target...
                // Blow up the current barrel, blacklist the target, and try again
                if (((neededRotation > (Math.PI / 2)) && (neededRotation < ((Math.PI * 2) - (Math.PI / 2)))) &&
                    !_combatContext.IsKegIgnited)
                {
                    QBCLog.Warning("We passed the selected target--igniting barrel to try again.");
                    IgniteKeg(_combatContext);
                    Blacklist.Add(_combatContext.SelectedTarget, BlacklistFlags.Combat, TimeSpan.FromMinutes(3));
                }

                // Ignite the keg at the appropriate time...
                if (_combatContext.SelectedTarget.Distance <= IgniteDistance)
                {
                    IgniteKeg(_combatContext);
                }

                // Guide the keg to target...
                Me.SetFacing(neededFacing);
                return RunStatus.Success;
            }))
                                                                        ))
                                                      )));
        }