// Largely used to convert 'string' representation of a value into the value's type...
        public object ToCongruentObject(object value)
        {
            var backingType  = PropInfo.PropertyType;
            var providedType = value != null?value.GetType() : backingType;

            try
            {
                Type underlyingType = Nullable.GetUnderlyingType(backingType);
                if (underlyingType != null)
                {
                    // Nullables are treated specially as they can be assigned from a null reference or just an underlying value
                    return(value != null?Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture) : null);
                }

                // Disallow int => bool conversions...
                // These are almost _always_ mistakes on the profile writer's part.
                if ((providedType == typeof(int) && (backingType == typeof(bool))))
                {
                    throw new ArgumentException();
                }

                return(Convert.ChangeType(value, backingType, CultureInfo.InvariantCulture));
            }
            catch (Exception)
            {
                var message = string.Format("For setting '{0}', the provided value '{1}' ({2})"
                                            + " cannot be converted to the backing type ({3}).",
                                            Name, value ?? "(NULL)", providedType.Name, backingType.Name);
                QBCLog.Error(message);
                throw new ArgumentException(message);
            }
        }
Example #2
0
        // 11Apr2013-04:42UTC chinajade
        public static HuntingGroundsType GetOrCreate(XElement parentElement, string elementName,
                                                     WaypointType defaultHuntingGroundCenter = null, double?forcedTolerance = null)
        {
            var huntingGrounds = new HuntingGroundsType(parentElement
                                                        .Elements()
                                                        .DefaultIfEmpty(new XElement(elementName))
                                                        .FirstOrDefault(elem => (elem.Name == elementName)));

            if (!huntingGrounds.IsAttributeProblem)
            {
                if (forcedTolerance.HasValue)
                {
                    foreach (var waypoint in huntingGrounds.Waypoints)
                    {
                        waypoint.ArrivalTolerance = forcedTolerance.Value;
                    }
                }

                // If user didn't provide a HuntingGrounds, and he provided a default center point, add it...
                if (!huntingGrounds.Waypoints.Any() && (defaultHuntingGroundCenter != null))
                {
                    huntingGrounds.Waypoints.Add(defaultHuntingGroundCenter);
                }

                if (!huntingGrounds.Waypoints.Any())
                {
                    QBCLog.Error("Neither the X/Y/Z attributes nor the <{0}> sub-element has been specified.",
                                 elementName);
                    huntingGrounds.IsAttributeProblem = true;
                }
            }

            return(huntingGrounds);
        }
Example #3
0
            public EquipmentType(XElement xElement)
                : base(xElement)
            {
                try
                {
                    ItemId = GetAttributeAsNullable <int>("ItemId", true, ConstrainAs.ItemId, null) ?? 0;
                    Name   = GetAttributeAs <string>("Name", false, ConstrainAs.StringNonEmpty, null) ?? string.Empty;

                    if (string.IsNullOrEmpty(Name))
                    {
                        Name = GetDefaultName(ItemId);
                    }

                    HandleAttributeProblem();
                }

                catch (Exception except)
                {
                    if (Query.IsExceptionReportingNeeded(except))
                    {
                        QBCLog.Error("[PROFILE PROBLEM with \"{0}\"]: {1}\nFROM HERE ({2}):\n{3}\n",
                                     xElement.ToString(), except.Message, except.GetType().Name,
                                     except.StackTrace);
                    }
                    IsAttributeProblem = true;
                }
            }
        public MobType(XElement xElement)
            : base(xElement)
        {
            try
            {
                Name  = GetAttributeAs <string>("Name", false, ConstrainAs.StringNonEmpty, null) ?? string.Empty;
                Entry = GetAttributeAsNullable <int>("Entry", false, ConstrainAs.MobId, null)
                        ?? GetAttributeAsNullable <int>("Id", false, ConstrainAs.MobId, null)
                        ?? 0;

                if (Entry == 0)
                {
                    QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                                "Attribute '{1}' is required, but was not provided.",
                                                                Environment.NewLine,
                                                                "Entry"));
                    IsAttributeProblem = true;
                }

                HandleAttributeProblem();
            }

            catch (Exception except)
            {
                if (Query.IsExceptionReportingNeeded(except))
                {
                    QBCLog.Exception(except, "PROFILE PROBLEM with \"{0}\"", xElement.ToString());
                }
                IsAttributeProblem = true;
            }
        }
Example #5
0
        // 11Apr2013-04:42UTC chinajade
        public static SafePathType GetOrCreate(XElement parentElement, string elementName, double defaultEgressDistance, Vector3?safespotLocation = null)
        {
            if (safespotLocation.HasValue &&
                ((safespotLocation.Value == Vector3.Zero) || safespotLocation.Value == Vector3.Zero))
            {
                safespotLocation = null;
            }

            var safePath = new SafePathType(parentElement
                                            .Elements()
                                            .DefaultIfEmpty(new XElement(elementName))
                                            .FirstOrDefault(elem => (elem.Name == elementName)),
                                            defaultEgressDistance);

            if (!safePath.IsAttributeProblem)
            {
                // If user didn't provide a HuntingGrounds, and he provided a default center point, add it...
                if (!safePath.Waypoints.Any() && safespotLocation.HasValue)
                {
                    safePath.Waypoints.Add(new WaypointType(safespotLocation.Value, "safe spot", 7.0));
                }

                if (!safePath.Waypoints.Any())
                {
                    QBCLog.Error("Neither the X/Y/Z attributes nor the <{0}> sub-element has been specified.",
                                 elementName);
                    safePath.IsAttributeProblem = true;
                }
            }

            return(safePath);
        }
