private async Task <bool> MainBehavior() { QBCLog.Info("Using hearthstone; {0} out of {1} tries", ++_retries, MaxRetries); bool onCooldown = false; await UtilityCoroutine.UseHearthStone( UseGarrisonHearthstone, hearthOnCooldownAction : () => onCooldown = true, hearthCastFailedAction : reason => { QBCLog.Warning("Hearth failed. Reason: {0}", reason); _retries++; }); if (_retries >= MaxRetries) { BehaviorDone(string.Format("We have reached our max number of tries ({0}) without successfully hearthing", MaxRetries)); return(true); } if (onCooldown && WaitOnCd) { TreeRoot.StatusText = "Waiting for hearthstone cooldown"; return(true); } BehaviorDone(); return(true); }
public override async Task <bool> Execute() { // If we have the quest, drop it... if (HasQuest(QuestId)) { Me.QuestLog.AbandonQuestById((uint)QuestId); await Coroutine.Wait(Delay.LagDuration, () => !HasQuest(QuestId)); return(true); } // If we cannot 'see' the mob yet, move to the rough location... var questGiver = ObjectManager.GetObjectsOfType <WoWUnit>().FirstOrDefault(u => u.Entry == QuestGiverId); if (questGiver == null) { await UtilityCoroutine.MoveTo(QuestGiverRoughLocation, "Quest Giver"); return(true); } if (!Navigator.AtLocation(questGiver.Location)) { return(await UtilityCoroutine.MoveTo(questGiver.Location, questGiver.Name)); } await ScriptHelpers.PickupQuest(questGiver, (uint)QuestId); await Coroutine.Wait(Delay.LagDuration, () => HasQuest(QuestId)); return(false); }
private Composite StateBehaviorPS_PathRetreating() { return(new PrioritySelector( // If no Egress path, build it... new Decorator(context => Path_Egress == null, new Action(context => { Path_Egress = FollowPath.FindPath_Egress(Mob_ToAvoid); QBCLog.Info("Retreating back to safespot due to {0}.", Me.Combat ? "combat" : string.Format("{0} too close (dist: {1:F1})", Mob_ToAvoid.SafeName, Mob_ToAvoid.Distance)); })), // If we've come to the end of our egress path, move back to safe spot... new Decorator(context => !Path_Egress.Any(), new Action(context => { Path_Ingress = null; Path_Egress = null; State_MainBehavior = StateType_MainBehavior.MovingToSafespot; })), // If we've arrived at the current waypoint, dequeue it... new Decorator(context => Navigator.AtLocation(Path_Egress.Peek().Location), new Action(context => { Path_Egress.Dequeue(); })), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( Path_Egress.Peek().Location, "retreat", MovementBy)) )); }
private async Task <bool> UtilityCoroutine_MoveToStartPosition() { if (Navigator.AtLocation(WaitPoint)) { return(false); } return(await UtilityCoroutine.MoveTo(WaitPoint, "Moving to start position", MovementByType.NavigatorOnly)); }
private async Task <bool> MoveFromEKToKalimdorHorde() { return(await UtilityCoroutine.UseTransport( GameObjectId_Ship_TheThundercaller, _theThundercallerEKLoc, _theThundercallerKalimdorLoc, _theThundercallerEKWaitLoc, _theThundercallerEKBoardLoc, _theThundercallerKalimdorWaitLoc)); }
protected override Composite CreateMainBehavior() { return(new PrioritySelector( // If we're not mounted, nothing to do... new Decorator(ret => !Me.IsMounted() && !Me.IsShapeshifted(), new Action(delegate { BehaviorDone(); })), new ActionRunCoroutine(context => UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.DismountOrCancelShapeshift)) )); }
protected override Composite CreateMainBehavior() { return(new PrioritySelector( // If we don't have a selected target, find one... new Decorator(context => !IsMobQualified(SelectedTarget), new PrioritySelector( new ActionFail(context => { SelectedTarget = FindQualifiedMob(); }), // No qualifed mobs in immediate vicinity... new Decorator(context => !IsMobQualified(SelectedTarget), new PrioritySelector( new Decorator(context => Me.GotTarget, new Action(context => { Me.ClearTarget(); })), // NB: if the terminateBehaviorIfNoTargetsProvider argument evaluates to 'true', calling // this sub-behavior will terminate the overall behavior. new ActionRunCoroutine(context => _noMobsAtCurrentWaypoint ?? (_noMobsAtCurrentWaypoint = new UtilityCoroutine.NoMobsAtCurrentWaypoint( () => HuntingGrounds, () => MovementBy, null, () => { if (!WaitForNpcs) { BehaviorDone("Terminating--\"WaitForNpcs\" is false."); } }, () => TargetExclusionAnalysis.Analyze( Element, () => Query.FindMobsAndFactions(MobIds), TargetExclusionChecks)))))) )), // If qualified mob was found, move within range, if needed... // NB: A mob can lose its 'qualified' status for several reasons. For instance, // another player moves close to or tags the mob while we're on our way to it. new Decorator(context => IsMobQualified(SelectedTarget), new PrioritySelector( new ActionFail(context => { Utility.Target(SelectedTarget); }), new Decorator(context => IsDistanceCloseNeeded(SelectedTarget), new ActionRunCoroutine( context => UtilityCoroutine.MoveTo( SelectedTarget.Location, SelectedTarget.SafeName, MovementBy))), new ActionRunCoroutine(context => CommonCoroutines.StopMoving()), new Action(context => { Utility.Target(SelectedTarget, true); BehaviorDone(); }) )) )); }
private async Task <bool> MainCoroutine() { if (IsDone) { return(false); } if (TookPortal) { if (Me.IsMoving) { await CommonCoroutines.StopMoving(); } await Coroutine.Sleep(_postZoningDelay); BehaviorDone("Zoned into portal"); return(true); } if (Navigator.AtLocation(StartingPoint) && await WaitToRetry()) { return(true); } // Move to portal starting position... if (!Navigator.AtLocation(StartingPoint)) { if (!await UtilityCoroutine.MoveTo(StartingPoint, "Portal", MovementBy)) { QBCLog.Fatal("Unable to Navigate to StartingPoint"); } return(true); } if (await EnterPortal()) { return(true); } // Zoning failed, do we have any retries left? _retryCount += 1; if (_retryCount > MaxRetryCount) { var message = string.Format("Unable to go through portal in {0} attempts.", MaxRetryCount); // NB: Posting a 'fatal' message will stop the bot--which is what we want. QBCLog.Fatal(message); BehaviorDone(message); return(true); } RetryDelayTimer = new Stopwatch(); return(true); }
private async Task <bool> MainCoroutine() { var activeMover = WoWMovement.ActiveMover; if (activeMover == null) { return(false); } var immediateDestination = FindImmediateDestination(); // Arrived at destination? if (AtLocation(activeMover.Location, immediateDestination)) { var completionMessage = string.Format("Arrived at destination '{0}'", RoughDestination.Name); // Land if we need to... // NB: The act of landing may cause us to exceed the ArrivalTolerance specified. if (Land && Me.Mounted) { await UtilityCoroutine.LandAndDismount(string.Format("Landing at destination '{0}'", RoughDestination.Name)); BehaviorDone(completionMessage); return(true); } // Done... BehaviorDone(completionMessage); return(false); } // Do not run FlyTo when there is a PoI set... if (BotPoi.Current.Type != PoiType.None) { await Coroutine.Sleep(TimeSpan.FromSeconds(10)); QBCLog.DeveloperInfo("FlyTo temporarily suspended due to {0}", BotPoi.Current); return(true); } // Move closer to destination... var parameters = new FlyToParameters(immediateDestination) { CheckIndoors = !IgnoreIndoors }; if (MinHeight.HasValue) { parameters.MinHeight = MinHeight.Value; } Flightor.MoveTo(parameters); return(true); }
private async Task <bool> MainCoroutine() { var activeMover = WoWMovement.ActiveMover; if (activeMover == null) { return(false); } var immediateDestination = FindImmediateDestination(); // If we've no way to reach destination, inform user and quit... if (!Flightor.CanFly && !Navigator.CanNavigateWithin(Me.Location, immediateDestination, (float)DefaultArrivalTolerance)) { QBCLog.Fatal("Toon doesn't have flying capability in this area, and there is no ground path to the destination." + " Please learn the flying skill appropriate for this area."); BehaviorDone(); return(false); } // Arrived at destination? if (AtLocation(activeMover.Location, immediateDestination)) { var completionMessage = string.Format("Arrived at destination '{0}'", RoughDestination.Name); // Land if we need to... // NB: The act of landing may cause us to exceed the ArrivalTolerance specified. if (Land && Me.Mounted) { await UtilityCoroutine.LandAndDismount(string.Format("Landing at destination '{0}'", RoughDestination.Name)); BehaviorDone(completionMessage); return(true); } // Done... BehaviorDone(completionMessage); return(false); } // Do not run FlyTo when there is a PoI set... if (BotPoi.Current.Type != PoiType.None) { await Coroutine.Sleep(TimeSpan.FromSeconds(10)); QBCLog.DeveloperInfo("FlyTo temporarily suspended due to {0}", BotPoi.Current); return(true); } // Move closer to destination... Flightor.MoveTo(immediateDestination, !IgnoreIndoors); return(true); }
private Composite CreateActualBehavior() { return(new PrioritySelector( new Decorator( ret => MountType == ForcedMountType.Ground, new ActionRunCoroutine(ret => UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.Mount, Styx.NavType.Run))), new Decorator( ret => MountType == ForcedMountType.Flying, new ActionRunCoroutine(ctx => MountForFlying())) )); }
private async Task <bool> MainLogic() { if (!Me.IsAlive) { return(false); } var bomb = Me.BagItems.FirstOrDefault(i => Query.IsViable(i) && i.Entry == 60849 || i.Entry == 60678); var bunny = ObjectManager.GetObjectsOfType <WoWUnit>() .Where(r => r.Entry == 44360) .OrderBy(r => r.Distance2D) .FirstOrDefault(); //Remove hook once were done with the quest if (bomb == null) { RemoveHook(); return(true); } if (bunny != null) { var bunnyDist = bunny.DistanceSqr; if (bunnyDist < 5 * 5) { bomb.Use(); SpellManager.ClickRemoteLocation(bunny.Location); await Coroutine.Sleep(Delay.AfterItemUse.Milliseconds); return(true); } if (bunnyDist < 35 * 35) { return(await UtilityCoroutine.MoveTo(bunny.Location, "Bunny", MovementByType.NavigatorOnly)); } } var stickbone = ObjectManager.GetObjectsOfType <WoWUnit>() .Where(r => r.Entry == 44329 && r.IsAlive) .OrderBy(r => r.Distance2D) .FirstOrDefault(); if (stickbone != null && stickbone.DistanceSqr < 5 * 5) { bomb.Use(); SpellManager.ClickRemoteLocation(stickbone.Location); await Coroutine.Sleep(Delay.AfterItemUse.Milliseconds); return(true); } return(false); }
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); }
private Composite StateBehaviorPS_MountingVehicle() { return(new PrioritySelector( new Decorator(context => Me.IsQuestComplete(GetQuestId()), new Action(context => { BehaviorDone(string.Format("quest complete")); })), // If we're mounted on something other than the dragon, then dismount... new Decorator(context => Me.Mounted && !Query.IsViable(DragonVehicle), new ActionRunCoroutine(context => UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.Dismount))), // If we're on the dragon, get moving... new Decorator(context => Query.IsViable(DragonVehicle), new PrioritySelector( SubBehaviorPS_InitializeVehicleAbilities(), new Action(context => { BehaviorState = BehaviorStateType.RidingOutToHuntingGrounds; }) )), // If we don't posssess item to summon the dragon, that's fatal... new Decorator(context => { ItemToSummonVehicle = Me.CarriedItems.FirstOrDefault(i => i.Entry == ItemIdToSummonVehicle); return !Query.IsViable(ItemToSummonVehicle); }, new Action(context => { QBCLog.Fatal("Unable to locate ItemId({0}) in inventory.", ItemIdToSummonVehicle); })), // Wait for item to come off cooldown... new Decorator(context => ItemToSummonVehicle.Cooldown > 0, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} cooldown ({1} remaining)", ItemToSummonVehicle.SafeName, Utility.PrettyTime(ItemToSummonVehicle.CooldownTimeLeft)); return RunStatus.Success; })), // Use the item new Decorator(context => !Me.IsCasting, new ActionFail(context => { // If we got booted out of a vehicle for some reason, reset the weapons... Weapon_DevourHuman = null; Weapon_FrozenDeathbolt = null; ItemToSummonVehicle.UseContainerItem(); })) )); }
private async Task <bool> MainLogic() { if (GetOffLocation != Vector3.Zero && Me.Location.DistanceSquared(GetOffLocation) < 2 * 2) { BehaviorDone("Successfully used the transport."); return(true); } if (Me.IsOnTransport || _usedTransport) { if (TransportLocation != Vector3.Zero && TransportLocation.DistanceSquared(EndLocation) < 1.5 * 1.5) { TreeRoot.StatusText = "Moving out of transport"; Navigator.PlayerMover.MoveTowards(GetOffLocation); return(true); } _usedTransport = true; TreeRoot.StatusText = "Waiting for the end location"; return(true); } if (Me.IsMoving) { return(false); } if (TransportLocation != Vector3.Zero && TransportLocation.DistanceSquared(StartLocation) < 1.5 * 1.5 && WaitAtLocation.DistanceSquared(Me.Location) < 2 * 2) { // don't do anything that can cause toon to move off course LevelBot.BehaviorFlags &= ~(BehaviorFlags.Vendor | BehaviorFlags.FlightPath | BehaviorFlags.Combat | BehaviorFlags.Loot); TreeRoot.StatusText = "Moving inside transport"; Navigator.PlayerMover.MoveTowards(StandLocation); return(true); } if (WaitAtLocation.DistanceSquared(Me.Location) > 2 * 2) { await UtilityCoroutine.MoveTo(WaitAtLocation, DestName, MovementBy); return(true); } await CommonCoroutines.LandAndDismount(); TreeRoot.StatusText = "Waiting for transport"; return(true); }
protected override Composite CreateBehavior_CombatOnly() { return(new PrioritySelector(isViableContext => { return IsViableForItemUse(Me.CurrentTarget); }, // If we acquired mob aggro while on the way to our selected target, // deal with the aggro'd mob immediately... new ActionRunCoroutine(context => UtilityCoroutine.PreferAggrodMob()), // Combat with viable mob... new Decorator(isViableContext => (bool)isViableContext, SubBehavior_CombatWithViableMob()), // Combat with non-viable mob... new Decorator(isViableContext => !(bool)isViableContext, SubBehavior_CombatWithNonViableMob()) )); }
private async Task <bool> TurninQuestAndBuyMount( int turninId, WoWPoint turninLoc, uint questId, int vendorId, WoWPoint vendorLocation, int itemId) { // Turnin the 'Learn to Ride' quest if in log if (_profileHelpers.HasQuest(questId)) { return(await UtilityCoroutine.TurninQuest(turninId, turninLoc, questId)); } // buy the mount return(await BuyMount(vendorId, vendorLocation, itemId)); }
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); }
private async Task <bool> MoveFromEKToSilvermoonCityHorde() { var portal = ObjectManager.GetObjectsOfType <WoWGameObject>() .FirstOrDefault(g => g.Entry == GameObjectId_OrbOfTranslocation); if (portal == null || !portal.WithinInteractRange) { return(await(UtilityCoroutine.MoveTo(portal?.Location ?? _silvermoonCityPortalLoc, "Silvermoon City portal"))); } await CommonCoroutines.StopMoving(); portal.Interact(); await Coroutine.Sleep(3000); return(true); }
private Composite PoleCombat() { return(new PrioritySelector( // Pick a target, if we don't have one... new Decorator(context => !IsMonkPersuable(SelectedMonk), new Action(context => { SelectedMonk = FindMonk(); })), // Make certain target stays selected... new Decorator(context => Me.CurrentTarget != SelectedMonk, new ActionFail(context => { SelectedMonk.Target(); })), // If we are within melee range of target, spank it... new Decorator(r => SelectedMonk.IsWithinMeleeRange, new ActionRunCoroutine(context => UtilityCoroutine.MiniCombatRoutine())), // If we are out of range of target, move closer... new Decorator(r => !SelectedMonk.IsWithinMeleeRange, new CompositeThrottle(TimeSpan.FromMilliseconds(500), new Action(delegate { var bestPole = (from pole in FindPoles() where pole.WithinInteractRange orderby pole.Location.DistanceSqr(SelectedMonk.Location) select pole) .FirstOrDefault(); // If we "can't get there from here", then jump own and start over... if (bestPole == null) { Utility.ExitVehicle(); } // Otherwise, move to the next best pole... else { bestPole.Interact(true); // Reset the stuck handler so it doesn't false positive... Navigator.NavigationProvider.StuckHandler.Reset(); } }))) )); }
private Composite StateBehaviorPS_ReturningToBase() { // If we are not returning home... return(new PrioritySelector( new Decorator(context => IsInTank(), new CompositeThrottle(Throttle.UserUpdate, new ActionFail(context => { TreeRoot.StatusText = "Returning to base"; }) )), new Decorator(context => !Navigator.AtLocation(Location_ReturnToSchnottz), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Location_ReturnToSchnottz, "Commander Schnottz", MovementBy))), new Decorator(context => Me.IsQuestComplete(QuestId), new Action(context => BehaviorDone("quest complete"))) )); }
private async Task <bool> BuyMount(int vendorId, WoWPoint vendorLocation, int itemId) { var item = Me.BagItems.FirstOrDefault(i => i.Entry == itemId); if (item == null) { return(await UtilityCoroutine.BuyItem( vendorId, vendorLocation, itemId, 1, noVendorFrameAction : () => QBCLog.Fatal("Npc ({0}) does not offer a vendor frame", vendorId), itemNotFoundAction : () => QBCLog.Fatal("Npc ({0}) does not sell the item with ID: {1}", vendorId, itemId), insufficientFundsAction : () => QBCLog.Fatal("Toon does not have enough funds to buy {0} from {1}", itemId, vendorId))); } item.Use(); _purchasedMountTimer.Reset(); await CommonCoroutines.SleepForRandomUiInteractionTime(); return(true); }
private async Task <bool> MountForFlying() { if (!Flightor.CanFly) { return(false); } await UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.Mount, Styx.NavType.Fly); try { WoWMovement.Move(WoWMovement.MovementDirection.JumpAscend, 500); await Coroutine.Sleep(250); } finally { Navigator.PlayerMover.MoveStop(); } return(true); }
private async Task <bool> PurchaseMount() { // Worgens have a ground mount from racial, paladin and warlock have class based mounts so // they do not need to purchase any ground mounts if (RidingLevel > RidingLevelType.None && Me.Race != WoWRace.Worgen && Me.Class != WoWClass.Paladin && Me.Class != WoWClass.Warlock) { // _purchasedMountTimer pervents double purchasing multiple mounts because Mount.GroundMounts is cached. if (!Mount.GroundMounts.Any() && _purchasedMountTimer.IsFinished) { _purchaseMount = true; return(await PurchaseGroundMount()); } // we need to hearth after purchasing our mount if (_purchaseMount) { var onCooldown = false; await UtilityCoroutine.UseHearthStone( hearthOnCooldownAction : () => onCooldown = true, hearthCastedAction : () => _purchaseMount = false, inHearthAreaAction : () => _purchaseMount = false); if (onCooldown) { TreeRoot.StatusText = "Waiting on Hearthstone cooldown"; return(true); } } } // Druids have flightform so do not need to purchase a flying mount. if (RidingLevel >= RidingLevelType.ExpertRiding && Me.Class != WoWClass.Druid && !Mount.FlyingMounts.Any() && _purchasedMountTimer.IsFinished) { return(await PurchaseFlyingMount()); } return(false); }
// 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. protected override Composite CreateMainBehavior() { return(new PrioritySelector( new Decorator(ret => Counter >= NumOfTimes, new Action(ret => BehaviorDone(string.Format("Object used {0} times.", Counter)))), new Decorator( ret => Location.Distance(StyxWoW.Me.Location) > 2, new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Location, "destination", MovementBy))), new Decorator(ret => StyxWoW.Me.IsMoving, new Action(ret => { Navigator.PlayerMover.MoveStop(); })), new Decorator(ret => TargetNearest, new Sequence( new Action(context => Lua.DoString("TargetNearest()")), new SleepForLagDuration(), new ActionAlwaysFail())), // fall through new Decorator(ret => (Item != null) && (Item.Cooldown <= 0), new Sequence( new Action(ret => { TreeRoot.StatusText = string.Format("Using {0} (count: {1}/{2})", Item.SafeName, Counter, NumOfTimes); Item.UseContainerItem(); Counter++; }), new SleepForLagDuration(), new Sleep(WaitTime))) )); }
private async Task <bool> MainCoroutine() { // break if we are done or we are not in combat and targting is not empty, we want the botbase to clear path for us. if (IsDone || (!Me.Combat && Targeting.Instance.FirstUnit != null) || !Me.IsAlive) { return(false); } if (!Query.IsViable(SelectedNpc)) { SelectedNpc = GetNpc(); } if (!Query.IsViable(SelectedNpc) || !Me.IsActuallyInCombat && Targeting.Instance.FirstUnit == null) { // move to search area if (SearchLocation != Vector3.Zero && !Navigator.AtLocation(SearchLocation)) { await UtilityCoroutine.MoveTo(SearchLocation, "Search Area", MovementBy); } // Dismount after reaching search location. else if ((SearchLocation == Vector3.Zero || Navigator.AtLocation(SearchLocation)) && Me.Mounted) { await UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.Dismount); } else { TreeRoot.StatusText = "Waiting for NPC to spawn"; } return(true); } if (SelectedNpc.IsDead && SelectedNpc.TaggedByMe && !VariantQuestIds.Any()) { BehaviorDone(); return(true); } if (SelectedNpc.HasAura(ImmunityAuraId)) { if (BotPoi.Current.AsObject == SelectedNpc) { BotPoi.Clear("Mob is immune"); } var targetedMob = Targeting.Instance.FirstUnit; if (targetedMob != null && ImmunityBreakingMobIds.Contains((int)targetedMob.Entry)) { if (targetedMob.IsTargetingMeOrPet) { // move close enough to shielded NPC so that the exploding mobs will hit it when killed. var myMinDistance = Math.Max(2, MaxRange - targetedMob.MeleeRange); if (SelectedNpc.DistanceSqr > myMinDistance * myMinDistance) { TreeRoot.StatusText = string.Format("Moving closer to {0} before killing {1}", SelectedNpc.SafeName, targetedMob.SafeName); Navigator.MoveTo(SelectedNpc.Location); return(true); } // wait for exploding mob to get within range of shielded mob. if (targetedMob.Location.DistanceSquared(SelectedNpc.Location) > MaxRange * MaxRange) { TreeRoot.StatusText = string.Format( "Waiting for {0} to move withing range of {1}", targetedMob.SafeName, SelectedNpc.SafeName); return(true); } } } } return(false); }
protected override Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update values for this BT node visit... new Action(context => { VehicleUnoccupied = FindUnoccupiedVehicle(); // Figure out our final destination (i.e., a location or a mob)... // NB: this can change as we travel. If our destination is a mob, // We can't "see" distant mobs until we get within 100 yards or so of them. // Until we close that distance, we'll head towards the provided location. // As soon as we "see" the mob, we'll switch to the mob as the destination. FinalDestination = Destination; FinalDestinationName = "destination"; if (MobIds.Count() > 0) { // If we can see our destination mob, calculate a path to it... var nearestMob = Query.FindMobsAndFactions(MobIds).OrderBy(u => u.Distance).FirstOrDefault() as WoWUnit; if (nearestMob != null) { // Target destination mob as feedback to the user... Utility.Target(nearestMob); FinalDestination = nearestMob.Location; FinalDestinationName = nearestMob.SafeName; } } return RunStatus.Failure; // fall thru }), // Proceed if we're not in combat, or are ignoring it... new Decorator(context => !Me.Combat || IgnoreCombat, new PrioritySelector( // If we were successfully mounted... // and within a few yards of our destination when we were dismounted, we must // assume we were auto-dismounted, and the behavior is complete... new Decorator(context => DidSuccessfullyMount && !IsInVehicle() && (WoWMovement.ActiveMover.Location.Distance(FinalDestination) < 15.0), new Action(context => { BehaviorDone(); })), // Enable combat while not in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) == 0 && !Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags |= BehaviorFlags.Combat)), // Disable combat while in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) != 0 && Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags &= ~BehaviorFlags.Combat)), // If we're not in a vehicle, go fetch one... new Decorator(context => !IsInVehicle() && Query.IsViable(VehicleUnoccupied), new Sequence( new CompositeThrottleContinue( Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0} {1}", VehicleUnoccupied.SafeName, Me.Combat ? "(ignoring combat)" : ""); })), new DecoratorContinue(context => VehicleUnoccupied.WithinInteractRange, new Action(context => { VehicleUnoccupied.Interact(); })), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( VehicleUnoccupied.Location, VehicleUnoccupied.SafeName, MovementBy)) )), // If we can't find a vehicle, terminate if requested... new CompositeThrottle( context => !IsInVehicle() && !Query.IsViable(VehicleUnoccupied), Throttle.UserUpdate, new Action(context => { if (!WaitForVehicle) { BehaviorDone(string.Format("No Vehicle, and WaitForVehicle=\"{0}\"", WaitForVehicle)); } else { TreeRoot.StatusText = "No vehicles in area--waiting for vehicle to become available."; } })), // Move vehicle to destination... new Decorator(context => IsInVehicle(), new PrioritySelector( // If we successfully mounted the vehicle, record the fact... new Decorator(context => !DidSuccessfullyMount, new Action(context => { DidSuccessfullyMount = true; })), new Decorator(context => !Navigator.AtLocation(FinalDestination), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( FinalDestination, FinalDestinationName, MovementBy))), new Decorator(context => WoWMovement.ActiveMover.IsMoving, new Action(context => { WoWMovement.MoveStop(); })), // Arrived at destination, use spell if necessary... // NB: We want to make certain movement is settled before we attempt // to cast spell, so we won't be interrupted. new SleepForLagDuration(), CreateSpellBehavior() )) )), // Squelch combat, if requested... new Decorator(context => IgnoreCombat, new ActionAlwaysSucceed()) ))); }
private async Task <bool> Coroutine_CombatMain() { if (IsDone) { return(false); } if (!Query.IsInVehicle()) { // only move to vehicle if doing nothing else if (!Targeting.Instance.IsEmpty() || BotPoi.Current.Type != PoiType.None) { return(false); } WoWUnit amber = Amber; // Wait for Amber to load in the ObjectMananger. if (amber == null || !amber.WithinInteractRange) { var moveTo = amber != null ? amber.Location : _vehicleLoc; await UtilityCoroutine.MoveTo(moveTo, "Moving to Start Amber(Human) Story", MovementBy); return(true); } if (await CommonCoroutines.StopMoving()) { return(true); } if (!GossipFrame.Instance.IsVisible) { amber.Interact(); await CommonCoroutines.SleepForRandomUiInteractionTime(); return(true); } if (GossipFrame.Instance.GossipOptionEntries != null) { GossipFrame.Instance.SelectGossipOption(0); await CommonCoroutines.SleepForRandomUiInteractionTime(); return(true); } return(true); } if (await InteractWithUnit(HozenEnemy)) { return(true); } if (await InteractWithUnit(OrcEnemy)) { return(true); } if (!Me.HasAura("See Quest Invis 5")) { var turret = Turret; if (TurretLocation.DistanceSqr(Me.Location) > 3 * 3) { await UtilityCoroutine.MoveTo(TurretLocation, "Turret Location", MovementBy); return(true); } if (turret == null) { TreeRoot.StatusText = "Waiting for turret to spawn"; return(true); } if (!turret.WithinInteractRange) { await UtilityCoroutine.MoveTo(TurretLocation, "interact range of turret", MovementBy); return(true); } if (await CommonCoroutines.StopMoving()) { return(true); } QBCLog.Info("Using turret"); Turret.Interact(); return(true); } return(false); }
private async Task <bool> MainCoroutine() { if (IsDone) { return(false); } if (!Query.IsInVehicle()) { return(await UtilityCoroutine.MountVehicle((int)KovokId, _kovokLoc)); } var ct = Me.CurrentTarget; var transport = (WoWUnit)Me.Transport; if (transport == null) { return(false); } if (ct == null) { var newTarget = GetNearestAttacker() ?? GetNearestTarget(); if (newTarget != null) { newTarget.Target(); _targetTimer.Reset(); return(true); } // move to waypoints searching for targets. if (transport.Location.DistanceSqr(_path.Peek()) < 15 * 15) { _path.Dequeue(); } return((await CommonCoroutines.MoveTo(_path.Peek())).IsSuccessful()); } if (ct.IsDead) { Me.ClearTarget(); return(true); } // blacklist target if it's taking too long to kill. if (_targetTimer.IsFinished) { Blacklist.Add(ct, BlacklistFlags.Combat, TimeSpan.FromMinutes(3)); Me.ClearTarget(); } if (transport.Location.DistanceSqr(ct.Location) > 35 * 35) { return((await CommonCoroutines.MoveTo(ct.Location)).IsSuccessful()); } if (!transport.IsSafelyFacing(ct, 40)) { ct.Face(); return(true); } if (transport.IsMoving) { //WoWMovement.MoveStop(); // WoWMovement.MoveStop doesn't seem to work... WoWMovement.ClickToMove(transport.Location); return(true); } var actionButton = ActionBar.Active.Buttons.FirstOrDefault(b => b.Index != 2 && b.CanUse); if (actionButton != null) { actionButton.Use(); await Coroutine.Sleep(Delay.AfterWeaponFire); return(true); } return(false); }
private Composite StateBehaviorPS_MountingVehicle() { return(new PrioritySelector( new Decorator(context => Me.IsQuestComplete(QuestId), new Action(context => { BehaviorDone(); })), // If we're in the vehicle, wait for the ride out to hunting grounds to complete... new Decorator(context => IsInTank(), new PrioritySelector( SubBehaviorPS_InitializeVehicleAbilities(), new Action(context => { BehaviorState = BehaviorStateType.RidingOutToHuntingGrounds; }) )), // If vehicle is in "enter vehicle" animation, wait for the animation to complete... new Decorator(context => FindVehicle_OwnedByMe(MobId_SchnottzSiegeTankInstanced) != null, new PrioritySelector( new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} to become ready.", Utility.GetObjectNameFromId(MobId_SchnottzSiegeTankInstanced)); })), new ActionAlwaysSucceed() )), // Locate a vehicle to mount... new Decorator(context => !Query.IsViable(Vehicle), new PrioritySelector( new Action(context => { Vehicle = Query.FindMobsAndFactions(Utility.ToEnumerable(MobId_SchnottzSiegeTank)) .FirstOrDefault() as WoWUnit; if (Query.IsViable(Vehicle)) { Utility.Target(Vehicle); return RunStatus.Success; } return RunStatus.Failure; // fall through }), // No vehicle found, move to staging area... new Decorator(ctx => !Navigator.AtLocation(Location_VehicleStagingArea), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Location_VehicleStagingArea, "Vehicle Staging Area", MovementBy))), // Wait for vehicle to respawn... new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Waiting for {0} to respawn.", Utility.GetObjectNameFromId(MobId_SchnottzSiegeTank)); })) )), // Move to vehicle and enter... new CompositeThrottle(Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0}", Vehicle.SafeName); })), new Decorator(context => !Vehicle.WithinInteractRange, new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( Vehicle.Location, Vehicle.SafeName, MovementBy))), new Decorator(context => Me.IsMoving, new Action(context => { Navigator.PlayerMover.MoveStop(); })), new Decorator(context => Me.Mounted, new ActionRunCoroutine(context => UtilityCoroutine.ExecuteMountStrategy(MountStrategyType.DismountOrCancelShapeshift))), new ActionFail(context => { // If we got booted out of a vehicle for some reason, reset the weapons... WeaponFireCannon = null; Utility.Target(Vehicle); Vehicle.Interact(); }), new Wait(TimeSpan.FromMilliseconds(10000), context => IsInTank(), new ActionAlwaysSucceed()), new ActionAlwaysSucceed() )); }