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 Composite CreateMainBehavior() { // NB: We need to allow lower BT nodes to run when the behavior is finished; otherwise, HB will not // process the change of _isBehaviorDone state. return(new PrioritySelector( // If quest is done, behavior is done... new Decorator(context => IsDone, new Action(context => { _isBehaviorDone = true; QBCLog.Info("Finished"); })), // If using cannon, start spanking targets... new Decorator(context => Query.IsInVehicle(), // Ready, Aim, Fire! new Action(context => { // If ejected from vehicle, try to re-locate it... if ((CannonVehicle == null) || !CannonVehicle.IsValid) { CannonVehicle = FindUnitsFromId(VehicleId_NurongsCannon).FirstOrDefault(); return; } // If target is no longer valid, select another... if (!IsViableTarget(CannonVehicle, SelectedTarget)) { SelectedTarget = ChooseTarget(CannonVehicle, SelectedTarget); if (SelectedTarget == null) { return; } SelectedTarget.Target(); } AimAndFireCannon(CannonVehicle, SelectedTarget); })), // If not using cannon, get in cannon vehicle... new Decorator(context => !Query.IsInVehicle(), new PrioritySelector(cannonContext => FindUnitsFromId(MobId_NurongsCannon).FirstOrDefault(), // If unable to locate cannon, warn user and stop... new Decorator(cannonContext => cannonContext == null, new PrioritySelector( // The Wait is a defensive bumper against a WoWclient/HBcore race condition... // Sometimes, the toon is ejected from the vehicle before the quest is marked as 'complete'. // We don't want this situation to cause the profile to stop, so we wait for a short while // before declaring a profile problem. new Wait(TimeSpan.FromMilliseconds(5000), cannonContext => IsDone, new ActionAlwaysSucceed()), new Action(cannonContext => { QBCLog.Error("PROFILE ERROR: Nurong's Cannon is not in the area--please repair profile"); TreeRoot.Stop(); _isBehaviorDone = true; }) )), // Move close enough, and interact with cannon... new Decorator(cannonContext => ((WoWUnit)cannonContext).Distance > ((WoWUnit)cannonContext).InteractRange, new Action(cannonContext => { Navigator.MoveTo(((WoWUnit)cannonContext).Location); })), new Decorator(cannonContext => !Me.IsFacing((WoWUnit)cannonContext), new Action(cannonContext => { ((WoWUnit)cannonContext).Face(); })), new Decorator(cannonContext => Me.IsMoving, new Action(cannonContext => { WoWMovement.MoveStop(); })), new Decorator(cannonContext => !Query.IsInVehicle(), new Action(cannonContext => { ((WoWUnit)cannonContext).Interact(); CannonVehicle = null; })), new Wait(TimeSpan.FromMilliseconds(5000), cannonContext => Query.IsInVehicle(), new ActionAlwaysSucceed()) )) )); }