Example #6
0
        public override void OnStart()
        {
            PlayerQuest quest = StyxWoW.Me.QuestLog.GetQuestById((uint)QuestId);

            if ((QuestId != 0) && (quest == null))
            {
                QBCLog.Error("This behavior has been associated with QuestId({0}), but the quest is not in our log", QuestId);
                IsAttributeProblem = true;
            }

            // 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)
            {
                _configMemento = new ConfigMemento();

                // Disable any settings that may interfere with the escort --
                // When we escort, we don't want to be distracted by other things.
                // NOTE: these settings are restored to their normal values when the behavior completes
                // or the bot is stopped.
                CharacterSettings.Instance.PullDistance     = 25;
                GlobalSettings.Instance.KillBetweenHotspots = true;

                _behaviorTreeCombatHook = CreateCombatBehavior();
                TreeHooks.Instance.InsertHook("Combat_Only", 0, _behaviorTreeCombatHook);

                this.UpdateGoalText(QuestId);
            }
        }
        public T[] GetAttributeAsArray <T>(string attributeName, bool isAttributeRequired, IConstraintChecker <T> constraints, string[] attributeNameAliases,
                                           char[] separatorCharacters)
        {
            // Vector3 are triples, so requires special handling...
            if (typeof(T) == typeof(Vector3))
            {
                return((T[])UtilGetAttributeAsVector3s(attributeName, isAttributeRequired, attributeNameAliases));
            }


            constraints         = constraints ?? new ConstrainTo.Anything <T>();
            separatorCharacters = separatorCharacters ?? new[] { ' ', ',', ';' };

            bool   isError    = false;
            string keyName    = UtilLocateKey(isAttributeRequired, attributeName, attributeNameAliases);
            var    resultList = new List <T>();

            if ((keyName == null) || !Attributes.ContainsKey(keyName))
            {
                resultList.Clear();
                return(resultList.ToArray());
            }

            // We 'continue' even if problems are encountered...
            // By doing this, the profile writer can see all his mistakes at once, rather than being
            // nickel-and-dimed to death with error messages.
            foreach (string listEntry in Attributes[keyName].Split(separatorCharacters, StringSplitOptions.RemoveEmptyEntries))
            {
                T tmpResult;

                try
                { tmpResult = UtilTo <T>(keyName, listEntry); }

                catch (Exception)
                {
                    isError = true;
                    continue;
                }

                string constraintViolationMessage = constraints.Check(keyName, tmpResult);
                if (constraintViolationMessage != null)
                {
                    QBCLog.Error(QBCLog.BuildMessageWithContext(Element, constraintViolationMessage));
                    isError = true;
                    continue;
                }

                resultList.Add(tmpResult);
            }

            if (isError)
            {
                resultList.Clear();
                IsAttributeProblem = true;
            }

            return(resultList.ToArray());
        }
        public T[] GetNumberedAttributesAsArray <T>(string baseName, int countRequired, IConstraintChecker <T> constraints, IEnumerable <string> aliasBaseNames)
        {
            bool isError    = false;
            bool isVector3  = (typeof(T) == typeof(Vector3));
            var  resultList = new List <T>();

            // Search for primary names first --
            // We 'continue' even if problems are encountered.  By doing this, the profile writer can see
            // all his mistakes at once, rather than being nickel-and-dimed to death with error messages.
            var primaryAttributeNames = from attributeName in Attributes.Keys
                                        where UtilIsNumberedAttribute(baseName, attributeName, isVector3)
                                        select attributeName;

            foreach (var numberedAttributeName in primaryAttributeNames)
            {
                isError |= UtilAddToNumberedAttributeToArray <T>(numberedAttributeName, constraints, resultList);
            }

            // Search using alias names --
            // We 'continue' even if problems are encountered.  By doing this, the profile writer can see
            // all his mistakes at once, rather than being nickel-and-dimed to death with error messages.
            if (aliasBaseNames != null)
            {
                var aliasAttributeNames = from aliasBaseName in aliasBaseNames
                                          from attributeName in Attributes.Keys
                                          where UtilIsNumberedAttribute(aliasBaseName, attributeName, isVector3)
                                          select attributeName;

                foreach (var numberedAttributeName in aliasAttributeNames)
                {
                    isError |= UtilAddToNumberedAttributeToArray <T>(numberedAttributeName, constraints, resultList);
                }
            }


            if (resultList.Count < countRequired)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(Element,
                                                            "The attribute '{1}N' must be provided at least {2} times (saw it '{3}' times).{0}"
                                                            + "(E.g., ButtonText1, ButtonText2, ButtonText3, ...){0}"
                                                            + "Please modify to supply {2} attributes with a base name of '{1}'.",
                                                            Environment.NewLine,
                                                            baseName,
                                                            countRequired,
                                                            resultList.Count));
                isError = true;
            }


            if (isError)
            {
                resultList.Clear();
                IsAttributeProblem = true;
            }

            return(resultList.ToArray());
        }
        public override void OnStart()
        {
            PlayerQuest quest = StyxWoW.Me.QuestLog.GetQuestById((uint)QuestId);

            if ((QuestId != 0) && (quest == null))
            {
                QBCLog.Error("This behavior has been associated with QuestId({0}), but the quest is not in our log", QuestId);
                IsAttributeProblem = true;
            }

            // 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();

            // We need to move off boat after quest is complete, so we can't use "quest complete"
            // as part of the normal IsDone criteria for this behavior.  So, we explicitly check for
            // quest complete here, and set IsDone appropriately.
            if (!UtilIsProgressRequirementsMet(QuestId, QuestRequirementInLog, QuestRequirementComplete))
            {
                _isBehaviorDone = true;
            }

            // 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)
            {
                _configMemento = new ConfigMemento();

                // Disable any settings that may interfere with the escort --
                // When we escort, we don't want to be distracted by other things.
                // NOTE: these settings are restored to their normal values when the behavior completes
                // or the bot is stopped.
                CharacterSettings.Instance.HarvestHerbs    = false;
                CharacterSettings.Instance.HarvestMinerals = false;
                CharacterSettings.Instance.LootChests      = false;
                CharacterSettings.Instance.NinjaSkin       = false;
                CharacterSettings.Instance.SkinMobs        = false;

                BlackspotManager.AddBlackspots(Blackspots);

                State_MainBehavior = StateType_MainBehavior.AssigningTask;

                _behaviorTreeHook_CombatMain = CreateBehavior_CombatMain();
                TreeHooks.Instance.InsertHook("Combat_Main", 0, _behaviorTreeHook_CombatMain);
                _behaviorTreeHook_CombatOnly = CreateBehavior_CombatOnly();
                TreeHooks.Instance.InsertHook("Combat_Only", 0, _behaviorTreeHook_CombatOnly);
                _behaviorTreeHook_DeathMain = CreateBehavior_DeathMain();
                TreeHooks.Instance.InsertHook("Death_Main", 0, _behaviorTreeHook_DeathMain);

                this.UpdateGoalText(QuestId);
            }
        }
