protected override Composite CreateMainBehavior() { return(new PrioritySelector( new Decorator(context => !Query.IsViable(Mob_ToAvoid), new ActionFail(context => { Mob_ToAvoid = Query.FindMobsAndFactions(Utility.ToEnumerable <int>(MobIdToAvoid)) .FirstOrDefault() as WoWUnit; })), new Decorator(context => !Query.IsViable(Mob_ToMoveNear), new ActionFail(context => { Mob_ToMoveNear = Query.FindMobsAndFactions(Utility.ToEnumerable <int>(MobIdToMoveNear)) .FirstOrDefault() as WoWUnit; })), // Stateful Operation: // NB: We do not allow combat in all states. Fighting is mostl limited to our 'safespot' position. new Switch <StateType_MainBehavior>(context => State_MainBehavior, new Action(context => // default case { var message = string.Format("StateType_MainBehavior({0}) is unhandled", State_MainBehavior); QBCLog.MaintenanceError(message); TreeRoot.Stop(); BehaviorDone(message); }), new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.MovingToSafespot, StateBehaviorPS_MovingToSafeSpot()), new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathIngressing, StateBehaviorPS_PathIngressing()), new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathRetreating, StateBehaviorPS_PathRetreating()), new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.DestinationReached, StateBehaviorPS_DestinationReached()) ))); }
private string FindActivityIdentifier() { if (ActivityKey_ItemId > 0) { return(DoWhenUseItemActivity.CreateActivityIdentifier(ActivityKey_ItemId)); } if (ActivityKey_SpellId > 0) { return(DoWhenCastSpellActivity.CreateActivityIdentifier(ActivityKey_SpellId)); } if (!string.IsNullOrEmpty(ActivityKey_Name)) { return(DoWhenNamedActivity.CreateActivityIdentifier(ActivityKey_Name)); } QBCLog.MaintenanceError("Unable to find ActivityIdentifier for ItemId, SpellId, or ActivityName--none were specified."); return(string.Empty); }
protected override Composite CreateMainBehavior() { return(new PrioritySelector( new Switch <BehaviorStateType>(context => BehaviorState, new Action(context => // default case { var message = string.Format("BehaviorStateType({0}) is unhandled", BehaviorState); QBCLog.MaintenanceError(message); TreeRoot.Stop(); BehaviorDone(message); }), new SwitchArgument <BehaviorStateType>(BehaviorStateType.MountingVehicle, StateBehaviorPS_MountingVehicle()), new SwitchArgument <BehaviorStateType>(BehaviorStateType.RidingOutToHuntingGrounds, StateBehaviorPS_RidingOutToHuntingGrounds()), new SwitchArgument <BehaviorStateType>(BehaviorStateType.CompletingObjectives, StateBehaviorPS_CompletingObjectives()), new SwitchArgument <BehaviorStateType>(BehaviorStateType.ReturningToBase, StateBehaviorPS_ReturningToBase()) ))); }
private IVisitStrategy GetVisitStrategyFromType(WaypointVisitStrategyType visitStrategyType) { IVisitStrategy visitStrategy = null; if (visitStrategyType == WaypointVisitStrategyType.InOrder) { visitStrategy = new VisitStrategy_InOrder(); } else if (visitStrategyType == WaypointVisitStrategyType.PickOneAtRandom) { visitStrategy = new VisitStrategy_PickOneAtRandom(); } else if (visitStrategyType == WaypointVisitStrategyType.Random) { visitStrategy = new VisitStrategy_Random(); } else { QBCLog.MaintenanceError("Unhandled WaypointVisitStrategy({0})", visitStrategyType); } return(visitStrategy); }
private async Task <bool> MainBehaviorCoroutine() { switch (BehaviorState) { case BehaviorStateType.MountingVehicle: return(await StateCoroutine_MountingVehicle()); case BehaviorStateType.RidingOutToHuntingGrounds: return(await StateCoroutine_RidingOutToHuntingGrounds()); case BehaviorStateType.CompletingObjectives: return(await StateCoroutine_CompletingObjectives()); case BehaviorStateType.ReturningToBase: return(await StateCoroutine_ReturningToBase()); default: var message = string.Format("BehaviorStateType({0}) is unhandled", BehaviorState); QBCLog.MaintenanceError(message); TreeRoot.Stop(); BehaviorDone(message); return(false); } }
private Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update information for this BT visit... new Action(context => { HighWarlordDarion = ObjectManager.GetObjectsOfType <WoWUnit>(false, false).FirstOrDefault(u => u.Entry == 29173); if ((HighWarlordDarion != null) && (Me.CurrentTarget != HighWarlordDarion)) { HighWarlordDarion.Target(); } return RunStatus.Failure; }), new Switch <StateType_Behavior>(context => State_Behavior, #region State: DEFAULT new Action(context => // default case { QBCLog.MaintenanceError("State_Behavior({0}) is unhandled", State_Behavior); TreeRoot.Stop(); _isBehaviorDone = true; }), #endregion #region State: Wait for Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForWarlordDarion, new PrioritySelector( // Move into position to await Warlord arrival... new Decorator(context => !Navigator.AtLocation(Location_WaitToChatWithDarion), new Action(context => { TreeRoot.StatusText = "Moving into position to wait on High Warlord Darion to arrive"; Navigator.MoveTo(Location_WaitToChatWithDarion); })), // Warlord has arrived, go have a chat.. new Decorator(context => HighWarlordDarion != null, new Action(context => { State_Behavior = StateType_Behavior.ChattingToStartBattle; })), // If warlord is not here, go check the battlefield... new Decorator(context => !IsBattlefieldCheckedForDarion, new Action(context => { State_Behavior = StateType_Behavior.CheckingBattlefieldForWarlordDarion; })), new Action(context => { TreeRoot.StatusText = "Waiting for High Warlord Darion to arrive"; AntiAfk(); }) )), #endregion #region State: Check Battlefield for Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.CheckingBattlefieldForWarlordDarion, new PrioritySelector( // Move into position to await Warlord arrival... new Decorator(context => !Navigator.AtLocation(Location_WaitForBattleToComplete), new Action(context => { TreeRoot.StatusText = "Checking battlefield for High Warlord Darion"; Navigator.MoveTo(Location_WaitForBattleToComplete); })), // If we found Warlord on battlefield, wait for battle to complete... new Decorator(context => HighWarlordDarion != null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToComplete; })), // If warlord is not here, return to start point and wait... new Decorator(context => HighWarlordDarion == null, new Action(context => { IsBattlefieldCheckedForDarion = true; State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })) )), #endregion #region State: Chat with Warlord new SwitchArgument <StateType_Behavior>(StateType_Behavior.ChattingToStartBattle, new PrioritySelector( // If the Warlord disappeared, go find him... new Decorator(context => HighWarlordDarion == null, new Action(context => { IsBattlefieldCheckedForDarion = false; State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // Move close enough to chat with Warlord... new Decorator(context => !HighWarlordDarion.WithinInteractRange, new Action(context => { TreeRoot.StatusText = "Moving to " + HighWarlordDarion.SafeName; Navigator.MoveTo(HighWarlordDarion.Location); })), // Chat with warlord... // When we interact with the warlord, he will present us with either: // 1) a Quest frame (with no gossip options) // 2) a Gossip frame (with gossip options) that we use to kick off the event // Both frames always *exist*, what matters is the one the Warlord presents us with. new Decorator(context => HighWarlordDarion.CanGossip, new PrioritySelector( new Decorator(context => !(GossipFrame.Instance.IsVisible || QuestFrame.Instance.IsVisible), new Action(context => { HighWarlordDarion.Interact(); })), // Process GossipFrame or QuestFrame, whichever was presented... new Sequence( // Simulate reading frame text... new WaitContinue(VariantTimeSpan(2500, 7000), context => false, new ActionAlwaysSucceed()), // If gossip frame showing, choose correct gossip option... new DecoratorContinue(context => GossipFrame.Instance.IsVisible && GossipFrame.Instance.GossipOptionEntries.Count() > 0, new Action(context => { GossipFrame.Instance.SelectGossipOption(0); })), new WaitContinue(VariantTimeSpan(1250, 3500), context => false, new ActionAlwaysSucceed()), // Close gossip frame if that was showing... new DecoratorContinue(context => GossipFrame.Instance.IsVisible, new Action(context => { GossipFrame.Instance.Close(); })), // Close quest frame if that was showing... new DecoratorContinue(context => QuestFrame.Instance.IsVisible, new Action(context => { QuestFrame.Instance.Close(); })), new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToStart; }) ) )), // Warlord doesn't want to chat, wait for battle to start... new Decorator(context => !HighWarlordDarion.CanGossip, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToStart; })) )), #endregion #region State: Wait for Battle to start new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForBattleToStart, new PrioritySelector( // If warlord disappeared, start over... new Decorator(context => HighWarlordDarion == null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // If Warlord is already on the battlefield, time to go... new Decorator(context => HighWarlordDarion.Location.Distance(Location_Battlefield.Location) <= Location_Battlefield.Radius, new Action(context => { State_Behavior = StateType_Behavior.WaitingForBattleToComplete; })), // If the warlord is not on the battlefield, follow him at a reasonable distance... new Decorator(context => HighWarlordDarion.Distance > DistanceToFollowWarlord, new Action(context => { TreeRoot.StatusText = string.Format("Following {0}", HighWarlordDarion.SafeName); Navigator.MoveTo(HighWarlordDarion.Location); })), // Move into position to await battle start... new Decorator(context => !HighWarlordDarion.IsMoving && !Navigator.AtLocation(Location_WaitToChatWithDarion), new Action(context => { TreeRoot.StatusText = "Waiting for Battle to start"; Navigator.MoveTo(Location_WaitToChatWithDarion); })) )), #endregion #region State: Wait for Battle to complete new SwitchArgument <StateType_Behavior>(StateType_Behavior.WaitingForBattleToComplete, new PrioritySelector( // If warlord disappeared, start over... new Decorator(context => HighWarlordDarion == null, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })), // If the warlord is on the battlefield, wait at our safespot... new Decorator(context => HighWarlordDarion.Location.Distance(Location_Battlefield.Location) <= Location_Battlefield.Radius, new PrioritySelector( // Move to our position to wait for battle to be over... new Decorator(context => !Navigator.AtLocation(Location_WaitForBattleToComplete), new Action(context => { TreeRoot.StatusText = "Moving to safe spot"; Navigator.MoveTo(Location_WaitForBattleToComplete); })), // Wait for battle to be over... new Action(context => { TreeRoot.StatusText = "Waiting for battle to complete."; AntiAfk(); }))), // If the warlord has returned to his starting position, then start over... new Decorator(context => HighWarlordDarion.Location.Distance(Location_WaitToChatWithDarion) <= DistanceToFollowWarlord, new Action(context => { State_Behavior = StateType_Behavior.WaitingForWarlordDarion; })) )) #endregion ) ))); }
private Composite StateBehaviorPS_PathIngressing() { return(new PrioritySelector( // If no Ingress path exists, build it... new Decorator(context => Path_Ingress == null, new Action(context => { Path_Ingress = FollowPath.FindPath_Ingress(); })), // If we've consumed our Ingress path (or the one we initially built is empty), we're done... new Decorator(context => !Path_Ingress.Any(), new Action(context => { State_MainBehavior = StateType_MainBehavior.DestinationReached; })), // If Mob_ToAvoid is too close or we get in combat, abandon current ingress, and retreat back to safespot... new Decorator(context => Query.IsViable(Mob_ToAvoid) && ((Mob_ToAvoid.Distance < FollowPath.EgressDistance) || Me.Combat), new Action(context => { Path_Ingress = null; Path_Egress = null; State_MainBehavior = StateType_MainBehavior.PathRetreating; })), new Switch <SafePathType.StrategyType>(context => FollowPath.Strategy, new Action(context => // default case { var message = string.Format("FollowPathStrategyType({0}) is unhandled", FollowPath.Strategy); QBCLog.MaintenanceError(message); TreeRoot.Stop(); BehaviorDone(message); }), new SwitchArgument <SafePathType.StrategyType>(SafePathType.StrategyType.StalkMobAtAvoidDistance, new Decorator(context => Query.IsViable(Mob_ToAvoid) && (Mob_ToAvoid.Distance < AvoidDistance), new PrioritySelector( new ActionRunCoroutine(context => CommonCoroutines.StopMoving()), new ActionAlwaysSucceed() ))), new SwitchArgument <SafePathType.StrategyType>(SafePathType.StrategyType.WaitForAvoidDistance, new PrioritySelector( // No addition action needed to implement strategy for now )) ), // If we've arrived at the current ingress waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(Path_Ingress.Peek().Location), new Action(context => { FollowPath.DismissPetIfNeeded(); Path_Ingress.Dequeue(); })), // Follow the prescribed ingress path, if its still safe to proceed... new Decorator(context => IsSafeToMoveToDestination(Mob_ToAvoid), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( Path_Ingress.Peek().Location, "follow ingress path", MovementBy))), // If mob is heading our direction, hold position... new Decorator(context => !IsSafeToMoveToDestination(Mob_ToAvoid), new Sequence( new Action(context => { TreeRoot.StatusText = string.Format("Holding position to evaluate {0}'s actions.", Mob_ToAvoid.SafeName); }), new ActionRunCoroutine(context => CommonCoroutines.StopMoving()) )) )); }
private Composite CreateMainBehavior() { return(new PrioritySelector( // If quest is done, behavior is done... new Decorator(context => IsDone, new Action(context => { _isBehaviorDone = true; QBCLog.Info("Finished"); })), // Stateful Operation: new Switch <StateType_MainBehavior>(context => State_MainBehavior, #region State: DEFAULT new Action(context => // default case { QBCLog.MaintenanceError("StateType_MainBehavior({0}) is unhandled", State_MainBehavior); TreeRoot.Stop(); _isBehaviorDone = true; }), #endregion #region State: Dropping Off Victim new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.DroppingOffVictim, new PrioritySelector( // If Watchman dropped off, go get another... new Decorator(context => !Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { WoWMovement.MoveStop(); _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // Move to drop off spot... new Decorator(context => Me.Location.Distance(PositionToMakeLandfall) > Navigator.PathPrecision, new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( PositionToMakeLandfall, "back to shore"))) )), #endregion #region State: Pathing Out to Victim new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathingOutToVictim, new PrioritySelector( // If our selected target is no good, find another... new Decorator(context => !IsViableDrowningWatchman(SelectedTarget), new Action(context => { QBCLog.Info("Finding new Drowning Watchman to save"); _currentPath = null; SelectedTarget = FindDrowningWatchman(); })), // Show user which target we're after... new Decorator(context => Me.CurrentTarget != SelectedTarget, new Action(context => { SelectedTarget.Target(); })), // If we don't have a path to victim, find one... new Decorator(context => _currentPath == null, new Action(context => { _currentPath = FindPath(Me.Location, SelectedTarget.Location); })), // If path completely consumed, we're done... new Decorator(context => _currentPath.Count() <= 0, new Action(context => { State_MainBehavior = StateType_MainBehavior.Rescuing; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(_currentPath.Peek()), new Action(context => { _currentPath.Dequeue(); })), // Follow the prescribed path... new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( _currentPath.Peek(), "out to Drowned Watcman")) )), #endregion #region State: Rescuing new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.Rescuing, new PrioritySelector( // If we've got the Watchman, start heading in... new Decorator(context => Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { _currentPath = null; State_MainBehavior = StateType_MainBehavior.PathingIntoShore; })), // If our selected target is no good, find another... new Decorator(context => !IsViableDrowningWatchman(SelectedTarget), new Action(context => { _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // Go get a fresh Drowning Watchman... UtilityBehavior_InteractWithMob(context => SelectedTarget) )), #endregion #region State: Pathing Into Shore new SwitchArgument <StateType_MainBehavior>(StateType_MainBehavior.PathingIntoShore, new PrioritySelector( // If we don't have a path, find the correct one... new Decorator(context => _currentPath == null, new Action(context => { _currentPath = FindPath(Me.Location, PositionToMakeLandfall); })), // If path completely consumed, we're done... new Decorator(context => _currentPath.Count() <= 0, new Action(context => { State_MainBehavior = StateType_MainBehavior.DroppingOffVictim; })), // If we've lost the Watchman we rescued, go fetch another... new Decorator(context => !Me.HasAura(AuraId_RescueDrowningWatchman), new Action(context => { _currentPath = null; SelectedTarget = null; State_MainBehavior = StateType_MainBehavior.PathingOutToVictim; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(_currentPath.Peek()), new Action(context => { _currentPath.Dequeue(); })), // Follow the prescribed path... new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( _currentPath.Peek(), "in to drop off Drowned Watchman")) )) #endregion ))); }
public ChangeSet(Dictionary <string, object> changes) { var changeSet = new List <Tuple <SettingDescriptor, object> >(); var isProblemAttribute = false; foreach (var change in changes) { try { var name = change.Key; var value = change.Value; // Setting name cannot be null or empty... if (string.IsNullOrEmpty(name)) { QBCLog.Error("Name may not be null or empty"); isProblemAttribute = true; continue; } // Check that setting exists... var settingDescriptor = RecognizedSettings.FirstOrDefault(s => s.Name == name); if (settingDescriptor == null) { QBCLog.Error("Unable to locate setting for '{0}'.", name); isProblemAttribute = true; continue; } // Is changing attribute allowed? if (settingDescriptor.IsAccessDisallowed) { QBCLog.Error("Accessing attribute '{0}' is not allowed.", name); isProblemAttribute = true; continue; } // Check that setting doesn't already exist in the changeset... if (changeSet.Any(t => t.Item1.Name == name)) { QBCLog.Error("Setting '{0}' already exists in the changeset.", name); isProblemAttribute = true; continue; } // If user specified 'original' value, go look it up and substitute it for 'value'... if ((value is string) && ((string)value == "original")) { object originalValue; if (!OriginalConfiguration.TryGetValue(settingDescriptor.Name, out originalValue)) { // A missing 'original configuration' is a maintenance issue, not a user error... QBCLog.MaintenanceError("For setting '{0}', there is no original configuration value.", settingDescriptor.Name); isProblemAttribute = true; continue; } value = originalValue; } // Check that setting is an appropriate type... var newValue = settingDescriptor.ToCongruentObject(value); if (!settingDescriptor.ConstraintChecker.IsWithinConstraints(newValue)) { QBCLog.Error("For setting '{0}', the provided value '{1}' is not within the required constraints of {2}.", name, value, settingDescriptor.ConstraintChecker.Description); isProblemAttribute = true; continue; } // Setting change is acceptable... changeSet.Add(Tuple.Create(settingDescriptor, value)); } catch (Exception ex) { QBCLog.Exception(ex, "MAINTENANCE ERROR: Error processing attribute '{0}.'", change.Key); isProblemAttribute = true; } } // If problem encountered with any change, we're unable to build the ChangeSet... if (isProblemAttribute) { _changeSet = null; throw new ArgumentException("Problems encountered with provided argument"); } Count = changeSet.Count; _changeSet = new ReadOnlyCollection <Tuple <SettingDescriptor, object> >(changeSet); }
// CreateBehavior supplied by QuestBehaviorBase. // Instead, provide CreateMainBehavior definition. // Dispose provided by QuestBehaviorBase. // IsDone provided by QuestBehaviorBase. // Call the QuestBehaviorBase.BehaviorDone() method when you want to indicate your behavior is complete. // OnFinished provided by QuestBehaviorBase. public override void OnStart() { // Acquisition and checking of any sub-elements go here. // A common example: // HuntingGrounds = HuntingGroundsType.GetOrCreate(Element, "HuntingGrounds", HuntingGroundCenter); // IsAttributeProblem |= HuntingGrounds.IsAttributeProblem; // 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) { // The BotStop handler will remove the "use when" activities... // Note, we only want to hook BotStopped once for this behavior. if (!s_persistedIsOnBotStopHooked) { BotEvents.OnBotStopped += BotEvents_OnBotStopped; s_persistedIsOnBotStopHooked = true; } if (!s_persistedIsOnNewProfileLoadedHooked) { BotEvents.Profile.OnNewProfileLoaded += BotEvents_OnNewProfileLoaded; s_persistedIsOnNewProfileLoadedHooked = true; } switch (Command) { case CommandType.Disable: ActionSetEnableState(false); break; case CommandType.Enable: ActionSetEnableState(true); break; case CommandType.ShowActivities: ActionShowActivities(); break; case CommandType.Remove: ActionRemove(); break; case CommandType.Update: IUseWhenPredicate useWhenPredicate = (UseAtInterval > TimeSpan.Zero) ? (IUseWhenPredicate) new UseWhenPredicate_TimeElapse(UseAtInterval, AllowUseDuringCombat, AllowUseInVehicle, AllowUseWhileFlying, AllowUseWhileMounted) : (IUseWhenPredicate) new UseWhenPredicate_FuncEval(UseWhen, AllowUseDuringCombat, AllowUseInVehicle, AllowUseWhileFlying, AllowUseWhileMounted); ActionUpdate(useWhenPredicate, StopMovingToConductActivity); break; default: QBCLog.MaintenanceError("Unhandled action type of '{0}'.", Command); TreeRoot.Stop(); return; } // Install or remove behavior as needed... // We need to install the hook when its not present, AND there is something to execute. // We remove the hook if there is nothing left to execute. This betters the user's experience, // by maximizing performance. // NB: We cannot simply override the methods provided by QuestBehaviorBase, because this behavior // is unusual. We want these hooks to remain after this behavior terminates. If we use the // QuestBehaviorBase-provide facilities (e.g., override the methods), then the hooks would be // cleaned up (e.g., removed) when this behavior exits. if (s_persistedActivities.Count > 0) { DoWhenHookInstall(); } if (s_persistedActivities.Count <= 0) { DoWhenHookRemove(); } BehaviorDone(); } }