private async static Task <bool> PoolSafetyChecks(WoWGameObject pool) { if (pool == null || !pool.IsValid) { BotPoi.Clear(); return(true); } if (pool.Guid != _lastVisitedPoolGuid) { _lastVisitedPoolGuid = pool.Guid; TimeAtPoolTimer.Restart(); } // safety check. if spending more than 5 mins at pool than black list it. if (TimeAtPoolTimer.ElapsedMilliseconds >= AutoAnglerSettings.Instance.MaxTimeAtPool * 60000) { Utility.BlacklistPool(pool, TimeSpan.FromMinutes(10), "Spend too much time at pool"); return(true); } // move to another spot if we have too many failed casts if (_castCounter >= AutoAnglerSettings.Instance.MaxFailedCasts) { AutoAnglerBot.Log("Moving to a new fishing location since we have {0} failed casts", _castCounter); _castCounter = 0; RemovePointAtTop(pool); return(true); } return(false); }
public static async Task <bool> HandleCombat() { if (!Me.IsFlying && Me.IsActuallyInCombat) { var mainHand = Me.Inventory.Equipped.MainHand; if ((mainHand == null || mainHand.Entry != AutoAnglerSettings.Instance.MainHand) && Utility.EquipWeapons()) { return(true); } if (await CombatBehavior.ExecuteCoroutine()) { return(true); } } if (BotPoi.Current.Type == PoiType.Kill) { var unit = BotPoi.Current.AsObject as WoWUnit; if (unit == null) { BotPoi.Clear("Target not found"); } else if (unit.IsDead) { BotPoi.Clear("Target is dead"); } } return(false); }
public static void Clear() { if (BotPoi.Current.Type == PoiType.Loot) { BotPoi.Clear(); lastguid = 0; } }
// 2Sep2013 chinajade public static bool IsPoiIdle(BotPoi poi) { if (poi == null) { return(false); } return(s_idlePoiTypes.Contains(poi.Type)); }
// 24Feb2013-08:10UTC chinajade public override void OnFinished() { // Defend against being called multiple times (just in case)... if (!IsOnFinishedRun) { if (Targeting.Instance != null) { Targeting.Instance.IncludeTargetsFilter -= TargetFilter_IncludeTargets; Targeting.Instance.RemoveTargetsFilter -= TargetFilter_RemoveTargets; Targeting.Instance.WeighTargetsFilter -= TargetFilter_WeighTargets; } // NB: we don't unhook _behaviorTreeHook_Main // This was installed when HB created the behavior, and its up to HB to unhook it BehaviorHookRemove("Combat_Main", ref _behaviorTreeHook_CombatMain); BehaviorHookRemove("Combat_Only", ref _behaviorTreeHook_CombatOnly); BehaviorHookRemove("Death_Main", ref _behaviorTreeHook_DeathMain); BehaviorHookRemove("Questbot_Main", ref _behaviorTreeHook_QuestbotMain); // Remove temporary blackspots... if (_temporaryBlackspots != null) { BlackspotManager.RemoveBlackspots(_temporaryBlackspots.GetBlackspots()); _temporaryBlackspots = null; } // Restore configuration... if (_configMemento != null) { _configMemento.Dispose(); _configMemento = null; } // Make sure we don't leave stale POIs set after finishing a QB. // This could happen if the user used a TerminateWhen to finish it // for example. BotPoi.Clear("Finished " + GetType().Name); TreeRoot.GoalText = string.Empty; TreeRoot.StatusText = string.Empty; // Report the behavior run time... if (_behaviorRunTimer.IsRunning) { _behaviorRunTimer.Stop(); QBCLog.DeveloperInfo("Behavior completed in {0}", Utility.PrettyTime(_behaviorRunTimer.Elapsed)); } base.OnFinished(); QBCLog.BehaviorLoggingContext = null; IsOnFinishedRun = true; } }
public static void MoveTo(WoWPoint point) { if (BotPoi.Current.Type != PoiType.None) { BotPoi.Clear(); } if (!ObjectManager.Me.Mounted && Mount.ShouldMount(point) && Mount.CanMount()) { Mount.MountUp(); } _lastPoint = point; _lastMove = DateTime.Now; Navigator.MoveTo(point); }
private void HandleCombatLog(object sender, LuaEventArgs args) { var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); //Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != Me.Guid) { return; } // reset target of current spell since complete CastingSpellTarget = null; // Update the last spell we cast. So certain classes can 'switch' their logic around. LastSpellCast = e.SpellName; Logger.WriteDebug("Successfully cast " + LastSpellCast); if (_sleepAfterSuccessSpells.Contains(e.SpellName)) { StyxWoW.SleepForLagDuration(); } // Force a wait for all summoned minions. This prevents double-casting it. if (myClass == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) { StyxWoW.SleepForLagDuration(); } break; case "SPELL_MISSED": //Logger.Write(e.Args.ToRealString()); if (e.Args[11].ToString() == "EVADE") { Logger.Write("Mob is evading. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } break; } }
public static async Task <bool> MailItems() { WoWPoint mboxLoc = BotPoi.Current.Location; var mailbox = ObjectManager.GetObjectsOfType <WoWGameObject>(). FirstOrDefault( m => m.SubType == WoWGameObjectType.Mailbox && m.Location.Distance(mboxLoc) < 10); if (mailbox == null) { if (Me.Location.DistanceSqr(BotPoi.Current.Location) > 4 * 4) { Flightor.MoveTo(BotPoi.Current.Location); return(true); } var profile = ProfileManager.CurrentOuterProfile; if (profile != null) { profile.MailboxManager.Blacklist.Add(BotPoi.Current.AsMailbox); } BotPoi.Clear(string.Format("Unable to find mailbox @ {0}", BotPoi.Current.Location)); return(false); } if (!mailbox.WithinInteractRange) { return(await FlyTo(BotPoi.Current.Location)); } if (!mailbox.WithinInteractRange) { return(await FlyTo(mailbox.Location, mailbox.SafeName)); } if (!MailFrame.Instance.IsVisible) { mailbox.Interact(); await CommonCoroutines.SleepForLagDuration(); return(true); } await Vendors.MailAllItemsCoroutine(); Vendor ven = ProfileManager.CurrentOuterProfile.VendorManager.GetClosestVendor(); BotPoi.Current = ven != null ? new BotPoi(ven, PoiType.Repair) : new BotPoi(PoiType.None); return(true); }
//protected override Composite CreateBehavior_CombatMain() //{ // return new PrioritySelector( // new Decorator(context => (State_MainBehavior == StateType_MainBehavior.PathIngressing) // || (State_MainBehavior == StateType_MainBehavior.PathRetreating), // CreateBehavior()) // ); //} protected override Composite CreateBehavior_CombatOnly() { return(new PrioritySelector( // NB: Since we highlight the target we're watching while we're waiting... // If we get into combat, we don't want Honorbuddy running off to chase the currently highlighted // target (its usually an elite). So, if the selected target not attacking us, we clear the target, // so Honorbuddy can make a proper target selection. new Decorator(context => Me.GotTarget && !Me.CurrentTarget.IsTargetingMeOrPet, new Action(context => { BotPoi.Clear(); Me.ClearTarget(); })) )); }
public static void MoveTo(WoWPoint point) { if (BotPoi.Current.Type != PoiType.None) { BotPoi.Clear(); } if (CharacterSettings.Instance.UseMount && !StyxWoW.Me.Mounted && Mount.CanMount() && Mount.ShouldMount(point)) { Mount.MountUp(() => point); } _lastPoint = point; _lastMove = DateTime.Now; Navigator.MoveTo(point); }
public static void MoveTo(WoWPoint point) { if (BotPoi.Current.Type != PoiType.None) { BotPoi.Clear(); } if (!ObjectManager.Me.Mounted && Mount.ShouldMount(point) && Mount.CanMount()) { Mount.MountUp(); } TreeRoot.StatusText = string.Format("PB: Moving to {0}", point); _lastPoint = point; _lastMove = DateTime.Now; Navigator.MoveTo(point); }
private static void CombatLogEventHander(object sender, LuaEventArgs args) { foreach (object arg in args.Args) { if (arg is String) { var s = (string)arg; if (s.ToUpper() == "EVADE" || s.ToUpper() == "ENTKOMMEN") { if (!AmplifySettings.Instance.MoveDisable) { if (StyxWoW.Me.GotTarget && !IsBattleGround()) { if (LastTarget == null || Me.CurrentTarget.Guid != LastTarget) //Meaning they are not the same. { LastTarget = Me.CurrentTarget.Guid; // set guid to current target. EvadeCount = 1; //it didnt match last target and already evaded once. Logging.Write("Target Evaded {0} Times", EvadeCount.ToString()); } else { EvadeCount++; Logging.Write("Target Evaded {0} Times", EvadeCount.ToString()); if (EvadeCount >= 3) { Logging.Write("Target Evaded {0} Times", EvadeCount.ToString()); Logging.Write("Target is Evade bugged."); Logging.Write("Blacklisting for 3 hours"); Blacklist.Add(StyxWoW.Me.CurrentTargetGuid, TimeSpan.FromHours(3)); StyxWoW.Me.ClearTarget(); BotPoi.Clear(); } } } else if (StyxWoW.Me.GotTarget && (IsBattleGround() || !Me.IsInInstance)) { Logging.Write("My target is Evade bugged."); Logging.Write("Blacklisting for 1 Minute"); Blacklist.Add(StyxWoW.Me.CurrentTargetGuid, TimeSpan.FromMinutes(1)); StyxWoW.Me.ClearTarget(); BotPoi.Clear(); } } } } } }
protected override Composite CreateBehavior_CombatMain() { return(new Decorator(context => IsViableForItemUse(SelectedTarget), new PrioritySelector( // If the target has the Item's Aura... new Decorator(context => SelectedTarget.HasAura(ItemAppliesAuraId), new PrioritySelector( // Count our success if no associated quest... new Decorator(context => QuestId == 0, new Action(context => { ++Counter; })), // Wait additional time requested by profile writer... new Wait(TimeSpan.FromMilliseconds(WaitTimeAfterItemUse), context => false, new ActionAlwaysSucceed()), new Action(context => { // If we can only use the item once per target, blacklist this target from subsequent selection... if ((UseItemStrategy == UseItemStrategyType.UseItemOncePerTarget) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)) { BlacklistForInteracting(SelectedTarget, TimeSpan.FromSeconds(180)); } // If we can't defend ourselves from the target, blacklist it for combat and move on... if ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)) { Blacklist.Add(SelectedTarget, BlacklistFlags.Combat, TimeSpan.FromSeconds(180)); BotPoi.Clear(); Me.ClearTarget(); SelectedTarget = null; } }) )), // If any mob aggros on us while are heading to deal with SelectedTarget, finish aggro mob first... // NB: We don't want to wait until the mob hits us and we get in combat; // otherwise, we may wind up at our target with multiple mobs to fight. UtilityBehaviorPS_SpankMobTargetingUs() ) )); }
// 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() { // 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) { const float defaultArrivalToleranceMin = 1; // Make certain ArrivalTolerance is coherent with Navigator.PathPrecision... if (DefaultArrivalTolerance < defaultArrivalToleranceMin) { QBCLog.DeveloperInfo("ArrivalTolerance({0:F1}) is less than Minimum({1:F1})." + " Setting ArrivalTolerance to be minimum to prevent navigational issues.", DefaultArrivalTolerance, defaultArrivalToleranceMin); DefaultArrivalTolerance = defaultArrivalToleranceMin; } // Disable any settings that may cause us to dismount -- // When we mount for travel via FlyTo, we don't want to be distracted by other things. // NOTE: the ConfigMemento in QuestBehaviorBase restores these settings to their // normal values when OnFinished() is called. LevelBot.BehaviorFlags &= ~(BehaviorFlags.Loot | BehaviorFlags.Pull); // Clear any existing POI (after we've disabled Pull/Loot behaviors)... // Otherwise, FlyTo can get stuck trying to pursue the previous POI, if one was // set immediately before the behavior was launched. This is a boundary condition, // and it happens frequently enough to be really annoying. BotPoi.Clear(); // Pick our destination proper... PotentialDestinations.WaypointVisitStrategy = HuntingGroundsType.WaypointVisitStrategyType.PickOneAtRandom; RoughDestination = PotentialDestinations.CurrentWaypoint(); var actionDescription = $"Flying to '{RoughDestination.Name}' ({RoughDestination.Location})"; this.UpdateGoalText(GetQuestId(), actionDescription); TreeRoot.StatusText = actionDescription; } }
private static void UIErrorEventHander(object sender, LuaEventArgs args) { string Error = args.Args[0].ToString(); if (Error == "Target not in line of sight" || Error == "Ziel ist nicht im Sichtfeld") { if (!AmplifySettings.Instance.MoveDisable && Me.CurrentTarget != null && Navigator.CanNavigateFully(Me.Location, Me.CurrentTarget.Location)) { Logging.Write("Target not in Line of Sight to {0} Blacklisting for 10 sec to allow Repositioning. ", Me.CurrentTarget.Name); Blacklist.Add(StyxWoW.Me.CurrentTargetGuid, TimeSpan.FromSeconds(10)); StyxWoW.Me.ClearTarget(); BotPoi.Clear(); } if (!AmplifySettings.Instance.MoveDisable && Me.CurrentTarget != null && !Navigator.CanNavigateFully(Me.Location, Me.CurrentTarget.Location)) { Logging.Write("Cant Navigate to {0} Blacklisting for 3min", Me.CurrentTarget.Name); Blacklist.Add(StyxWoW.Me.CurrentTargetGuid, TimeSpan.FromMinutes(3)); StyxWoW.Me.ClearTarget(); BotPoi.Clear(); } } }
public static void RepairFly() { if (Flightor.MountHelper.CanMount && !_iGotThis) { _iGotThis = true; _currentPOI = BotPoi.Current; BotPoi.Clear(); _oldLoc = _me.Location; Log("Vendor/repair run discovered, attempting to fly"); var _safeSpot = findSafeFlightPoint(_currentPOI.Location); if (_safeSpot.Equals(_currentPOI.Location)) { flyTo(_currentPOI.Location); } else { performSafeFlight(_safeSpot, _currentPOI.Location); } _currentPOI.AsObject.Interact(); StyxWoW.SleepForLagDuration(); Thread.Sleep(1000); Vendors.RepairAllItems(); Thread.Sleep(1000); Vendors.SellAllItems(); Thread.Sleep(1000); Log("Vendor visited, flying back!"); var _safeSpotBack = findSafeFlightPoint(_oldLoc); if (_safeSpotBack.Equals(_oldLoc)) { flyTo(_oldLoc); } else { performSafeFlight(_safeSpotBack, _oldLoc); } Log("Back where we started (hopefully), thank you for flying with Crafty Airlines!"); _iGotThis = false; } }
public override void Pulse() { try { if (Battlegrounds.IsInsideBattleground && Me.ZoneId != 4384) { ObjectManager.Update(); BGTimer.Start(); combatTimerBG.Start(); } if (!Battlegrounds.IsInsideBattleground) { combatTimerBG.Reset(); BGTimer.Reset(); SotaTimer.Reset(); Sotamsg.Reset(); } if (combatTimerBG.Elapsed.TotalSeconds > 90 && combatTimerBG.Elapsed.TotalSeconds < 92) { Logging.Write(Color.Red, "[BGHelper] - BG Mode Running - Starting NoW!"); //combatTimerBG.Stop(); //BGTimer.Reset(); //BGTimer.Stop(); } while (BGTimer.Elapsed.TotalSeconds > EnterTimeout && Battlegrounds.IsInsideBattleground && combatTimerBG.Elapsed.TotalSeconds < settings.BgTimeout && Me.ZoneId != 4384) { //combatTimer.Reset(); //BGTimer.Stop(); BotPoi.Clear(); //Thread.Sleep(110000); antispam.Start(); if (antispam.Elapsed.TotalSeconds > 20) { PlaySound("Enter.wav"); Logging.Write(Color.Red, "[BGHelper] - BG Detected - Wait Routine Running"); antispam.Reset(); } } // SOTA while (Me.HasAura("Preparation") && Battlegrounds.IsInsideBattleground && Me.ZoneId == 4384) { //combatTimer.Reset(); //BGTimer.Stop(); BotPoi.Clear(); //Thread.Sleep(110000); antispam.Start(); if (antispam.Elapsed.TotalSeconds > 20) { PlaySound("Enter.wav"); Logging.Write(Color.Red, "[BGHelper] - We are in Sota - Wait Till BG Starts"); antispam.Reset(); } } if (!Me.HasAura("Preparation") && Battlegrounds.IsInsideBattleground && Me.ZoneId == 4384) { Sotamsg.Start(); if (Sotamsg.Elapsed.TotalSeconds < 3) { Logging.Write(Color.Red, "[BGHelper] - Sota Running - Enjoy Botting!"); } } } catch (Exception e) { Log("ERROR: " + e.Message + ". See debug log."); Logging.WriteDebug("exception:"); Logging.WriteException(e); } }
public static void BlacklistPool(WoWGameObject pool, TimeSpan time, string reason) { Blacklist.Add(pool.Guid, BlacklistFlags.Node, time, reason); BotPoi.Clear(reason); }
private static void HandleCombatLog(object sender, LuaEventArgs args) { var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Logger.WriteDebug("[CombatLog] " + e.Event + " - " + e.SourceName + " - " + e.SpellName); switch (e.Event) { default: Logger.WriteDebug("[CombatLog] filter out this event -- " + e.Event + " - " + e.SourceName + " - " + e.SpellName); break; case "SPELL_CAST_FAILED": if (SingularSettings.Instance.EnableDebugLogging) { Logger.WriteDebug("[CombatLog] {0}:{1} cast of {2}#{3} failed: '{4}'", e.SourceName, e.SourceGuid, e.SpellName, e.SpellId, e.Args[14] ); } break; case "SPELL_AURA_APPLIED": case "SPELL_CAST_SUCCESS": if (e.SourceGuid != StyxWoW.Me.Guid) { return; } // Update the last spell we cast. So certain classes can 'switch' their logic around. Spell.LastSpellCast = e.SpellName; //Logger.WriteDebug("Successfully cast " + Spell.LastSpellCast); // Force a wait for all summoned minions. This prevents double-casting it. if (StyxWoW.Me.Class == WoWClass.Warlock && e.SpellName.StartsWith("Summon ")) { StyxWoW.SleepForLagDuration(); } break; case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { Logger.Write("Mob is evading swing. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; case "SPELL_MISSED": case "RANGE_MISSED": // DoT casting spam can occur when running on test dummy with low +hit // .. and multiple misses occurring. this should help troubleshoot // .. false reports of flawed rotation if (SingularSettings.Instance.EnableDebugLogging) { Logger.WriteFile( "[CombatLog] {0} {1}#{2} {3}", e.Event, e.SpellName, e.SpellId, e.Args[14] ); } if (e.Args[14].ToString() == "EVADE") { Logger.Write("Mob is evading ranged attack. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { Logger.WriteDebug("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; } }
private static void HandleEvadeBuggedMob(LuaEventArgs args, CombatLogEventArgs e) { WoWUnit unit = e.DestUnit; ulong guid = e.DestGuid; if (unit == null && StyxWoW.Me.CurrentTarget != null) { unit = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; Logging.Write("Evade: bugged mob guid:{0}, so assuming current target instead", args.Args[7]); } if (unit != null) { if (!MobsThatEvaded.ContainsKey(unit.Guid)) { MobsThatEvaded.Add(unit.Guid, 0); } MobsThatEvaded[unit.Guid]++; if (MobsThatEvaded[unit.Guid] <= 5) { Logging.Write("Mob {0} has evaded {1} times. Keeping an eye on {2:X0} for now!", unit.Name, MobsThatEvaded[unit.Guid], unit.Guid); } else { const int secondsToBlacklist = 10; if (Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logging.Write(Colors.LightGoldenrodYellow, "Mob {0} has evaded {1} times. Previously blacklisted {2:X0} for {3} seconds!", unit.Name, MobsThatEvaded[unit.Guid], unit.Guid, secondsToBlacklist); } else { Logging.Write(Colors.LightGoldenrodYellow, "Mob {0} has evaded {1} times. Blacklisting {2:X0} for {3} seconds!", unit.Name, MobsThatEvaded[unit.Guid], unit.Guid, secondsToBlacklist); Blacklist.Add(unit.Guid, BlacklistFlags.Combat, TimeSpan.FromSeconds(secondsToBlacklist)); if (!Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logging.Write(Colors.Pink, "error: blacklist does not contain entry for {0} so adding {1}", unit.Name, unit.Guid); } } if (BotPoi.Current.Guid == unit.Guid) { Logging.Write("EvadeHandling: Current BotPOI type={0} is Evading, clearing now...", BotPoi.Current.Type); BotPoi.Clear("Singular recognized Evade bugged mob"); } if (StyxWoW.Me.CurrentTargetGuid == guid) { foreach (var target in Targeting.Instance.TargetList) { if (target.IsAlive && Classname.ValidUnit(target) && !Blacklist.Contains(target, BlacklistFlags.Combat)) { Logging.Write(Colors.Pink, "Setting target to {0} to get off evade bugged mob!", target.Name); target.Target(); return; } } Logging.Write(Colors.Pink, "BotBase has 0 entries in Target list not blacklisted -- nothing else we can do at this point!"); // StyxWoW.Me.ClearTarget(); } } } /// line below was originally in Evade logic, but commenting to avoid Sleeps // StyxWoW.SleepForLagDuration(); }
/// <summary> /// This behavior SHOULD be called at top of the combat behavior. This behavior won't let the rest of the combat behavior to be called /// if you don't have a target. Also it will find a proper target, if the current target is dead or you don't have a target and still in combat. /// Tank targeting is also dealed in this behavior. /// </summary> /// <returns></returns> public static Composite EnsureTarget() { return (new Decorator( ret => !SingularSettings.DisableAllTargeting, new PrioritySelector( #region Switch from Current Target if a more important one exists! new PrioritySelector( #region Validate our CurrentTarget - ctx set to null if we need a new one, non-null if ok! ctx => { #region Tank Targeting // Handle tank targeting - only if in Combat, otherwise we'll choose based upon Targeting list if (TankManager.NeedTankTargeting && !SingularSettings.Instance.DisableTankTargetSwitching && Group.MeIsTank && StyxWoW.Me.Combat && TankManager.Instance.FirstUnit != null) { if (Me.CurrentTarget != TankManager.Instance.FirstUnit) { if (TankManager.TargetingTimer.IsFinished) { Logger.Write(targetColor, "TankTarget: switching to first unit of TankTargeting"); return TankManager.Instance.FirstUnit; } if (!Unit.ValidUnit(Me.CurrentTarget, showReason: false)) { Logger.Write(targetColor, "TankTarget: CurrentTarget invalid, switching to first unit of TankTargeting"); return TankManager.Instance.FirstUnit; } } return Me.CurrentTarget; // pass our currenttarget to skip setting or switching } #endregion #region WORLD_PVP_FIRST_AND_FOREMOST if (SingularRoutine.CurrentWoWContext == WoWContext.Normal && SingularSettings.Instance.TargetWorldPvpRegardless) { // if on an enemy player, stay there if (Me.GotTarget() && Me.CurrentTarget.IsPlayer && Unit.ValidUnit(Me.CurrentTarget)) { return Me.CurrentTarget; } // if attacked in last 15 seconds, go after them if (EventHandlers.TimeSinceAttackedByEnemyPlayer.TotalSeconds < 15) { WoWUnit ganker = EventHandlers.AttackingEnemyPlayer; if (Unit.ValidUnit(ganker)) { if (!Me.GotTarget() || !Me.CurrentTarget.IsPlayer || !Unit.ValidUnit(Me.CurrentTarget)) { if (ganker != Me.CurrentTarget) { Logger.Write(targetColor, "Switching to Ganker: " + ganker.SafeName() + " who attacked us first!"); Logger.WriteDebug("Setting BotPoi to Kill {0}", ganker.SafeName()); BotPoi.Current = new BotPoi(ganker, PoiType.Kill); } return ganker; } } } } #endregion #region TOTEM KILLER if (SingularRoutine.CurrentWoWContext == WoWContext.Normal && SingularSettings.Instance.TargetCurrentTargetTotems) { if (Me.GotTarget() && !Me.CurrentTarget.IsPlayer && Unit.ValidUnit(Me.CurrentTarget)) { if (Me.CurrentTarget.IsTotem) { if (Me.CurrentTarget.SummonedByUnit != null && !Me.CurrentTarget.SummonedByUnit.IsPlayer) { return Me.CurrentTarget; } } else if ((DateTime.UtcNow - timePrevTotem).TotalSeconds > 15) { float range = Me.IsMelee() ? 15 : 39; WoWUnit totem = ObjectManager.GetObjectsOfType <WoWUnit>(false, false) .FirstOrDefault(t => t.IsTotem && guidPrevTotem != t.Guid && t.SummonedByUnitGuid == Me.CurrentTargetGuid && Unit.ValidUnit(t) && t.SpellDistance() < range); if (totem != null) { guidPrevTotem = totem.Guid; timePrevTotem = DateTime.UtcNow; Logger.Write(targetColor, "Switching to Totem: {0} set by {1}", totem.Name, totem.SummonedUnit.SafeName()); return totem; } } } } #endregion #if ALWAYS_SWITCH_TO_BOTPOI WoWUnit unit; // Check botpoi (our top priority.) we switch to BotPoi if a kill type exists and not blacklisted // .. if blacklisted, clear the poi to give bot a chance to do something smarter // .. if we are already fighting it, we keep fighting it, end of story if (BotPoi.Current.Type == PoiType.Kill) { if (BotPoi.Current.AsObject == null) { Logger.Write(targetColor, "BotPOI is (null) --- clearing"); BotPoi.Clear(string.Format("Singular: (null) object was target (possibly another components error)")); } else { unit = BotPoi.Current.AsObject.ToUnit(); if (unit != null && !unit.IsAlive) { Logger.WriteDiagnostic(targetColor, "BotPOI " + unit.SafeName() + " is dead --- clearing"); BotPoi.Clear(string.Format("Singular: {0} is dead", unit.SafeName())); } else if (!Unit.ValidUnit(unit, showReason: true)) { Logger.Write(targetColor, "BotPOI " + unit.SafeName() + " not valid --- clearing"); BotPoi.Clear(string.Format("Singular: {0} invalid target", unit.SafeName())); } else { if (StyxWoW.Me.CurrentTargetGuid != unit.Guid) { Logger.Write(targetColor, "Switching to BotPoi: " + unit.SafeName() + "!"); } return unit; } } } #endif // Go below if current target is null or dead. We have other checks to deal with that if (!StyxWoW.Me.GotTarget() || StyxWoW.Me.CurrentTarget.IsDead) { return null; } // target not aggroed yet or out of range? check for adds in melee pounding us if (!Me.IsInGroup() && Me.Combat && ((!StyxWoW.Me.CurrentTarget.Combat && !StyxWoW.Me.CurrentTarget.Aggro && !StyxWoW.Me.CurrentTarget.PetAggro) || StyxWoW.Me.SpellDistance() > 30 || !StyxWoW.Me.CurrentTarget.InLineOfSpellSight)) { // Look for agrroed mobs next. prioritize by IsPlayer, Relative Distance, then Health var target = ObjectManager.GetObjectsOfType <WoWUnit>(false, false) .Where( p => p.SpellDistance() < 10 && Unit.ValidUnit(p) && (p.Aggro || p.PetAggro) && p.InLineOfSpellSight ) // .OrderBy(u => CalcDistancePriority(u)).ThenBy(u => u.HealthPercent) .OrderBy(u => u.HealthPercent) .FirstOrDefault(); if (target != null && target.Guid != Me.CurrentTargetGuid) { // Return the closest one to us Logger.Write(targetColor, "Switching to aggroed mob pounding on me " + target.SafeName() + "!"); return target; } } // check if current target is owned by a player WoWUnit pOwner = Unit.GetPlayerParent(Me.CurrentTarget); if (pOwner != null) { if (!Me.CurrentTarget.CanWeAttack()) { Logger.Write(targetColor, "CurrentTarget " + Me.CurrentTarget.SafeName() + " is a non-attackable enemy player pet so clearing target!"); Blacklist.Add(Me.CurrentTargetGuid, BlacklistFlags.Pull | BlacklistFlags.Combat, TimeSpan.FromSeconds(60), "Unattackable Enemy Player Pet is CurrentTarget"); Me.ClearTarget(); return null; } else if (Unit.ValidUnit(pOwner) && !Blacklist.Contains(pOwner, BlacklistFlags.Combat)) { Logger.Write(targetColor, "Current target owned by a player. Switching to " + pOwner.SafeName() + "!"); if (BotPoi.Current.Type == PoiType.Kill && BotPoi.Current.Guid == Me.CurrentTarget.Guid) { BotPoi.Clear(string.Format("Singular detected {0} as Player Owned Pet", Me.CurrentTarget.SafeName())); } return pOwner; } } // no valid BotPoi, so let's check Targeting.FirstUnit which is Bots #1 choice #if IGNORE_TARGETING_UNLESS_SEARCHING_FOR_NEW_TARGET #elif BOT_FIRSTUNIT_GETS_PRIORITY unit = Targeting.Instance.FirstUnit; if (unit != null && unit.IsAlive) { if (Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logger.Write(targetColor, "Targeting.FirstUnit " + unit.SafeName() + " is blacklisted!"); if (unit == Me.CurrentTarget && (Me.CurrentTarget.Combat && Me.CurrentTarget.IsTargetingMeOrPet)) { return unit; } return null; } if (StyxWoW.Me.CurrentTarget != unit) { Logger.Write(targetColor, "Current target is not Bots first choice. Switching to " + unit.SafeName() + "!"); } return unit; } #else foreach (var unit in Targeting.Instance.TargetList) { if (StyxWoW.Me.CurrentTargetGuid != unit.Guid && unit.IsAlive && !Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logger.Write(targetColor, "Bot has a higher priority target available. Switching to " + unit.SafeName() + "!"); return unit; } } #endif // at this point, just check its okay to kill currenttarget if (Blacklist.Contains(StyxWoW.Me.CurrentTargetGuid, BlacklistFlags.Combat)) { Logger.Write(targetColor, "CurrentTarget " + Me.CurrentTarget.SafeName() + " blacklisted and not in combat with so clearing target!"); Me.ClearTarget(); return null; } // valid unit? keep it then if (Unit.ValidUnit(Me.CurrentTarget, showReason: true)) { return Me.CurrentTarget; } if (Me.CurrentTarget.IsPlayer && !Battlegrounds.IsInsideBattleground && Me.CurrentTarget.IsHostile && !Me.CurrentTarget.CanWeAttack()) { Logger.Write(targetColor, "CurrentTarget " + Me.CurrentTarget.SafeName() + " is a non-attackable enemy player so clearing target!"); Blacklist.Add(Me.CurrentTargetGuid, BlacklistFlags.Pull | BlacklistFlags.Combat, TimeSpan.FromSeconds(15), "Unattackable Enemy Player is CurrentTarget"); Me.ClearTarget(); } // otherwise, let's get a new one Logger.WriteDebug(targetColor, "EnsureTarget: invalid target {0}, so forcing selection of a new one...", !Me.GotTarget() ? "(null)" : Me.CurrentTarget.SafeName()); return null; }, #endregion #region Target was selected -- change target if needed, or do nothing if already current target new Decorator( ret => ret != null, new Sequence( CreateClearPendingCursorSpell(RunStatus.Success), new Decorator( req => ((WoWUnit)req).Guid != StyxWoW.Me.CurrentTargetGuid, new Sequence( new Action(ret => { if (SingularSettings.Debug) { Logger.WriteDebug(targetColor, "EnsureTarget: switching to target {0}", ((WoWUnit)ret).SafeName()); } }), new Action(ret => ((WoWUnit)ret).Target()), new WaitContinue(2, ret => StyxWoW.Me.GotTarget() && StyxWoW.Me.CurrentTarget == (WoWUnit)ret, new ActionAlwaysSucceed()), new Action(ret => TankManager.TargetingTimer.Reset()) // cheaper to just reset than to check if we need Tank Targeting ) ), // fall through to spell priority at this point as we have our target and its valid new ActionAlwaysFail() ) ), #endregion #endregion #region Target Invalid (none or dead) - Find a New one if possible new Decorator( ret => ret == null, new PrioritySelector( ctx => { // If we have a RaF leader, then use its target. var rafLeader = RaFHelper.Leader; if (rafLeader != null && rafLeader.IsValid && !rafLeader.IsMe && rafLeader.Combat && rafLeader.GotTarget() && rafLeader.CurrentTarget.IsAlive && !Blacklist.Contains(rafLeader.CurrentTarget, BlacklistFlags.Combat)) { Logger.Write(targetColor, "Current target invalid. Switching to Tanks target " + rafLeader.CurrentTarget.SafeName() + "!"); return rafLeader.CurrentTarget; } /* * // if we have BotPoi then try it * if (SingularRoutine.CurrentWoWContext != WoWContext.Normal && BotPoi.Current.Type == PoiType.Kill) * { * var unit = BotPoi.Current.AsObject as WoWUnit; * if (unit == null) * { * Logger.Write(targetColor, "Current Kill POI invalid. Clearing POI!"); * BotPoi.Clear("Singular detected null POI"); * } * else if (!unit.IsAlive) * { * Logger.Write(targetColor, "Current Kill POI dead. Clearing POI " + unit.SafeName() + "!"); * BotPoi.Clear("Singular detected Unit is dead"); * } * else if (Blacklist.Contains(unit, BlacklistFlags.Combat)) * { * Logger.Write(targetColor, "Current Kill POI is blacklisted. Clearing POI " + unit.SafeName() + "!"); * BotPoi.Clear("Singular detected Unit is Blacklisted"); * } * else * { * Logger.Write(targetColor, "Current target invalid. Switching to POI " + unit.SafeName() + "!"); * return unit; * } * } */ // Look for agrroed mobs next. prioritize by IsPlayer, Relative Distance, then Health var target = Targeting.Instance.TargetList .Where( p => !Blacklist.Contains(p, BlacklistFlags.Combat) && Unit.ValidUnit(p) // && p.DistanceSqr <= 40 * 40 // dont restrict check to 40 yds && (p.Aggro || p.PetAggro || (p.Combat && p.GotTarget() && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)))) .OrderBy(u => u.IsPlayer) .ThenBy(u => CalcDistancePriority(u)) .ThenBy(u => u.HealthPercent) .FirstOrDefault(); if (target != null) { // Return the closest one to us Logger.Write(targetColor, "Current target invalid. Switching to aggroed mob " + target.SafeName() + "!"); return target; } /* * // if we have BotPoi then try it * if (SingularRoutine.CurrentWoWContext == WoWContext.Normal && BotPoi.Current.Type == PoiType.Kill) * { * var unit = BotPoi.Current.AsObject as WoWUnit; * if (unit == null) * { * Logger.Write(targetColor, "Current Kill POI invalid. Clearing POI!"); * BotPoi.Clear("Singular detected null POI"); * } * else if (!unit.IsAlive) * { * Logger.Write(targetColor, "Current Kill POI dead. Clearing POI " + unit.SafeName() + "!"); * BotPoi.Clear("Singular detected Unit is dead"); * } * else if (Blacklist.Contains(unit, BlacklistFlags.Combat)) * { * Logger.Write(targetColor, "Current Kill POI is blacklisted. Clearing POI " + unit.SafeName() + "!"); * BotPoi.Clear("Singular detected Unit is Blacklisted"); * } * } */ // now anything in the target list or a Player target = Targeting.Instance.TargetList .Where( p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.IsAlive // && p.DistanceSqr <= 40 * 40 // don't restrict check to 40 yds ) .OrderBy(u => u.IsPlayer) .ThenBy(u => u.DistanceSqr) .FirstOrDefault(); if (target != null) { // Return the closest one to us Logger.Write(targetColor, "Current target invalid. Switching to TargetList mob " + target.SafeName() + "!"); return target; } /* * // Cache this query, since we'll be using it for 2 checks. No need to re-query it. * var agroMob = * ObjectManager.GetObjectsOfType<WoWUnit>(false, false) * .Where(p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.IsHostile && !p.IsDead * && !p.Mounted && p.DistanceSqr <= 70 * 70 && p.IsPlayer && p.Combat && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)) * .OrderBy(u => u.DistanceSqr) * .FirstOrDefault(); * * if (agroMob != null) * { * if (!agroMob.IsPet || agroMob.SummonedByUnit == null) * { * Logger.Write(targetColor, "Current target invalid. Switching to player attacking us " + agroMob.SafeName() + "!"); * } * else * { * Logger.Write(targetColor, "Current target invalid. Enemy player pet {0} attacking us, switching to player {1}!", agroMob.SafeName(), agroMob.SummonedByUnit.SafeName()); * agroMob = agroMob.SummonedByUnit; * } * * return agroMob; * } */ // Look for agrroed mobs not in targetlist for some reason next. prioritize by IsPlayer, Relative Distance, then Health target = Unit.UnfriendlyUnits() .Where( p => !Blacklist.Contains(p, BlacklistFlags.Combat) && Unit.ValidUnit(p) // && p.DistanceSqr <= 40 * 40 // dont restrict check to 40 yds && (p.Aggro || p.PetAggro || (p.Combat && p.GotTarget() && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)))) .OrderBy(u => u.IsPlayer) .ThenBy(u => CalcDistancePriority(u)) .ThenBy(u => u.HealthPercent) .FirstOrDefault(); if (target != null) { // Return the closest one to us Logger.Write(targetColor, "Current target invalid. Switching to Unfriendly mob " + target.SafeName() + " attacking us!"); return target; } // And there's nothing left, so just return null, kthx. // ... but show a message about botbase still calling our Combat behavior with nothing to kill if (DateTime.UtcNow >= _timeNextInvalidTargetMessage) { _timeNextInvalidTargetMessage = DateTime.UtcNow + TimeSpan.FromSeconds(5); Logger.Write(targetColor, "Bot TargetList is empty, no targets available"); } return null; }, // Make sure the target is VALID. If not, then ignore this next part. (Resolves some silly issues!) new Decorator( ret => ret != null && ((WoWUnit)ret).Guid != StyxWoW.Me.CurrentTargetGuid, new Sequence( CreateClearPendingCursorSpell(RunStatus.Success), new Action(ret => Logger.WriteDebug(targetColor, "EnsureTarget: set target to chosen target {0}", ((WoWUnit)ret).SafeName())), new Action(ret => ((WoWUnit)ret).Target()), new WaitContinue(2, ret => StyxWoW.Me.GotTarget() && StyxWoW.Me.CurrentTargetGuid == ((WoWUnit)ret).Guid, new ActionAlwaysSucceed()) ) ), // fall through... we'll catch whether we targeted or not in next check new ActionAlwaysFail() ) ) ), #endregion new Decorator( req => !Me.GotTarget() || !Unit.ValidUnit(Me.CurrentTarget), new Action(r => { if (_lastTargetMessageGuid != Me.CurrentTargetGuid || _nextTargetMessageTimer.IsFinished) { Logger.Write(targetColor, "EnsureTarget: no valid target set by " + SingularRoutine.GetBotName() + " -- skipping " + Dynamics.CompositeBuilder.CurrentBehaviorType.ToString() + " spell priority"); _nextTargetMessageTimer.Reset(); } _lastTargetMessageGuid = Me.CurrentTargetGuid; return RunStatus.Success; }) ) ) )); }
private Composite SubBehavior_CombatWithViableMob() { return(new PrioritySelector(context => SelectedTarget = Me.CurrentTarget, // Recall pet, if necessary... new Decorator(context => (SelectedTarget.HealthPercent < RecallPetAtMobPercentHealth) && (Me.GotAlivePet && Me.Pet.GotTarget), new ActionFail(context => { QBCLog.Info("Recalling Pet from '{0}' (health: {1:F1})", SelectedTarget.SafeName, SelectedTarget.HealthPercent); PetControl.SetStance_Passive(); PetControl.Follow(); })), // If we are beyond the max range allowed to use the item, move within range... new Decorator(context => SelectedTarget.Distance > MaxRangeToUseItem, new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( SelectedTarget.Location, string.Format("within {0} feet of {1}", MaxRangeToUseItem, SelectedTarget.SafeName), MovementBy, (float)MaxRangeToUseItem))), // If time to use the item, do so... new Decorator(context => IsUseItemNeeded(SelectedTarget), new PrioritySelector( new ActionRunCoroutine(context => CommonCoroutines.StopMoving()), // Halt combat until we are able to use the item... new Decorator(context => ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)), new ActionFail(context => { // We use LUA to stop casting, since SpellManager.StopCasting() doesn't seem to work... if (Me.IsCasting) { Lua.DoString("SpellStopCasting()"); } if (Me.IsAutoAttacking) { Lua.DoString("StopAttack()"); } TreeRoot.StatusText = string.Format("Combat halted--waiting for {0} to become usable.", Utility.GetItemNameFromId(ItemId)); })), new Sequence( new ActionRunCoroutine(ctx => UtilityCoroutine.UseItemOnTarget( ItemId, SelectedTarget, () => BehaviorDone(string.Format("Terminating behavior due to missing {0}", Utility.GetItemNameFromId(ItemId))))), // Allow a brief time for WoWclient to apply aura to mob... new WaitContinue(TimeSpan.FromMilliseconds(5000), context => ItemUseAlwaysSucceeds || SelectedTarget.HasAura(ItemAppliesAuraId), new ActionAlwaysSucceed()), new ActionFail(context => { _waitTimerAfterUsingItem.Reset(); if (ItemUseAlwaysSucceeds || SelectedTarget.HasAura(ItemAppliesAuraId)) { // Count our success if no associated quest... if (!VariantQuestIds.Any()) { ++Counter; } // If we can only use the item once per target, blacklist this target from subsequent selection... if ((UseItemStrategy == UseItemStrategyType.UseItemOncePerTarget) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)) { SelectedTarget.BlacklistForInteracting(TimeSpan.FromSeconds(InteractBlacklistTimeInSeconds)); } // If we can't defend ourselves from the target, blacklist it for combat and move on... if (Query.IsViable(SelectedTarget) && ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend))) { SelectedTarget.BlacklistForCombat(TimeSpan.FromSeconds(InteractBlacklistTimeInSeconds)); BotPoi.Clear(); Me.ClearTarget(); SelectedTarget = null; } } if ((ItemAppliesAuraId > 0) && !SelectedTarget.HasAura(ItemAppliesAuraId)) { var auraNamesOnMob = ((SelectedTarget.Auras.Keys.Count > 0) ? string.Join(", ", SelectedTarget.Auras.Keys) : "none"); QBCLog.Warning("{1} did not acquire expected AuraId, \"{2}\"--retrying.{0}" + " Auras on {1}: {3}", Environment.NewLine, SelectedTarget.SafeName, Utility.GetSpellNameFromId(ItemAppliesAuraId), auraNamesOnMob); } }), // Prevent combat, if we're not supposed to defend... new Decorator(context => ((UseItemStrategy == UseItemStrategyType.UseItemContinuouslyOnTargetDontDefend) || (UseItemStrategy == UseItemStrategyType.UseItemOncePerTargetDontDefend)), new ActionAlwaysSucceed()) ))) )); }
public static async Task <bool> DoFishing() { if (AutoAnglerBot.Instance.Profile.FishAtHotspot && !Navigator.AtLocation(AutoAnglerBot.Instance.Profile.CurrentPoint)) { return(false); } if (AutoAnglerSettings.Instance.Poolfishing && BotPoi.Current.Type != PoiType.Harvest) { return(false); } if (await CheckLootFrame()) { return(true); } // refresh water walking if needed if (!Me.Mounted && WaterWalking.CanCast && !WaterWalking.IsActive && await WaterWalking.Cast()) { return(true); } if (AutoAnglerSettings.Instance.Poolfishing) { var pool = BotPoi.Current.AsObject as WoWGameObject; if (pool == null || !pool.IsValid) { BotPoi.Clear(); return(false); } if (await MoveToPool(pool)) { return(true); } } if (await EquipPole()) { return(true); } if (await EquipHat()) { return(true); } if (await Applylure()) { return(true); } if (await Applybait()) { return(true); } if (!AutoAnglerSettings.Instance.Poolfishing && AutoAnglerBot.Instance.ShouldFaceWaterNow) { AutoAnglerBot.Instance.ShouldFaceWaterNow = false; if (await FaceWater()) { return(true); } } if (Me.Mounted && await CommonCoroutines.Dismount("Fishing")) { return(true); } if (!await Coroutine.Wait(10000, () => !Me.IsFalling)) { AutoAnglerBot.Log("Falling for 10 seconds; I don't think this will end good."); return(false); } if (Me.IsSwimming) { await JumpOnWaterSurface(); } if (Me.IsMoving) { WoWMovement.MoveStop(); if (!await Coroutine.Wait(4000, () => !Me.IsMoving)) { return(false); } } // Checks if we got a bite and recasts if needed. if (await CheckFishLine()) { return(true); } return(false); }
private static void HandleEvadeBuggedMob(LuaEventArgs args, CombatLogEventArgs e) { WoWUnit unit = e.DestUnit; WoWGuid guid = e.DestGuid; if (unit == null && StyxWoW.Me.GotTarget()) { unit = StyxWoW.Me.CurrentTarget; guid = StyxWoW.Me.CurrentTargetGuid; Logger.Write("Evade: bugged mob guid:{0}, so assuming current target instead", args.Args[7]); } if (unit != null) { if (!MobsThatEvaded.ContainsKey(unit.Guid)) { MobsThatEvaded.Add(unit.Guid, 0); } MobsThatEvaded[unit.Guid] = MobsThatEvaded[unit.Guid] + 1; if (MobsThatEvaded[unit.Guid] < SingularSettings.Instance.EvadedAttacksAllowed) { Logger.Write("Mob {0} has evaded {1} times. Not blacklisting yet, but will count evades on {2:X0} for now", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid); } else { const int MinutesToBlacklist = 5; if (Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logger.Write(Color.LightGoldenrodYellow, "Mob {0} has evaded {1} times. Previously blacklisted {2:X0} for {3} minutes!", unit.SafeName(), MobsThatEvaded[unit.Guid], unit.Guid, MinutesToBlacklist); } else { string fragment = string.Format("Mob {0} has evaded {1} times", unit.SafeName(), MobsThatEvaded[unit.Guid]); Logger.Write(Color.LightGoldenrodYellow, "{0}. Blacklisting {1:X0} for {2} minutes!", fragment, unit.Guid, MinutesToBlacklist); Blacklist.Add(unit.Guid, BlacklistFlags.Combat, TimeSpan.FromMinutes(MinutesToBlacklist), "Singular - " + fragment); if (!Blacklist.Contains(unit.Guid, BlacklistFlags.Combat)) { Logger.Write(Color.Pink, "error: blacklist does not contain entry for {0} after Blacklist.Add", unit.SafeName()); } } if (BotPoi.Current.Guid == unit.Guid) { Logger.Write("EvadeHandling: Current BotPOI type={0} is Evading, clearing now...", BotPoi.Current.Type); BotPoi.Clear("Singular recognized Evade bugged mob"); } if (StyxWoW.Me.CurrentTargetGuid == guid) { foreach (var target in Targeting.Instance.TargetList) { if (Unit.ValidUnit(target) && !Blacklist.Contains(target.Guid, BlacklistFlags.Pull | BlacklistFlags.Combat) && unit.EvadedAttacksCount() < SingularSettings.Instance.EvadedAttacksAllowed ) { Logger.Write(Color.Pink, "Setting target to {0} to get off evade bugged mob!", target.SafeName()); target.Target(); return; } } Logger.Write(Color.Pink, "BotBase has 0 entries in Target list not blacklisted -- nothing else we can do at this point!"); // StyxWoW.Me.ClearTarget(); } } } /// line below was originally in Evade logic, but commenting to avoid Sleeps // StyxWoW.SleepForLagDuration(); }
private static WoWUnit SecondTarget() { // Check BotPoi first if (BotPoi.Current.Type == PoiType.Kill) { var unit = BotPoi.Current.AsObject as WoWUnit; if (unit == null) { Helpers.Logger.PrintLog("Current BotPoi is null, clearing BotPoi"); BotPoi.Clear(); } else if (!unit.IsAlive) { Helpers.Logger.PrintLog("Current unit is dead, clearing BotPoi"); BotPoi.Clear(); } else if (Blacklist.Contains(unit, BlacklistFlags.Combat)) { Helpers.Logger.PrintLog("Current unit is blacklisted, clearing BotPoi"); BotPoi.Clear(); } else { Helpers.Logger.PrintLog("Current unit invalid, clearing BotPoi"); return(unit); } } // Look for agrroed mobs next. prioritize by IsPlayer, Relative Distance, then Health var target = Targeting.Instance.TargetList .Where( p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.ValidAttackUnit() && (p.Aggro || p.PetAggro || (p.Combat && p.GotTarget && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)))) // Check if there's a player there, maybe we're getting ganked .OrderBy(u => u.IsPlayer) // Then order then pick the closest and lowest health target .ThenBy(u => u.Distance) .ThenBy(u => u.HealthPercent) .FirstOrDefault(); if (target != null) { // Return the target we selected Helpers.Logger.PrintLog("Switching to a unit aggro'd to us"); return(target); } // At this point, look for anything in the target list target = Targeting.Instance.TargetList .Where(p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.IsAlive) .OrderBy(u => u.IsPlayer) .ThenBy(u => u.DistanceSqr) .FirstOrDefault(); if (target != null) { // Return the closest one to us //Helpers.Logger.PrintLog("Switching to unit in the target list"); return(target); } return(null); }
private static Composite CreatePullMorePull() { if (false == IsPullMoreActive) return new ActionAlwaysFail(); _rangePullMore = Me.IsMelee() ? SingularSettings.Instance.PullMoreDistMelee : SingularSettings.Instance.PullMoreDistRanged; return new Decorator( req => HotkeyDirector.IsPullMoreEnabled && (_allowPullMoreUntil == DateTime.MinValue || _allowPullMoreUntil > DateTime.UtcNow) && !Spell.IsCastingOrChannelling(), new Sequence( new PrioritySelector( new Decorator( req => SingularSettings.Instance.UsePullMore == PullMoreUsageType.Auto && SingularRoutine.IsQuestBotActive && !IsQuestProfileLoaded, new ActionAlwaysFail() ), new Decorator( req => !IsAllowed( CapabilityFlags.MultiMobPull), new Action(r => { // disable pull more until we leave combat Logger.WriteDiagnostic(Color.White, "Pull More: CapabilityFlag.MultiMobPull set to Disallow, finishing these before pulling more"); _allowPullMoreUntil = DateTime.UtcNow; }) ), new Decorator( req => Me.HealthPercent < SingularSettings.Instance.PullMoreMinHealth, new Action(r => { // disable pull more until we leave combat Logger.WriteDiagnostic(Color.White, "Pull More: health dropped to {0:F1}%, finishing these before pulling more", Me.HealthPercent); _allowPullMoreUntil = DateTime.UtcNow; }) ), new Decorator( req => (Singular.Utilities.EventHandlers.TimeSinceAttackedByEnemyPlayer.TotalSeconds < 15), new Action(r => { Logger.WriteDiagnostic(Color.White, "Pull More: attacked by player {0:F1} seconds ago, disabling pull more until out of combat", Singular.Utilities.EventHandlers.TimeSinceAttackedByEnemyPlayer.TotalSeconds); _allowPullMoreUntil = DateTime.UtcNow; }) ), new PrioritySelector( ctx => Unit.UnitsInCombatWithUsOrOurStuff(45) .FirstOrDefault(u => u.TappedByAllThreatLists || (u.Elite && (u.Level + 8) > Me.Level) || (u.MaxHealth > (Me.MaxHealth * 2))), new Decorator( req => req != null, new Action(r => { if ((r as WoWUnit).TappedByAllThreatLists) Logger.WriteDiagnostic(Color.White, "Pull More: attacked by important quest mob {0} #{1}, disabling pull more until killed", (r as WoWUnit).SafeName(), (r as WoWUnit).Entry); else if ((r as WoWUnit).Elite) Logger.WriteDiagnostic(Color.White, "Pull More: attacking non-trivial Elite {0} #{1}, disabling pull more until killed", (r as WoWUnit).SafeName(), (r as WoWUnit).Entry); else Logger.WriteDiagnostic(Color.White, "Pull More: attacking non-trivial Mob {0} #{1} maxhealth {2}, disabling pull more until killed", (r as WoWUnit).SafeName(), (r as WoWUnit).Entry, (r as WoWUnit).MaxHealth); _allowPullMoreUntil = DateTime.UtcNow; }) ) ), new Sequence( ctx => BotPoi.Current == null ? null : BotPoi.Current.AsObject, new Action(r => { _mobCountInCombat = Unit.UnitsInCombatWithUsOrOurStuff(50).Count(); if (_mobCountInCombat >= SingularSettings.Instance.PullMoreMobCount) { Logger.WriteDiagnostic(Color.White, "Pull More: in combat with {0} mobs, finishing these before pulling more", _mobCountInCombat); _allowPullMoreUntil = DateTime.UtcNow; } else if ( r == null ) { } else if (BotPoi.Current.Type != PoiType.Kill) { } else if ((r as WoWObject).ToUnit() == null) { } else { // cleared validations, move on to next state return RunStatus.Success; } return RunStatus.Failure; }), // check if still pulling new DecoratorContinue( req => { WoWUnit unit = (req as WoWUnit); return unit.IsAlive && (!unit.IsTagged || !unit.IsTargetingMyStuff() || !unit.Combat); }, new Sequence( // check if timed out new Decorator( req => DateTime.UtcNow > _timeoutPullMoreAt, new Action( r => { WoWUnit unit = (r as WoWUnit); Logger.Write( LogColor.Hilite, "Pull More: could not pull {0} @ {1:F1} yds within {2} seconds, blacklisting", unit.SafeName(), unit.SpellDistance(), SingularSettings.Instance.PullMoreTimeOut ); Blacklist.Add(unit.Guid, BlacklistFlags.Pull, TimeSpan.FromMinutes(5), "Singular: pull more timed out"); BotPoi.Clear("Singular: pull more timed out"); return RunStatus.Failure; }) ), // otherwise fail since target not engaged yet new ThrottlePasses( 1, TimeSpan.FromSeconds(1), RunStatus.Failure, new Action( r => { WoWUnit unit = (r as WoWUnit); Logger.WriteDebug("Pull More: waiting since current KillPoi {0} not attacking me yet (target={1}, combat={2}, tagged={3})", unit.SafeName(), unit.GotTarget() ? unit.SafeName() : "(null)", unit.Combat.ToYN(), unit.IsTagged.ToYN() ); return RunStatus.Failure; }) ) ) ), // now pull more new ThrottlePasses( 1, TimeSpan.FromSeconds(1), RunStatus.Failure, new Action( r => { WoWUnit unit = (r as WoWUnit); _timeoutPullMoreAt = DateTime.MaxValue; Func<WoWUnit, bool> whereClause = PullMoreTargetSelectionDelegate(); // build list of location of mobs to avoid List<WoWPoint> mobToAvoid = Unit.UnfriendlyUnits() .Where( u => u.IsHostile && u.IsAlive && ( (u.Elite && u.Level+8 > Me.Level) || (u.MaxHealth > Me.MaxHealth * 2) || (ProfileManager.CurrentProfile != null && ProfileManager.CurrentProfile.AvoidMobs != null && ProfileManager.CurrentProfile.AvoidMobs.Contains(u.Entry)) ) && u.DistanceSqr < 70 * 70) .Select( u => u.Location) .ToList(); WoWUnit nextPull = Unit.UnfriendlyUnits() .Where( t => !t.IsPlayer && !t.IsPet && !t.IsPetBattleCritter && !t.IsTagged && (!t.Combat || (t.GotTarget() && !t.CurrentTarget.IsPlayer && !t.CurrentTarget.IsPet)) && !Blacklist.Contains(t, BlacklistFlags.Pull | BlacklistFlags.Combat) && Unit.ValidUnit(t) && t.Level <= (Me.Level + 2) && (whereClause(t) || Targeting.Instance.TargetList.Any(u => u.Guid == t.Guid)) && (ProfileManager.CurrentProfile == null || ProfileManager.CurrentProfile.AvoidMobs == null || !ProfileManager.CurrentProfile.AvoidMobs.Contains(t.Entry)) && t.SpellDistance() <= _rangePullMore && !mobToAvoid.Any( loc => loc.DistanceSqr(t.Location) < 40) ) .OrderBy(k => (long)k.DistanceSqr) .FirstOrDefault(); // set target at botpoi if (nextPull != null && unit.Guid != nextPull.Guid) { Logger.WriteDebug("Pull More: more adds allowed since current KillPoi {0}, target={1}, combat={2}, tagged={3}", unit.SafeName(), unit.GotTarget() ? unit.SafeName() : "(null)", unit.Combat.ToYN(), unit.IsTagged.ToYN() ); Logger.Write( LogColor.Hilite, "Pull More: pulling {0} #{1} - {2} @ {3:F1} yds", _PullMoreTargetFindType, _mobCountInCombat + 1, nextPull.SafeName(), nextPull.SpellDistance()); BotPoi poi = new BotPoi(nextPull, PoiType.Kill, NavType.Run); Logger.WriteDebug("Setting BotPoi to Kill {0}", nextPull.SafeName()); Styx.CommonBot.POI.BotPoi.Current = poi; if (Styx.CommonBot.POI.BotPoi.Current.Guid != poi.Guid) Logger.WriteDiagnostic(Color.White, "Pull More: ERROR, could not set POI: Current: {0}, Wanted: {1}", Styx.CommonBot.POI.BotPoi.Current, poi); else { nextPull.Target(); _timeoutPullMoreAt = DateTime.UtcNow + TimeSpan.FromSeconds(SingularSettings.Instance.PullMoreTimeOut); if (_allowPullMoreUntil == DateTime.MinValue) _allowPullMoreUntil = DateTime.UtcNow + TimeSpan.FromSeconds(SingularSettings.Instance.PullMoreMaxTime); if (Me.Pet != null && (Me.Pet.CurrentTarget == null || Me.Pet.CurrentTargetGuid != Me.Guid)) { PetManager.Attack(nextPull); } } } return RunStatus.Failure; }) ) ) ), new ActionAlwaysFail() ) ); }
internal static Composite TargetingPulse() { return(new Decorator(ret => AdvancedAI.Movement, new PrioritySelector(ctx => { // If we have a RaF leader, then use its target. var rafLeader = RaFHelper.Leader; if (rafLeader != null && rafLeader.IsValid && !rafLeader.IsMe && rafLeader.Combat && rafLeader.CurrentTarget != null && rafLeader.CurrentTarget.IsAlive && !Blacklist.Contains(rafLeader.CurrentTarget, BlacklistFlags.Combat)) { Logging.Write(targetColor, "Current target invalid. Switching to Tanks target " + rafLeader.CurrentTarget.SafeName() + "!"); return rafLeader.CurrentTarget; } // if we have BotPoi then try it if (AdvancedAI.CurrentWoWContext != WoWContext.Normal && BotPoi.Current.Type == PoiType.Kill) { var unit = BotPoi.Current.AsObject as WoWUnit; if (unit == null) { Logging.Write(targetColor, "Current Kill POI invalid. Clearing POI!"); BotPoi.Clear("AdvancedAI detected null POI"); } else if (!unit.IsAlive) { Logging.Write(targetColor, "Current Kill POI dead. Clearing POI " + unit.SafeName() + "!"); BotPoi.Clear("AdvancedAI detected Unit is dead"); } else if (Blacklist.Contains(unit, BlacklistFlags.Combat)) { Logging.Write(targetColor, "Current Kill POI is blacklisted. Clearing POI " + unit.SafeName() + "!"); BotPoi.Clear("AdvancedAI detected Unit is Blacklisted"); } else { Logging.Write(targetColor, "Current target invalid. Switching to POI " + unit.SafeName() + "!"); return unit; } } // Look for agrroed mobs next. prioritize by IsPlayer, Relative Distance, then Health var target = Targeting.Instance.TargetList.Where(p => !Blacklist.Contains(p, BlacklistFlags.Combat) && Unit.ValidUnit(p) && (p.Aggro || p.PetAggro || (p.Combat && p.GotTarget && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)))) .OrderBy(u => u.IsPlayer) .ThenBy(CalcDistancePriority) .ThenBy(u => u.HealthPercent) .FirstOrDefault(); if (target != null) { // Return the closest one to us Logging.Write(targetColor, "Current target invalid. Switching to aggroed mob " + target.SafeName() + "!"); return target; } // if we have BotPoi then try it if (AdvancedAI.CurrentWoWContext == WoWContext.Normal && BotPoi.Current.Type == PoiType.Kill) { var unit = BotPoi.Current.AsObject as WoWUnit; if (unit == null) { Logging.Write(targetColor, "Current Kill POI invalid. Clearing POI!"); BotPoi.Clear("AdvancedAI detected null POI"); } else if (!unit.IsAlive) { Logging.Write(targetColor, "Current Kill POI dead. Clearing POI " + unit.SafeName() + "!"); BotPoi.Clear("AdvancedAI detected Unit is dead"); } else if (Blacklist.Contains(unit, BlacklistFlags.Combat)) { Logging.Write(targetColor, "Current Kill POI is blacklisted. Clearing POI " + unit.SafeName() + "!"); BotPoi.Clear("AdvancedAI detected Unit is Blacklisted"); } else { Logging.Write(targetColor, "Current target invalid. Switching to POI " + unit.SafeName() + "!"); return unit; } } // now anything in the target list or a Player target = Targeting.Instance.TargetList.Where(p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.IsAlive) .OrderBy(u => u.IsPlayer) .ThenBy(u => u.DistanceSqr) .FirstOrDefault(); if (target != null) { // Return the closest one to us Logging.Write(targetColor, "Current target invalid. Switching to TargetList mob " + target.SafeName() + "!"); return target; } #region Commented //// Cache this query, since we'll be using it for 2 checks. No need to re-query it. //var agroMob = // ObjectManager.GetObjectsOfType<WoWUnit>(false, false) // .Where(p => !Blacklist.Contains(p, BlacklistFlags.Combat) && p.IsHostile && !p.IsDead // && !p.Mounted && p.DistanceSqr <= 70 * 70 && p.IsPlayer && p.Combat && (p.IsTargetingMeOrPet || p.IsTargetingMyRaidMember)) // .OrderBy(u => u.DistanceSqr) // .FirstOrDefault(); //if (agroMob != null) //{ // if (!agroMob.IsPet || agroMob.SummonedByUnit == null) // { // Logger.Write(targetColor, "Current target invalid. Switching to player attacking us " + agroMob.SafeName() + "!"); // } // else // { // Logger.Write(targetColor, "Current target invalid. Enemy player pet {0} attacking us, switching to player {1}!", agroMob.SafeName(), agroMob.SummonedByUnit.SafeName()); // agroMob = agroMob.SummonedByUnit; // } // return agroMob; //} #endregion // And there's nothing left, so just return null, kthx. // ... but show a message about botbase still calling our Combat behavior with nothing to kill if (DateTime.Now >= _timeNextInvalidTargetMessage) { _timeNextInvalidTargetMessage = DateTime.Now + TimeSpan.FromSeconds(1); Logging.Write(targetColor, "Bot TargetList is empty, no targets available"); } return null; }, // Make sure the target is VALID. If not, then ignore this next part. (Resolves some silly issues!) new Decorator(ret => ret != null && ((WoWUnit)ret).Guid != StyxWoW.Me.CurrentTargetGuid, new Sequence( CreateClearPendingCursorSpell(RunStatus.Success), new Action(ret => Logging.WriteDiagnostic(targetColor, "EnsureTarget: set target to chosen target {0}", ((WoWUnit)ret).SafeName())), new Action(ret => ((WoWUnit)ret).Target()), new WaitContinue(2, ret => StyxWoW.Me.CurrentTarget != null && StyxWoW.Me.CurrentTargetGuid == ((WoWUnit)ret).Guid, new ActionAlwaysSucceed()))), // looks like no success, so don't continue to spell priorities new Decorator(ret => !Me.GotTarget || Me.CurrentTarget.IsDead, new ActionAlwaysSucceed()), // otherwise, we are here if current target is valid or we set a good one, either way... fall through new ActionAlwaysFail()))); }
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); }
// Thanks to Singular Devs for the CombatLogEventArgs class and SpellImmunityManager. private static void HandleCombatLog(object sender, LuaEventArgs args) { var e = new CombatLogEventArgs(args.EventName, args.FireTimeStamp, args.Args); //var missType = Convert.ToString(e.Args[14]); switch (e.Event) { case "SWING_MISSED": if (e.Args[11].ToString() == "EVADE") { CLULogger.TroubleshootLog("Mob is evading swing. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[11].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { CLULogger.TroubleshootLog("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; case "SPELL_MISSED": case "RANGE_MISSED": if (e.Args[14].ToString() == "EVADE") { CLULogger.TroubleshootLog("Mob is evading ranged attack. Blacklisting it!"); Blacklist.Add(e.DestGuid, TimeSpan.FromMinutes(30)); if (StyxWoW.Me.CurrentTargetGuid == e.DestGuid) { StyxWoW.Me.ClearTarget(); } BotPoi.Clear("Blacklisting evading mob"); StyxWoW.SleepForLagDuration(); } else if (e.Args[14].ToString() == "IMMUNE") { WoWUnit unit = e.DestUnit; if (unit != null && !unit.IsPlayer) { CLULogger.TroubleshootLog("{0} is immune to {1} spell school", unit.Name, e.SpellSchool); SpellImmunityManager.Add(unit.Entry, e.SpellSchool); } } break; case "SPELL_AURA_REFRESH": if (e.SourceGuid == StyxWoW.Me.Guid) { if (e.SpellId == 1822) { Classes.Druid.Common.RakeMultiplier = 1; //TF if (StyxWoW.Me.HasAura(5217)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.15; } //Savage Roar if (StyxWoW.Me.HasAura(127538)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.3; } //Doc if (StyxWoW.Me.HasAura(108373)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.25; } } if (e.SpellId == 1079) { Classes.Druid.Common.ExtendedRip = 0; Classes.Druid.Common.RipMultiplier = 1; //TF if (StyxWoW.Me.HasAura(5217)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.15; } //Savage Roar if (StyxWoW.Me.HasAura(127538)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.3; } //Doc if (StyxWoW.Me.HasAura(108373)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.25; } } } break; case "SPELL_AURA_APPLIED": if (e.SourceGuid == StyxWoW.Me.Guid) { if (e.SpellId == 1822) { Classes.Druid.Common.RakeMultiplier = 1; //TF if (StyxWoW.Me.HasAura(5217)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.15; } //Savage Roar if (StyxWoW.Me.HasAura(127538)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.3; } //Doc if (StyxWoW.Me.HasAura(108373)) { Classes.Druid.Common.RakeMultiplier = Classes.Druid.Common.RakeMultiplier * 1.25; } } if (e.SpellId == 1079) { Classes.Druid.Common.ExtendedRip = 0; Classes.Druid.Common.RipMultiplier = 1; //TF if (StyxWoW.Me.HasAura(5217)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.15; } //Savage Roar if (StyxWoW.Me.HasAura(127538)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.3; } //Doc if (StyxWoW.Me.HasAura(108373)) { Classes.Druid.Common.RipMultiplier = Classes.Druid.Common.RipMultiplier * 1.25; } } } break; case "SPELL_AURA_REMOVED": if (e.SourceGuid == StyxWoW.Me.Guid) { if (e.SpellId == 1822) { Classes.Druid.Common.RakeMultiplier = 0; } if (e.SpellId == 1079) { Classes.Druid.Common.ExtendedRip = 0; Classes.Druid.Common.RipMultiplier = 0; } } break; } }