Example #10
0
            protected override async Task <ActivityResult> ExecuteSpecificActivity()
            {
                // If spell is not known at the moment, this is a problem...
                if ((_wowSpell == null) || !_wowSpell.IsValid)
                {
                    QBCLog.Error(_errorMessage_UnknownSpell);
                    return(ActivityResult.Failed);
                }

                return
                    (await UtilityCoroutine.CastSpell(_wowSpell.Id) == SpellCastResult.Succeeded
                        ? ActivityResult.Succeeded
                        : ActivityResult.Failed);
            }
Example #11
0
        public VehicleMover(Dictionary <string, string> args)
            : base(args)
        {
            try
            {
                // NB: Core attributes are parsed by QuestBehaviorBase parent (e.g., QuestId, NonCompeteDistance, etc)

                // Primary attributes...
                AuraId_ProxyVehicle = GetAttributeAsNullable <int>("AuraId_ProxyVehicle", false, ConstrainAs.SpellId, null) ?? 0;
                MobIds      = GetNumberedAttributesAsArray <int>("MobId", 0, ConstrainAs.MobId, new[] { "MobID", "NpcId" });
                SpellId     = GetAttributeAsNullable <int>("SpellId", false, ConstrainAs.SpellId, new[] { "SpellID" }) ?? 0;
                VehicleIds  = GetNumberedAttributesAsArray <int>("VehicleId", 1, ConstrainAs.VehicleId, new[] { "VehicleID" });
                Destination = GetAttributeAsNullable <WoWPoint>("", true, ConstrainAs.WoWPointNonEmpty, null) ?? WoWPoint.Empty;

                // Tunables...
                NumOfTimes   = GetAttributeAsNullable <int>("CastNum", false, ConstrainAs.RepeatCount, null) ?? 1;
                CastTime     = GetAttributeAsNullable <int>("CastTime", false, new ConstrainTo.Domain <int>(0, 30000), null) ?? 1500;
                Hop          = GetAttributeAsNullable <bool>("Hop", false, null, null) ?? false;
                IgnoreCombat = GetAttributeAsNullable <bool>("IgnoreCombat", false, null, null) ?? true;
                /*unused*/
                GetAttributeAsNullable <double>("Precision", false, new ConstrainTo.Domain <double>(2.0, 100.0), null);

                var useNavigator = GetAttributeAsNullable <bool>("UseNavigator", false, null, null);
                if (useNavigator.HasValue)
                {
                    MovementBy = useNavigator.Value ? MovementByType.NavigatorPreferred : MovementByType.ClickToMoveOnly;
                }

                WaitForVehicle = GetAttributeAsNullable <bool>("WaitForVehicle", false, null, null) ?? true;

                // For backward compatibility, we do not error off on an invalid SpellId, but merely warn the user...
                if ((1 <= SpellId) && (SpellId <= 12))
                {
                    QBCLog.Error("SpellId of {0} is not valid--did you accidently provde an ActionBarIndex instead?", SpellId);
                }
            }

            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;
            }
        }
Example #12
0
        private void ActionRemove()
        {
            var activityIdentifier = FindActivityIdentifier();
            var activity           = FindActivity(activityIdentifier);

            // If activity does not exist, that's a problem...
            if (activity == null)
            {
                QBCLog.Error("DoWhenActivity '{0}' is not in use.", activityIdentifier);
                return;
            }

            // Remove the activity...
            s_persistedActivities.Remove(activity);
            QBCLog.DeveloperInfo("DoWhenActivity '{0}' removed.", activity.ActivityIdentifier);
        }
Example #13
0
 private async Task <bool> MainCoroutine()
 {
     if (!string.IsNullOrEmpty(CurrentProfileName))
     {
         QBCLog.Info("Skipping Current HBRelogTask... Bye Bye Now");
         HBRelogRemoteApi.SkipCurrentTask(CurrentProfileName);
         BehaviorDone();
         return(true);
     }
     else
     {
         QBCLog.Error("Could not connect to HBRelog Server or Invalid Profile. Could not Skip Task");
         BehaviorDone();
         return(true);
     }
 }
        public override void OnStart()
        {
            PlayerQuest quest = StyxWoW.Me.QuestLog.GetQuestById((uint)QuestId);

            if ((QuestId != 0) && (quest == null))
            {
                QBCLog.Error("This behavior has been associated with QuestId({0}), but the quest is not in our log", QuestId);
                IsAttributeProblem = true;
            }

            // 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)
            {
                _configMemento = new ConfigMemento();

                // Disable any settings that may interfere with the escort --
                // When we escort, we don't want to be distracted by other things.
                // NOTE: these settings are restored to their normal values when the behavior completes
                // or the bot is stopped.
                CharacterSettings.Instance.HarvestHerbs    = false;
                CharacterSettings.Instance.HarvestMinerals = false;
                CharacterSettings.Instance.LootChests      = false;
                CharacterSettings.Instance.NinjaSkin       = false;
                CharacterSettings.Instance.SkinMobs        = false;
                // CharacterSettings.Instance.PullDistance = 1;    // don't pull anything unless we absolutely must

                BlackspotManager.AddBlackspots(Blackspots);

                State_MainBehavior = StateType_MainBehavior.DroppingOffVictim;

                _behaviorTreeHook_CombatMain = CreateBehavior_CombatMain();
                TreeHooks.Instance.InsertHook("Combat_Main", 0, _behaviorTreeHook_CombatMain);
                _behaviorTreeHook_CombatOnly = CreateBehavior_CombatOnly();
                TreeHooks.Instance.InsertHook("Combat_Only", 0, _behaviorTreeHook_CombatOnly);
                _behaviorTreeHook_DeathMain = CreateBehavior_DeathMain();
                TreeHooks.Instance.InsertHook("Death_Main", 0, _behaviorTreeHook_DeathMain);

                this.UpdateGoalText(QuestId);
            }
        }
