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) { _flightTimer.Reset(); this.UpdateGoalText(GetQuestId()); } }
private async Task <bool> Coroutine_CombatMain() { if (!ImmediatelySwitchToHighestPriorityTarget || !_targetSwitchTimer.IsFinished || BotPoi.Current.Type != PoiType.Kill || !Me.Combat || // Let quest bot handle targeting when we don't have any targets. High priority targets will be picked first as they are weighted more in targeting. // Otherwise, there is a race condition happens where we immediately pick a new target when current one dies and we are still in combat for split second. // This was causing the looting etc. to be skipped Me.CurrentTarget == null || Me.CurrentTarget.IsDead) { return(false); } var firstUnit = Targeting.Instance.FirstUnit; if (!Query.IsViable(firstUnit)) { return(false); } if (firstUnit != BotPoi.Current.AsObject) { BotPoi.Current = new BotPoi(firstUnit, PoiType.Kill, QuestOrder.Instance.NavType); QBCLog.Info("Current POI is not the best target. Changing."); _targetSwitchTimer.Reset(); } return(false); }
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) { int waitDuration = WaitTime + StyxWoW.Random.Next(VariantTime); _timer = new Styx.Common.Helpers.WaitTimer(TimeSpan.FromMilliseconds(waitDuration)); _waitTimeAsString = Utility.PrettyTime(_timer.WaitTime); _timer.Reset(); this.UpdateGoalText(GetQuestId(), "Waiting for " + _waitTimeAsString); } }
/// <summary>Waits until a result is available for a spell cast and then retrurn it.</summary> /// <param name="maxTimeoutMs">The maximum timeout in milliseconds.</param> public async Task <SpellCastResult> GetResult(int maxTimeoutMs = 15000) { var timer = new WaitTimer(TimeSpan.FromMilliseconds(StyxWoW.WoWClient.Latency * 2 + 50)); timer.Reset(); var startedCast = false; Func <bool> beganCast = () => { startedCast = startedCast || StyxWoW.Me.IsCasting; return(startedCast); }; await Coroutine.Wait(maxTimeoutMs, () => HasResult || timer.IsFinished && !beganCast()); if (!HasResult && timer.IsFinished && !beganCast()) { return(SpellCastResult.NoCastStarted); } return(Result); }
protected Composite CreateBehavior_Antistuck() { var prevPosition = WoWPoint.Empty; WoWPoint myLoc = WoWPoint.Empty; var moveDirection = WoWMovement.MovementDirection.None; return(new PrioritySelector( new Decorator( ctx => _stuckTimer.IsFinished, new Sequence( ctx => myLoc = WoWMovement.ActiveMover.Location, // checks if stuck new DecoratorContinue( ctx => myLoc.DistanceSqr(prevPosition) < 3 * 3, new Sequence( ctx => moveDirection = GetRandomMovementDirection(), new Action(ctx => QBCLog.Debug("Stuck. Movement Directions: {0}", moveDirection)), new Action(ctx => WoWMovement.Move(moveDirection)), new WaitContinue(2, ctx => false, new ActionAlwaysSucceed()), new Action(ctx => WoWMovement.MoveStop(moveDirection)))), new Action(ctx => prevPosition = myLoc), new Action(ctx => _stuckTimer.Reset()))))); }
public Composite CreateBehavior_KillMantid() { WoWUnit attackTarget = null; WoWUnit yeti = null; WaitTimer leapSmashTimer = WaitTimer.TenSeconds; return(new Decorator(r => !Me.IsQuestComplete(QuestId) && Query.IsInVehicle() && (yeti = Me.CharmedUnit) != null, new PrioritySelector(ctx => attackTarget = GetAttackTarget(), new Decorator(ctx => attackTarget != null, new PrioritySelector( new ActionFail(ctx => _stuckTimer.Reset()), new ActionSetActivity("Moving to Attack"), new Decorator(ctx => Me.CurrentTargetGuid != attackTarget.Guid, new ActionFail(ctx => attackTarget.Target())), new Decorator(ctx => !Me.IsSafelyFacing(attackTarget) || !yeti.IsSafelyFacing(attackTarget), new ActionFail(ctx => attackTarget.Face())), // cast 'Hozen Snack' ability to heal up. new Decorator(ctx => yeti.HealthPercent <= 70, new ActionFail(ctx => Lua.DoString("CastPetAction(4)"))), // cast 'Leap Smash' ability on targets outside of melee new Decorator( ctx => yeti.Location.DistanceSqr(attackTarget.Location) > 30 * 30 && yeti.Location.DistanceSqr(attackTarget.Location) < 90 * 90 && leapSmashTimer.IsFinished, new Sequence( new Action(ctx => Lua.DoString("CastPetAction(1)")), new WaitContinue(2, ctx => StyxWoW.Me.CurrentPendingCursorSpell != null, new ActionAlwaysSucceed()), new Action(ctx => SpellManager.ClickRemoteLocation(attackTarget.Location)), new Action(ctx => leapSmashTimer.Reset()))), // cast 'Headbutt' ability on melee range target. new Decorator( ctx => yeti.Location.DistanceSqr(attackTarget.Location) <= 25 * 25, new PrioritySelector( new Decorator( ctx => yeti.Location.DistanceSqr(attackTarget.Location) <= 25 * 25 && (Me.IsMoving || Me.CharmedUnit.IsMoving), new ActionFail(ctx => WoWMovement.ClickToMove(Me.CharmedUnit.Location))), new Action(ctx => Lua.DoString("CastPetAction(2)")))), new Decorator(ctx => yeti.Location.DistanceSqr(attackTarget.Location) > 25 * 25, new Action(ctx => Navigator.MoveTo(attackTarget.Location))))), new Decorator( ctx => attackTarget == null, new PrioritySelector( new Decorator( ctx => yeti.Location.DistanceSqr(_waitPoint) > 10 * 10, new PrioritySelector( // can't set path precision so I'll just handle it directly... // the yeti takes wide turns so needs a higher path precision than normal new Decorator( ctx => { var nav = Navigator.NavigationProvider as MeshNavigator; if (nav == null) { return false; } if (nav.CurrentMovePath == null || nav.CurrentMovePath.Index >= nav.CurrentMovePath.Path.Points.Length) { return false; } WoWPoint point = nav.CurrentMovePath.Path.Points[nav.CurrentMovePath.Index]; return point.DistanceSqr(yeti.Location) < 6 * 6; }, new Action(ctx => ((MeshNavigator)Navigator.NavigationProvider).CurrentMovePath.Index++)), CreateBehavior_Antistuck(), new Action(ctx => Navigator.MoveTo(_waitPoint)))), new ActionSetActivity("No viable targets, waiting."))), new ActionAlwaysSucceed()))); }
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 async Task <bool> ScareSpiders() { // if not in a turret than move to one and interact with it if (!Query.IsInVehicle()) { var mustang = GetMustang(); if (mustang == null) { QBCLog.Warning("No mustang was found nearby"); return(false); } TreeRoot.StatusText = "Moving To Mustang"; if (mustang.DistanceSqr > 5 * 5) { return((await CommonCoroutines.MoveTo(mustang.Location)).IsSuccessful()); } await CommonCoroutines.LandAndDismount(); QBCLog.Info("Interacting with Mustang"); mustang.Interact(); return(true); } // Find the nearest spider and if none exist then move to the spawn location if (!Query.IsViable(_currentTarget) || !_currentTarget.IsAlive) { _currentTarget = ObjectManager.GetObjectsOfType <WoWUnit>() .Where(u => u.IsAlive && u.Entry == 44284 && !Blacklist.Contains(u, BlacklistFlags.Interact)) .OrderBy(u => u.DistanceSqr).FirstOrDefault(); if (_currentTarget == null) { if (!Navigator.AtLocation(_spiderSpawnLocation)) { return((await CommonCoroutines.MoveTo(_spiderSpawnLocation)).IsSuccessful()); } TreeRoot.StatusText = "Waiting for spiders to spawn"; return(true); } _noMoveBlacklistTimer.Reset(); _blacklistTimer.Reset(); QBCLog.Info("Locked on a new target. Distance {0}", _currentTarget.Distance); } TreeRoot.StatusText = "Scaring spider towards lumber mill"; var moveToPoint = WoWMathHelper.CalculatePointFrom(_lumberMillLocation, _currentTarget.Location, -6); if (moveToPoint.DistanceSqr((WoWMovement.ActiveMover ?? StyxWoW.Me).Location) > 4 * 4) { return((await CommonCoroutines.MoveTo(moveToPoint)).IsSuccessful()); } // spider not moving? blacklist and find a new target. if (_noMoveBlacklistTimer.ElapsedMilliseconds > 20000 && _currentTarget.Location.DistanceSqr(_spiderScareLoc) < 10 * 10) { Blacklist.Add(_currentTarget, BlacklistFlags.Interact, TimeSpan.FromMinutes(3), "Spider is not moving"); _currentTarget = null; } else if (_blacklistTimer.IsFinished) { Blacklist.Add(_currentTarget, BlacklistFlags.Interact, TimeSpan.FromMinutes(3), "Took too long"); _currentTarget = null; } else if (!_currentTarget.HasAura("Fear")) { await CommonCoroutines.StopMoving(); Me.SetFacing(_lumberMillLocation); await CommonCoroutines.SleepForLagDuration(); await Coroutine.Sleep(200); if (!_noMoveBlacklistTimer.IsRunning || _currentTarget.Location.DistanceSqr(_spiderScareLoc) >= 10 * 10) { _noMoveBlacklistTimer.Restart(); _spiderScareLoc = _currentTarget.Location; } Lua.DoString("CastSpellByID(83605)"); await Coroutine.Wait(3000, () => Query.IsViable(_currentTarget) && _currentTarget.HasAura("Fear")); } return(true); }
public Composite CreateBehavior_KillMantid() { WoWUnit attackTarget = null; WoWUnit IronShredder = null; WaitTimer DeathFromAboveTimer = WaitTimer.TenSeconds; return(new Decorator(r => !Me.IsQuestComplete(QuestId) && Query.IsInVehicle() && (IronShredder = Me.CharmedUnit) != null, new PrioritySelector(ctx => attackTarget = GetAttackTarget(), new Decorator(ctx => attackTarget != null, new PrioritySelector( new ActionSetActivity("Moving to Attack"), new Decorator(ctx => Me.CurrentTargetGuid != attackTarget.Guid, new ActionFail(ctx => attackTarget.Target())), new Decorator(ctx => !Me.IsSafelyFacing(attackTarget) || !IronShredder.IsSafelyFacing(attackTarget), new ActionFail(ctx => attackTarget.Face())), // cast 'Death From Above' ability on targets outside of melee new Decorator( ctx => IronShredder.Location.DistanceSquared(attackTarget.Location) > 10 * 10 && IronShredder.Location.DistanceSquared(attackTarget.Location) < 70 * 70 && DeathFromAboveTimer.IsFinished, new Sequence( new Action(ctx => Lua.DoString("CastPetAction(2)")), new WaitContinue(2, ctx => StyxWoW.Me.CurrentPendingCursorSpell != null, new ActionAlwaysSucceed()), new Action(ctx => SpellManager.ClickRemoteLocation(attackTarget.Location)), new Action(ctx => DeathFromAboveTimer.Reset()))), // cast 'Elecrostatic Distortion' ability on melee range target. new Decorator( ctx => IronShredder.Location.DistanceSquared(attackTarget.Location) <= 25 * 25, new PrioritySelector( new Decorator( ctx => IronShredder.Location.DistanceSquared(attackTarget.Location) <= 25 * 25 && (Me.IsMoving || Me.CharmedUnit.IsMoving), new ActionFail(ctx => WoWMovement.ClickToMove(Me.CharmedUnit.Location))), new Action(ctx => Lua.DoString("CastPetAction(1)")))), new Decorator(ctx => IronShredder.Location.DistanceSquared(attackTarget.Location) > 25 * 25, new Action(ctx => Navigator.MoveTo(attackTarget.Location))))), new Decorator( ctx => attackTarget == null, new PrioritySelector( new Decorator( ctx => IronShredder.Location.DistanceSquared(_waitPoint) > 10 * 10, new PrioritySelector( new Action(ctx => Navigator.MoveTo(_waitPoint)))), new ActionSetActivity("No viable targets, waiting."))), new ActionAlwaysSucceed()))); }
public Composite CreateBehavior_KillGnomereganStealthFighter() { WoWUnit attackTarget = null; WoWUnit PrideofKezan = null; WaitTimer WildWeaselRocketsTimer = WaitTimer.FiveSeconds; return(new Decorator(r => !Me.IsQuestComplete(QuestId) && Query.IsInVehicle() && (PrideofKezan = Me.CharmedUnit) != null, new PrioritySelector(ctx => attackTarget = GetAttackTarget(), new Decorator(ctx => attackTarget != null, new PrioritySelector( new ActionSetActivity("Moving to Attack"), new Decorator(ctx => Me.CurrentTargetGuid != attackTarget.Guid, new ActionFail(ctx => attackTarget.Target())), new Decorator(ctx => !Me.IsSafelyFacing(attackTarget) || !PrideofKezan.IsSafelyFacing(attackTarget), new ActionFail(ctx => attackTarget.Face())), // cast 'Wild Weasel Rockets' ability new Decorator( ctx => PrideofKezan.Location.DistanceSqr(attackTarget.Location) < 25 * 25 && WildWeaselRocketsTimer.IsFinished, new Sequence( new Action(ctx => Lua.DoString("CastPetAction(2)")), new Action(ctx => WildWeaselRocketsTimer.Reset()))), // cast 'Machine Gun' ability new Decorator( ctx => PrideofKezan.Location.DistanceSqr(attackTarget.Location) <= 25 * 25, new Sequence( new Action(ctx => Lua.DoString("CastPetAction(1)")))), new Decorator(ctx => PrideofKezan.Location.DistanceSqr(attackTarget.Location) > 25 * 25, new Action(ctx => WoWMovement.ClickToMove(attackTarget.Location))))), new Decorator( ctx => attackTarget == null, new PrioritySelector( new Decorator( ctx => PrideofKezan.Location.DistanceSqr(_waitPoint) > 10 * 10, new Sequence( new Action(ctx => WoWMovement.ClickToMove(_waitPoint)))), new ActionSetActivity("No viable targets, waiting."))), new ActionAlwaysSucceed()))); }
private async Task TargetLogic(WoWUnit target) { if (!Query.IsViable(target)) { return; } var targetDistSqr = target.Location.DistanceSquared(Vehicle.Location); if (PickUpPassengerButton == 0) { TreeRoot.StatusText = string.Format("Blowing stuff up. {0} mins before resummon is required", _flightTimer.TimeLeft.TotalMinutes); if (HealButton > 0 && targetDistSqr < 60 * 60 && (Vehicle.HealthPercent <= HealPercent || Vehicle.ManaPercent <= HealPercent) && UseVehicleButton(HealButton)) { QBCLog.Info("Used heal button {0} on NPC:{1}", HealButton, target.SafeName); return; } // return when a button is used. foreach (var button in Buttons) { if (UseVehicleButton(button)) { return; } } return; } TreeRoot.StatusText = string.Format("Rescuing {0}", target.SafeName); var pickTimer = new WaitTimer(TimeSpan.FromSeconds(20)); pickTimer.Reset(); while (target.IsValid && target.IsAlive && !UnitIsRidingMyVehicle(target) && Query.IsInVehicle() && !pickTimer.IsFinished) { Vector3 clickLocation = target.Location.RayCast(target.Rotation, 6); clickLocation.Z += 3; if (Vehicle.Location.DistanceSquared(clickLocation) > 3 * 3) { Stopwatch timer = Stopwatch.StartNew(); do { Flightor.MoveTo(clickLocation); await Coroutine.Yield(); } while (timer.ElapsedMilliseconds < 1000 && Vehicle.Location.DistanceSquared(clickLocation) > 3 * 3); } else { if (Vehicle.IsMoving) { await CommonCoroutines.StopMoving(string.Format("Picking up {0}", target.SafeName)); } UseVehicleButton(PickUpPassengerButton); if (await Coroutine.Wait(4000, () => UnitIsRidingMyVehicle(target))) { QBCLog.Info("Successfully picked up passenger {0}", target.SafeName); return; } QBCLog.Info("Failed to picked up passenger {0}", target.SafeName); await Coroutine.Yield(); } } }