Example #15
0
            protected override async Task <ActivityResult> ExecuteSpecificActivity()
            {
                // If item is not in inventory at the moment, we consider that a problem...
                if (!Query.IsViable(_itemToUse))
                {
                    QBCLog.Error(_errorMessage_ItemNotInInventory);
                    return(ActivityResult.Failed);
                }

                var activityResult = ActivityResult.Failed;
                await UtilityCoroutine.UseItem((int)_itemToUse.Entry,
                                               null,  /*missing item is non-fatal*/
                                               null,  /*notification on fail*/
                                               () => { activityResult = ActivityResult.Succeeded; });

                return(activityResult);
            }
        public CombatUseItemOn(Dictionary <string, string> args)
            : base(args)
        {
            QBCLog.BehaviorLoggingContext = this;

            try
            {
                CastingSpellId           = GetAttributeAsNullable <int>("CastingSpellId", false, ConstrainAs.SpellId, null) ?? 0;
                MaxRange                 = GetAttributeAsNullable <double>("MaxRange", false, ConstrainAs.Range, null) ?? 25;
                HasAuraId                = GetAttributeAsNullable <int>("HasAuraId", false, ConstrainAs.AuraId, new[] { "HasAura" }) ?? 0;
                ItemId                   = GetAttributeAsNullable <int>("ItemId", true, ConstrainAs.ItemId, null) ?? 0;
                Location                 = GetAttributeAsNullable <Vector3>("", false, ConstrainAs.Vector3NonEmpty, null) ?? Me.Location;
                MobIds                   = GetNumberedAttributesAsArray <int>("MobId", 1, ConstrainAs.MobId, new[] { "NpcId" });
                MobHasAuraId             = GetAttributeAsNullable <int>("MobHasAuraId", false, ConstrainAs.AuraId, new[] { "NpcHasAuraId", "NpcHasAura" }) ?? 0;
                MobHpPercentLeft         = GetAttributeAsNullable <double>("MobHpPercentLeft", false, ConstrainAs.Percent, new[] { "NpcHpLeft", "NpcHPLeft" }) ?? 0;
                NumOfTimes               = GetAttributeAsNullable <int>("NumOfTimes", false, ConstrainAs.RepeatCount, null) ?? 1;
                QuestId                  = GetAttributeAsNullable <int>("QuestId", false, ConstrainAs.QuestId(this), null) ?? 0;
                UseOnce                  = GetAttributeAsNullable <bool>("UseOnce", false, null, null) ?? true;
                BlacklistMob             = GetAttributeAsNullable <bool>("BlacklistMob", false, null, null) ?? false;
                WaitTime                 = GetAttributeAsNullable <int>("WaitTime", false, ConstrainAs.Milliseconds, null) ?? 500;
                QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete;
                QuestRequirementInLog    = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog;

                // semantic coherency checks --
                if ((CastingSpellId == 0) && (HasAuraId == 0) && (MobHasAuraId == 0) && (MobHpPercentLeft == 0.0))
                {
                    QBCLog.Error("One or more of the following attributes must be specified:\n"
                                 + "CastingSpellId, HasAuraId, MobHasAuraId, MobHpPercentLeft");
                    IsAttributeProblem = true;
                }

                QuestBehaviorBase.DeprecationWarning_Behavior(this, "CombatUseItemOnV2", BuildReplacementArguments());
            }

            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;
            }
        }
Example #17
0
        private void UtilPopulateMapWithAuras(Dictionary <int, int> auraIdToButtonMap,
                                              int buttonNum,
                                              int[] auraIds)
        {
            foreach (int auraId in auraIds)
            {
                if (auraIdToButtonMap.ContainsKey(auraId))
                {
                    QBCLog.Error("AuraId({0}) cannot be associated with two buttons."
                                 + "  (Attempted to associate with Button{1} and Button{2}.)",
                                 auraId, auraIdToButtonMap[auraId], buttonNum);
                    IsAttributeProblem = true;
                    break;
                }

                auraIdToButtonMap.Add(auraId, buttonNum);
            }
        }
Example #18
0
        public override void OnStart()
        {
            var         questId = GetQuestId();
            PlayerQuest quest   = StyxWoW.Me.QuestLog.GetQuestById((uint)questId);

            if ((questId != 0) && (quest == null))
            {
                QBCLog.Error("This behavior has been associated with QuestId({0}), but the quest is not in our log", questId);
                IsAttributeProblem = true;
            }

            // If the needed item is not in my inventory, report problem...
            if (!Me.BagItems.Any(i => ItemId_BlindingRageTrap == (int)i.Entry))
            {
                QBCLog.Error("The behavior requires \"Blind Rage Trap\"(ItemId: {0}) to be in our bags; however, it cannot be located)",
                             ItemId_BlindingRageTrap);
                IsAttributeProblem = true;
            }


            // Let QuestBehaviorBase do basic initialization of the behavior, deal with bad or deprecated attributes,
            // capture configuration state, install BT hooks, etc.  This will also update the goal text.
            var isBehaviorShouldRun = OnStart_QuestBehaviorCore();

            // 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 (isBehaviorShouldRun)
            {
                // Disable any settings that may interfere with the escort --
                // When we escort, we don't want to be distracted by other things.
                // NOTE: these settings are restored to their normal values when the behavior completes
                // or the bot is stopped.
                CharacterSettings.Instance.HarvestHerbs    = false;
                CharacterSettings.Instance.HarvestMinerals = false;
                CharacterSettings.Instance.LootChests      = false;
                CharacterSettings.Instance.NinjaSkin       = false;
                CharacterSettings.Instance.SkinMobs        = false;
                // don't pull anything unless we absolutely must
                LevelBot.BehaviorFlags &= ~BehaviorFlags.Pull;

                _combatContext = new BattlefieldContext(ItemId_BlindingRageTrap, GameObjectId_BlindingRageTrap);
                this.UpdateGoalText(GetQuestId(), "Looting and Harvesting are disabled while behavior in progress");
            }
        }
        private IEnumerable <WoWUnit> FindUnitsFromIds(params int[] unitIds)
        {
            if (unitIds == null)
            {
                string message = "BEHAVIOR MAINTENANCE ERROR: unitIds argument may not be null";

                QBCLog.Error(message);
                throw new ArgumentException(message);
            }

            return
                (from unit in ObjectManager.GetObjectsOfType <WoWUnit>()
                 where
                 unit.IsValid &&
                 unit.IsAlive &&
                 unitIds.Contains((int)unit.Entry) &&
                 !unit.TaggedByOther
                 select unit);
        }
Example #20
0
            public async Task <bool> Execute()
            {
                if (!IsSpecificExecutionNeeded())
                {
                    return(false);
                }

                if (IsMovementStopRequired && Me.IsMoving)
                {
                    await CommonCoroutines.StopMoving();
                }

                var activityResult = await ExecuteSpecificActivity();

                if (activityResult == ActivityResult.Indeterminate)
                {
                    return(ShouldBreakWhenIndeterminate);
                }

                if (activityResult == ActivityResult.Failed)
                {
                    return(false);
                }

                // If we get here, we got a ActivityResult.Succeeded
                UseWhenPredicate.Reset();

                // If predicate did not clear, then predicate is bad...
                // We allow for a server round-trip time to allow enough time for a potential
                // aura to be applied.
                await CommonCoroutines.SleepForLagDuration();

                if (UseWhenPredicate.IsReady())
                {
                    QBCLog.Error(
                        "For DoWhenActivity {1}, predicate ({2}) was not reset by execution.{0}"
                        + "  This is a profile problem, and can result in erratic Honorbuddy behavior.{0}"
                        + "  The predicate must return to 'false' after the action has been successfully executed.",
                        Environment.NewLine, ActivityIdentifier, UseWhenPredicate.ExpressionAsString);
                }

                return(true);
            }
        public void SetValue(object newValueAsObject)
        {
            if (IsAccessDisallowed)
            {
                return;
            }

            var newValue = ToCongruentObject(newValueAsObject);

            if (!ConstraintChecker.IsWithinConstraints(newValue))
            {
                var message = string.Format("For '{0}', provided value ('{1}') is not within required constraints {2}.",
                                            Name, newValue, ConstraintChecker.Description);
                QBCLog.Error(message);
                throw new ArgumentException(message);
            }

            PropInfo.SetValue(SettingsInstance, newValue, null);
        }
        private object UtilGetAttributeAs <T>(string attributeName, bool isAttributeRequired, IConstraintChecker <T> constraints, string[] attributeNameAliases)
        {
            Type concreteType = typeof(T);

            // Vector3 are a triple of attributes, so requires special handling...
            if (concreteType == typeof(Vector3))
            {
                return(UtilGetXYZAttributesAsVector3(attributeName, isAttributeRequired, attributeNameAliases));
            }


            constraints = constraints ?? new ConstrainTo.Anything <T>();

            string keyName = UtilLocateKey(isAttributeRequired, attributeName, attributeNameAliases);

            if ((keyName == null) || !Attributes.ContainsKey(keyName))
            {
                return(null);
            }

            T      tmpResult;
            string valueAsString = Attributes[keyName];

            try
            { tmpResult = UtilTo <T>(keyName, valueAsString); }
            catch (Exception)
            {
                IsAttributeProblem = true;
                return(null);
            }

            string constraintViolationMessage = constraints.Check(keyName, tmpResult);

            if (constraintViolationMessage != null)
            {
                QBCLog.Error(QBCLog.BuildMessageWithContext(Element, constraintViolationMessage));
                IsAttributeProblem = true;
                return(null);
            }

            return(tmpResult);
        }
Example #23
0
        protected PursueObjectTypeBase(XElement xElement, string parameterName, Type expressionType)
            : base(xElement)
        {
            try
            {
                Id       = GetAttributeAsNullable <int>("Id", false, ConstrainAs.MobId, null) ?? 0;
                Priority = GetAttributeAsNullable <int>("Priority", false, new ConstrainTo.Domain <int>(-10000, 10000), null) ?? 0;

                var pursueWhenExpression  = GetAttributeAs <string>("PursueWhen", false, ConstrainAs.StringNonEmpty, null);
                var convertWhenExpression = GetAttributeAs <string>("ConvertWhen", false, ConstrainAs.StringNonEmpty, null) ?? "false";

                ConvertBy = GetAttributeAsNullable <ConvertByType>("ConvertBy", false, null, null) ?? ConvertByType.Killing;

                if (string.IsNullOrEmpty(pursueWhenExpression))
                {
                    if (Id == 0)
                    {
                        QBCLog.Error("Either Id, PursueWhen, or both must be specified.");
                        IsAttributeProblem = true;
                    }
                    else
                    {
                        pursueWhenExpression = "true";
                    }
                }

                ConvertWhenDelayCompiledExpression = (DelayCompiledExpression)Activator.CreateInstance(expressionType, parameterName + "=>" + convertWhenExpression);
                ConvertWhen = ConvertWhenDelayCompiledExpression.CallableExpression;

                PursueWhenDelayCompiledExpression = (DelayCompiledExpression)Activator.CreateInstance(expressionType, parameterName + "=>" + pursueWhenExpression);
                PursueWhen = PursueWhenDelayCompiledExpression.CallableExpression;
            }
            catch (Exception except)
            {
                if (Query.IsExceptionReportingNeeded(except))
                {
                    QBCLog.Exception(except, "PROFILE PROBLEM with \"{0}\"", xElement.ToString());
                }
                IsAttributeProblem = true;
            }
        }
Example #24
0
        private void ActionSetEnableState(bool wantEnabled)
        {
            var activityIdentifier = FindActivityIdentifier();
            var activity           = FindActivity(activityIdentifier);

            // If activity does not exist, that's a problem...
            if (activity == null)
            {
                QBCLog.Error("DoWhenActivity '{0}' is not in use.", activityIdentifier);
                return;
            }

            // Update activity's enabled status...
            var previousState = activity.UseWhenPredicate.IsEnabled;

            activity.UseWhenPredicate.IsEnabled = wantEnabled;
            QBCLog.DeveloperInfo("DoWhenActivity '{0}' {1} (was {2}).",
                                 activity.ActivityIdentifier,
                                 (wantEnabled ? "enabled" : "disabled"),
                                 (previousState ? "enabled" : "disabled"));
        }
Example #25
0
        public override void OnStart()
        {
            // Let QuestBehaviorBase do basic initializaion of the behavior, deal with bad or deprecated attributes,
            // capture configuration state, install BT hooks, etc.  This will also update the goal text.
            var isBehaviorShouldRun = OnStart_QuestBehaviorCore();

            // 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 (isBehaviorShouldRun)
            {
                HbProcId     = System.Diagnostics.Process.GetCurrentProcess().Id;
                _pipeFactory = new ChannelFactory <IRemotingApi>(new NetNamedPipeBinding(),
                                                                 new EndpointAddress("net.pipe://localhost/HBRelog/Server"));
                try
                {
                    HBRelogRemoteApi = _pipeFactory.CreateChannel();

                    IsConnected = HBRelogRemoteApi.Init(HbProcId);
                    if (IsConnected)
                    {
                        QBCLog.DeveloperInfo("Connected to HBRelog Server");
                        CurrentProfileName = HBRelogRemoteApi.GetCurrentProfileName(HbProcId);
                        QBCLog.DeveloperInfo(string.Format("HBRelog Current Profile: {0}", CurrentProfileName));
                    }
                    else
                    {
                        QBCLog.Error("Could Not Connect to HBRelog Server at net.pipe://localhost/HBRelog/Server");
                    }
                }
                catch (Exception ex)
                {
                    QBCLog.Error(
                        "Could not make endpoint connection to HBRelog Application.  You may not be running under HBRelog. Ignoring");
                    CurrentProfileName = string.Empty;
                }
            }
        }
        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;
            }
        }
Example #27
0
        public ButtonPressOnAura(Dictionary <string, string> args)
            : base(args)
        {
            QBCLog.BehaviorLoggingContext = this;

            try
            {
                int[] tmpAuras;

                // FOR FUTURE IMPLEMENTATION...
                // Self Auras --
                //for (int i = 1;   i <= 12;    ++i)
                //{
                //    string      attributeName   = string.Format("Button{0}SelfAuraId", i);
                //    tmpAuras    = GetNumberedAttributesAsIntegerArray(attributeName, 0, 1, int.MaxValue, null) ?? new int[0];
                //    UtilPopulateMapWithAuras(SelfAuraToButtonMap, i, tmpAuras);
                //}

                // Target Auras --
                for (int i = 1; i <= 12; ++i)
                {
                    string attributeName = string.Format("Button{0}TargetAuraId", i);
                    tmpAuras = GetNumberedAttributesAsArray <int>(attributeName, 0, ConstrainAs.AuraId, null);
                    UtilPopulateMapWithAuras(_targetAuraToButtonMap, i, tmpAuras);
                }

                ButtonOnQuestComplete  = GetAttributeAsNullable <int>("ButtonOnQuestComplete", false, ConstrainAs.HotbarButton, null);
                HuntingGroundAnchor    = GetAttributeAsNullable <WoWPoint>("", false, ConstrainAs.WoWPointNonEmpty, null) ?? Me.Location;
                HuntingGroundRadius    = GetAttributeAsNullable <double>("HuntingGroundRadius", false, new ConstrainTo.Domain <double>(1.0, 200.0), null) ?? 120.0;
                IgnoreMobsInBlackspots = GetAttributeAsNullable <bool>("IgnoreMobsInBlackspots", false, null, null) ?? false;
                MobIds                   = GetNumberedAttributesAsArray <int>("MobId", 1, ConstrainAs.MobId, null);
                NonCompeteDistance       = GetAttributeAsNullable <double>("NonCompeteDistance", false, new ConstrainTo.Domain <double>(1.0, 150.0), null) ?? 25.0;
                PostInteractDelay        = TimeSpan.FromMilliseconds(GetAttributeAsNullable <int>("PostInteractDelay", false, new ConstrainTo.Domain <int>(0, 61000), null) ?? 1000);
                QuestId                  = GetAttributeAsNullable <int>("QuestId", true, ConstrainAs.QuestId(this), null) ?? 0;
                QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete;
                QuestRequirementInLog    = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog;


                // Semantic coherency --
                if ((_selfAuraToButtonMap.Count() == 0) && (_targetAuraToButtonMap.Count() == 0))
                {
                    QBCLog.Error("You must specify at least one ButtonNTargetAura attribute.");
                    IsAttributeProblem = true;
                }

                // Final initialization...
                _behavior_HuntingGround = new HuntingGroundBehavior(ViableTargets,
                                                                    HuntingGroundAnchor,
                                                                    HuntingGroundRadius);
            }

            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;
            }
        }
Example #28
0
        protected override Composite CreateMainBehavior()
        {
            return(_root ?? (_root =
                                 new PrioritySelector(
                                     // don't drop down while wait timer is running
                                     new Decorator(ctx => !_waitTimer.IsFinished, new ActionAlwaysSucceed()),

                                     new Decorator(ret => Counter > NumOfTimes,
                                                   new Action(ret => BehaviorDone(string.Format("Used the item {0} times", NumOfTimes)))),

                                     // If item is not in our backpack, behavior is done...
                                     new Decorator(context => Item == null,
                                                   new Action(context =>
            {
                QBCLog.Error("ItemId({0}) is not in our backpack", ItemId);
                TreeRoot.Stop();
                BehaviorDone("Item is not in our backpack");
            })),

                                     // Wait for item to come off of cooldown...
                                     new Decorator(context => Item.CooldownTimeLeft > TimeSpan.Zero,
                                                   new Action(context => QBCLog.Info("Waiting for {0} to leave cooldown (time remaining: {1})",
                                                                                     Item.SafeName, Item.CooldownTimeLeft))),

                                     new Decorator(
                                         ret => UseType == QBType.PointToPoint,
                                         new PrioritySelector(
                                             new Decorator(
                                                 ret => Me.Location.Distance(MoveToLocation) > 3,
                                                 new ActionRunCoroutine(context => UtilityCoroutine.MoveTo(MoveToLocation, "Destination", MovementBy))),
                                             new Sequence(
                                                 new Action(ret => TreeRoot.StatusText = string.Format("Using Quest Item: {0} Out of {1} Times",
                                                                                                       Counter, NumOfTimes)),
                                                 new Action(ret => Navigator.PlayerMover.MoveStop()),
                                                 new Action(ret => Me.SetFacing(ClickToLocation)),
                                                 new SleepForLagDuration(),
                                                 new Action(ret => Item.UseContainerItem()),
                                                 new SleepForLagDuration(),
                                                 new Action(ret => Counter++),
                                                 new Action(ret => SpellManager.ClickRemoteLocation(ClickToLocation)),
                                                 new Action(ctx => _waitTimer.Reset())
                                                 ))),

                                     new Decorator(
                                         ret => UseType == QBType.PointToObject,
                                         new PrioritySelector(
                                             new Decorator(
                                                 ret => UseObject == null && Me.Location.DistanceSqr(MoveToLocation) >= 2 * 2,
                                                 new Sequence(
                                                     new Action(ret => TreeRoot.StatusText = "Moving to location"),
                                                     new ActionRunCoroutine(context => UtilityCoroutine.MoveTo(MoveToLocation, "Destination", MovementBy)))),
                                             new Decorator(
                                                 ret => UseObject != null,
                                                 new PrioritySelector(
                                                     new Decorator(
                                                         ret => UseObject.DistanceSqr >= Range * Range,
                                                         new Sequence(
                                                             new Action(ret => TreeRoot.StatusText = "Moving closer to the object"),
                                                             new ActionRunCoroutine(context => UtilityCoroutine.MoveTo(UseObject.Location, "UseObject location", MovementBy)))),
                                                     new Decorator(
                                                         ret => UseObject.DistanceSqr < MinRange * MinRange,
                                                         new Sequence(
                                                             new Action(ret => TreeRoot.StatusText = "Too Close, Backing Up"),
                                                             new ActionRunCoroutine(context =>
                                                                                    UtilityCoroutine.MoveTo(
                                                                                        WoWMathHelper.CalculatePointFrom(Me.Location, UseObject.Location, (float)MinRange + 2f),
                                                                                        "Backing up",
                                                                                        MovementBy))
                                                             )),
                                                     new Sequence(
                                                         new Action(ret => TreeRoot.StatusText = string.Format("Using Item: {0} {1} Out of {2} Times",
                                                                                                               UseObject.SafeName, Counter, NumOfTimes)),
                                                         new Action(ret => Navigator.PlayerMover.MoveStop()),
                                                         new Action(ret => Me.SetFacing(UseObject.Location)),
                                                         new SleepForLagDuration(),
                                                         new Action(ret => Item.UseContainerItem()),
                                                         new Action(ret => Counter++),
                                                         new SleepForLagDuration(),
                                                         new Action(ret => SpellManager.ClickRemoteLocation(UseObject.Location)),
                                                         new Action(ret => _npcBlacklist.Add(UseObject.Guid)),
                                                         new Action(ctx => _waitTimer.Reset())))),
                                             new Action(ret => TreeRoot.StatusText = "No objects around. Waiting")
                                             )),

                                     new Decorator(
                                         ret => UseType == QBType.ToObject,
                                         new PrioritySelector(
                                             new Decorator(
                                                 ret => UseObject != null,
                                                 new PrioritySelector(
                                                     new Decorator(
                                                         ret => UseObject.DistanceSqr >= Range * Range,
                                                         new Sequence(
                                                             new Action(ret => TreeRoot.StatusText = "Moving to object's range"),
                                                             new ActionRunCoroutine(context => UtilityCoroutine.MoveTo(UseObject.Location, "UseObject location", MovementBy)))),
                                                     new Decorator(
                                                         ret => UseObject.DistanceSqr < MinRange * MinRange,
                                                         new Sequence(
                                                             new Action(ret => TreeRoot.StatusText = "Too Close, Backing Up"),
                                                             new ActionRunCoroutine(
                                                                 context =>
                                                                 UtilityCoroutine.MoveTo(
                                                                     WoWMathHelper.CalculatePointFrom(Me.Location, UseObject.Location, (float)MinRange + 2f),
                                                                     "Backing up",
                                                                     MovementBy))
                                                             )),
                                                     new Sequence(
                                                         new Action(ret => TreeRoot.StatusText = string.Format("Using Item: {0} {1} Out of {2} Times",
                                                                                                               UseObject.SafeName, Counter, NumOfTimes)),
                                                         new Action(ret => Navigator.PlayerMover.MoveStop()),
                                                         new Action(ret => Me.SetFacing(UseObject.Location)),
                                                         new SleepForLagDuration(),
                                                         new Action(ret => Item.UseContainerItem()),
                                                         new Action(ret => Counter++),
                                                         new SleepForLagDuration(),
                                                         new Action(ret => SpellManager.ClickRemoteLocation(UseObject.Location)),
                                                         new Action(ret => _npcBlacklist.Add(UseObject.Guid)),
                                                         new Action(ctx => _waitTimer.Reset())))),
                                             new Decorator(
                                                 ret => Me.Location.DistanceSqr(MoveToLocation) > 2 * 2,
                                                 new Sequence(
                                                     new Action(ret => TreeRoot.StatusText = "Moving to location"),
                                                     new ActionRunCoroutine(context => UtilityCoroutine.MoveTo(MoveToLocation, "Destination", MovementBy))))
                                             ))
                                     )));
        }
        protected override Composite CreateBehavior()
        {
            return(_Root ?? (_Root =
                                 new PrioritySelector(context => !s_isBehaviorDone,

                                                      #region MyHotSpot
                                                      // Store our current location.
                                                      new Decorator(context => MyHotSpot == WoWPoint.Empty,
                                                                    new Sequence(
                                                                        new DecoratorContinue(context => Me.IsMoving,
                                                                                              new WaitContinue(TimeSpan.FromMilliseconds(2000), context => false, new ActionAlwaysSucceed())
                                                                                              ),
                                                                        new DecoratorContinue(context => !Me.IsMoving,
                                                                                              new Action(context => MyHotSpot = Me.Location)
                                                                                              )
                                                                        )
                                                                    ),
                                                      #endregion

                                                      #region MinLevel
                                                      // Should we check for partymember minumum level ?
                                                      new Decorator(context => (MinLevel > 0),
                                                                    new Sequence(
                                                                        // Someone is below MinLevel.
                                                                        new DecoratorContinue(context => !CheckLevel(),
                                                                                              new Sequence(
                                                                                                  new Action(context => QBCLog.Info("Someone in your party is below level {0}.", MinLevel)),
                                                                                                  new Action(context => s_isBehaviorDone = true)
                                                                                                  )
                                                                                              ),
                                                                        // Everyone is equal or above MinLevel.
                                                                        new DecoratorContinue(context => CheckLevel(),
                                                                                              new Action(context => MinLevel = 0)
                                                                                              )
                                                                        )
                                                                    ),
                                                      #endregion

                                                      #region CheckRange
                                                      // Should we wait for party members to be in range ?
                                                      new Decorator(context => (CheckRange != 0),
                                                                    new Sequence(
                                                                        // Everyone isn't within interact range, lets wait abit before checking again.
                                                                        new DecoratorContinue(context => !CheckPartyRange(),
                                                                                              new Sequence(
                                                                                                  new DecoratorContinue(context => !Navigator.AtLocation(MyHotSpot),
                                                                                                                        new Sequence(
                                                                                                                            new DecoratorContinue(context => Navigator.CanNavigateFully(Me.Location, MyHotSpot),
                                                                                                                                                  new Action(context => Navigator.MoveTo(MyHotSpot))
                                                                                                                                                  ),
                                                                                                                            new DecoratorContinue(context => !Navigator.CanNavigateFully(Me.Location, MyHotSpot),
                                                                                                                                                  new Action(context => Flightor.MoveTo(MyHotSpot))
                                                                                                                                                  )
                                                                                                                            )
                                                                                                                        ),
                                                                                                  new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed())
                                                                                                  )
                                                                                              ),
                                                                        // Everyone is within interact range.
                                                                        new DecoratorContinue(context => CheckPartyRange(),
                                                                                              new Sequence(
                                                                                                  new Action(context => QBCLog.Info("Everyone is within range.")),
                                                                                                  new Action(context => CheckRange = 0)
                                                                                                  )
                                                                                              )
                                                                        )
                                                                    ),
                                                      #endregion

                                                      #region ChkExp
                                                      // Disabled until I can find out a safer way to to it.

                                                      /*
                                                       * new Decorator(context => (ChkExp != 0),
                                                       *  new Sequence(
                                                       *      new DecoratorContinue(context => !AreWeDone(),
                                                       *          new Action(context => CheckExpansions())
                                                       *      ),
                                                       *      new DecoratorContinue(context => AreWeDone(),
                                                       *          new Sequence(
                                                       *              new DecoratorContinue(context => !DoAllHaveExp(),
                                                       *                  new Sequence(
                                                       *                      new Action(context => QBCLog.Info("Everyone in your group doesn't have ExpansionLevel '{0}'", ChkExp)),
                                                       *                      new Action(context => _isBehaviorDone = true)
                                                       *                  )
                                                       *              ),
                                                       *              new DecoratorContinue(context => DoAllHaveExp(),
                                                       *                  new Sequence(
                                                       *                      new Action(context => QBCLog.Info("Everyone has atleast ExpansionLevel '{0}'", ChkExp)),
                                                       *                      new Action(context => ChkExp = 0)
                                                       *                  )
                                                       *              )
                                                       *          )
                                                       *      )
                                                       *  )
                                                       * ),
                                                       */
                                                      #endregion

                                                      #region RemotePath
                                                      // Load the remote profile...
                                                      new Decorator(context => RemotePath != "",
                                                                    new Sequence(
                                                                        // You have included a RemotePath but not a ProfileName.
                                                                        new DecoratorContinue(context => ProfileName == "",
                                                                                              new Sequence(
                                                                                                  new Action(context => QBCLog.Error("You need to include a ProfileName.")),
                                                                                                  new Action(context => s_isBehaviorDone = true)
                                                                                                  )
                                                                                              ),
                                                                        // Remote Profile doesn't exist.
                                                                        new DecoratorContinue(context => (ProfileName != "" && !UrlExists(NewRemoteProfilePath)),
                                                                                              new Sequence(
                                                                                                  new Action(context => QBCLog.Error("Profile '{0}' does not exist.", ProfileName)),
                                                                                                  new Action(context => s_isBehaviorDone = true)
                                                                                                  )
                                                                                              ),
                                                                        // Everything is ok, Load the remote Profile
                                                                        new DecoratorContinue(context => (ProfileName != "" && UrlExists(NewRemoteProfilePath)),
                                                                                              new Sequence(
                                                                                                  new Action(context => TreeRoot.StatusText = "Loading profile '" + ProfileName + "'"),
                                                                                                  new Action(context => QBCLog.Info("Loading profile '{0}'", ProfileName)),
                                                                                                  new Action(context => ProfileManager.LoadNew(new MemoryStream(new WebClient().DownloadData(NewRemoteProfilePath)))),
                                                                                                  new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed()),
                                                                                                  new Action(context => s_isBehaviorDone = true)
                                                                                                  )
                                                                                              )
                                                                        )
                                                                    ),
                                                      #endregion

                                                      #region ProfileName
                                                      // Load the local profile...
                                                      new Decorator(context => (ProfileName != "" && RemotePath == ""),
                                                                    new PrioritySelector(
                                                                        // Local Profile doesn't exist.
                                                                        new Decorator(context => !IsStoreProfile && !File.Exists(NewLocalProfilePath),
                                                                                      new Sequence(
                                                                                          new Action(context => QBCLog.Error("Profile '{0}' does not exist.", ProfileName)),
                                                                                          new Action(context => s_isBehaviorDone = true)
                                                                                          )
                                                                                      ),
                                                                        // Everything is ok, Load the local Profile.
                                                                        new Sequence(
                                                                            new Action(context => TreeRoot.StatusText = "Loading profile '" + ProfileName + "'"),
                                                                            new Action(context => QBCLog.Error("Loading profile '{0}'", ProfileName)),
                                                                            new Action(context => ProfileManager.LoadNew(NewLocalProfilePath, false)),
                                                                            new WaitContinue(TimeSpan.FromMilliseconds(300), context => false, new ActionAlwaysSucceed()),
                                                                            new Action(context => s_isBehaviorDone = true)
                                                                            )
                                                                        )
                                                                    ),
                                                      #endregion

                                                      #region Behavior Done
                                                      // Everyone is within interact range and we shouldn't load a profile, then end the Quest Behavior.
                                                      new Decorator(context => !s_isBehaviorDone,
                                                                    new Action(context => s_isBehaviorDone = true)
                                                                    )
                                                      #endregion
                                                      )
                             ));
        }
        private 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);
        }