private static void StealthedCombat() { if (Me.CurrentTarget == null || Me.CurrentTarget.IsDead || (!Me.CurrentTarget.IsHostile && !Unit.IsTrainingDummy(Me.CurrentTarget)) || !Me.CurrentTarget.Attackable) { return; } if ((!Me.IsStealthed && !Buff.PlayerHasActiveBuff("Vanish")) || !SafeToBreakStealth) { return; } // If we're not behind, attempt to shadowstep and wait for next pulse. if (SpellManager.HasSpell("Shadowstep") && !StyxWoW.Me.IsBehind(Me.CurrentTarget) && Spell.CanCast("Shadowstep", Me.CurrentTarget)) { CLULogger.Log(" [Casting] Shadowstep on {0} @ StealthedCombat", CLULogger.SafeName(Me.CurrentTarget)); SpellManager.Cast("Shadowstep"); } else if (Me.Behind(Me.CurrentTarget) && (Me.CurrentEnergy >= 60 || HasShadowFocus)) { CLULogger.Log(" [Casting] Ambush on {0} @ StealthCombat", CLULogger.SafeName(Me.CurrentTarget)); SpellManager.Cast("Ambush"); } }
/// <summary> /// Returns true if we meet the requirements of the weapon /// </summary> /// <param name="slot">Inventory slot to check</param> /// <returns>true if the weapon is suitable</returns> public static bool HasSuitableWeapon(WoWInventorySlot slot) { switch (slot) { case WoWInventorySlot.OffHand: { var suitableOffhand = Me.Inventory.Equipped.OffHand != null && Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon && Me.Inventory.Equipped.MainHand != null && StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment != null; if (!suitableOffhand) { CLULogger.Log("Please Ensure your weapons are correct for the TalentSpec you are using"); } return(suitableOffhand); } case WoWInventorySlot.MainHand: { var suitableMainhand = Me.Inventory.Equipped.MainHand.ItemInfo.ItemClass == WoWItemClass.Weapon && Me.Inventory.Equipped.MainHand != null; if (!suitableMainhand) { CLULogger.Log("Please Ensure your weapons are correct for the TalentSpec you are using"); } return(suitableMainhand); } } return(false); }
/// <summary>Returns a summoned pet</summary> /// <param name="nameID">the id of the spell</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The cast pet summon spell.</returns> public static Composite CastPetSummonSpell(int nameID, CanRunDecoratorDelegate cond, string label) { WoWSpell summonPet = WoWSpell.FromId(nameID); if (summonPet.CastTime > 0) { Spell.KnownChanneledSpells.Add(summonPet.Name); } return(new Decorator( delegate(object a) { if (!cond(a)) { return false; } if (!Spell.CanCast(summonPet.ToString())) { return false; } return true; }, new Decorator(ret => !Me.GotAlivePet && PetTimer.IsFinished, new Sequence( new Action(a => CLULogger.Log(" {0}", label)), new Action(a => SpellManager.Cast(summonPet)), Spell.CreateWaitForLagDuration(), new Wait(5, a => Me.GotAlivePet || !Me.IsCasting, new PrioritySelector( new Decorator(a => StyxWoW.Me.IsCasting, new Action(ret => SpellManager.StopCasting())), new ActionAlwaysSucceed())))))); }
/// <summary>Cast's a pet spell</summary> /// <param name="name">the pet spell to cast</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The cast pet spell.</returns> public static Composite CastPetSpell(string name, CanRunDecoratorDelegate cond, string label) { return(new Decorator( a => cond(a) && CanCastPetSpell(name), new Sequence( new Action(a => CLULogger.Log(" [Pet Spell] {0} ", label)), new Action(a => CastMyPetSpell(name))))); }
/// <summary> /// sets the character's active rotation. /// Print the help located in the specific rotation /// </summary> /// <param name="rb">an instance of the rotationbase</param> private void SetActiveRotation(RotationBase rb) { CLULogger.Log(" Greetings, level {0} user!", Me.Level); CLULogger.Log(" I am CLU."); CLULogger.Log(" I will create the perfect system for you."); CLULogger.Log(" I suggest we use the " + rb.Name + " rotation. Revision: " + rb.Revision); CLULogger.Log(" as I know you have " + rb.KeySpell); CLULogger.Log(" BotBase: {0} ({1})", BotManager.Current.Name, BotChecker.SupportedBotBase() ? "Supported" : "Currently Not Supported"); CLULogger.Log(rb.Help); CLULogger.Log(" You can Access CLU's Settings by clicking the CLASS CONFIG button"); CLULogger.Log(" Let's execute the plan!"); this._rotationBase = rb; this.PulseEvent = null; this.PulseEvent += rb.OnPulse; // Check for Instancebuddy and warn user that healing is not supported. if (BotChecker.BotBaseInUse("Instancebuddy") && this.ActiveRotation.GetType().BaseType == typeof(HealerRotationBase)) { CLULogger.Log(" [BotChecker] Instancebuddy Detected. *UNABLE TO HEAL WITH CLU*"); StopBot("You cannot use CLU with InstanceBuddy as Healer"); } if (this.ActiveRotation.GetType().BaseType == typeof(HealerRotationBase)) { CLULogger.TroubleshootLog(" [HealingChecker] HealerRotationBase Detected. *Activating Automatic HealableUnit refresh*"); IsHealerRotationActive = true; } }
/// <summary>Runs Lua MacroText</summary> /// <param name="macro">the macro text to run</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The run macro text.</returns> public static Composite RunMacroText(string macro, CanRunDecoratorDelegate cond, string label) { return(new Decorator( cond, new Sequence( new Action(a => CLULogger.Log(" [RunMacro] {0} ", label)), new Action(a => Lua.DoString("RunMacroText(\"" + Spell.RealLuaEscape(macro) + "\")"))))); }
public static Composite HandleTotemRecall() { return(new Decorator( ret => Totems.NeedToRecallTotems, new Sequence( new Action(ret => CLULogger.Log(" [Totems] Recalling Totems")), new Action(ret => Totems.RecallTotems())))); }
/// <summary> /// Uses the item specified (simulated click) /// </summary> /// <param name="item">The item to use</param> private static void UseItem(WoWItem item) { if (item != null) { CLULogger.Log(" [UseItem] {0} ", item.Name); item.Use(); } }
public void PrintHealReport() { CLULogger.Log("CLU Healing report:"); CLULogger.Log("------------------------------------------"); CLULogger.Log("These are the spells from UNIT_SPELLCAST_SUCCEEDED"); CLULogger.Log("------------------------------------------"); foreach (KeyValuePair <DateTime, string> entry in this.healingStats) { CLULogger.Log("[" + entry.Key + "] " + entry.Value); } CLULogger.Log("------------------------------------------"); }
/// <summary> /// Frees you from movement imparing effects if a usable spell exists /// </summary> /// <returns>More win then Wulf's UseRacial call</returns> public static Composite freeMe() { return( new PrioritySelector(delegate { foreach (WoWSpell s in freeMeSpellList.Where(spell => Spell.CanCast(spell.Name, StyxWoW.Me) && freeMeSpellUsage(spell))) { CLULogger.Log(" [Freeing you via] {0} ", s.Name); SpellManager.Cast(s.Name); } return RunStatus.Success; }) ); }
/// <summary> /// Blows your wad all over the floor /// </summary> /// <returns>Nothing but win</returns> public static Composite UseRacials() { return(new PrioritySelector(delegate { if (!CLUSettings.Instance.UseRacials) { return false; // gtfo if we do not want to use racials. } foreach (WoWSpell r in CurrentRacials.Where(racial => Spell.CanCast(racial.Name, StyxWoW.Me) && RacialUsageSatisfied(racial))) { CLULogger.Log(" [Racial Abilitie] {0} ", r.Name); SpellManager.Cast(r.Name); } return RunStatus.Success; })); }
/// <summary>Casts a Pet spell at the units location</summary> /// <param name="name">the name of the spell to cast</param> /// <param name="onUnit">The on Unit.</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The cast spell at location.</returns> public static Composite CastPetSpellAtLocation(string name, CLU.UnitSelection onUnit, CanRunDecoratorDelegate cond, string label) { // CLU.DebugLog(" [CastSpellAtLocation] name = {0} location = {1} and can we cast it? {2}", name, SysLog.SafeName(unit), CanCast(name)); return(new Decorator( delegate(object a) { if (!CLUSettings.Instance.UseAoEAbilities) { return false; } if (Me.CurrentTarget == null) { return false; } WoWPoint currTargetLocation = Me.CurrentTarget.Location; if (Unit.NearbyControlledUnits(currTargetLocation, 20, false).Any()) { return false; } if (!cond(a)) { return false; } if (!CanCastPetSpell(name)) { return false; } return onUnit != null; }, new Sequence( new Action(a => CLULogger.Log(" [Pet Casting at location] {0} ", label)), new Action(a => CastMyPetSpell(name)), // new WaitContinue( // 0, // ret => StyxWoW.Me.CurrentPendingCursorSpell != null && // StyxWoW.Me.CurrentPendingCursorSpell.Name == name, // new ActionAlwaysSucceed()), new Action(a => SpellManager.ClickRemoteLocation(onUnit(a).Location))))); }
/// <summary>Attempts to use the bag item provided it is usable and its not on cooldown</summary> /// <param name="name">the name of the bag item to use</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The use bag item.</returns> public static Composite UseBagItem(string name, CanRunDecoratorDelegate cond, string label) { WoWItem item = null; return(new Decorator( delegate(object a) { if (!cond(a)) { return false; } item = Me.BagItems.FirstOrDefault(x => x.Name == name && x.Usable && x.Cooldown <= 0); return item != null; }, new Sequence( new Action(a => CLULogger.Log(" [BagItem] {0} ", label)), new Action(a => item.UseContainerItem())))); }
/// <summary>Returns a summoned pet</summary> /// <param name="name">the name of the spell</param> /// <param name="cond">The conditions that must be true</param> /// <param name="label">A descriptive label for the clients GUI logging output</param> /// <returns>The cast pet summon spell.</returns> public static Composite CastPetSummonSpell(string name, CanRunDecoratorDelegate cond, string label) { try { var isWarlock = Me.Class == WoWClass.Warlock && SpellManager.Spells[name].Name.StartsWith("Summon "); if (isWarlock) { Spell.KnownChanneledSpells.Add(name); } return(new Decorator( delegate(object a) { if (!cond(a)) { return false; } if (!Spell.CanCast(name, Me)) { return false; } return true; }, new Decorator(ret => !Me.GotAlivePet && PetTimer.IsFinished, new Sequence( new Action(a => CLULogger.Log(" {0}", label)), new Action(a => SpellManager.Cast(name)), Spell.CreateWaitForLagDuration(), new Wait(5, a => Me.GotAlivePet || !Me.IsCasting, new PrioritySelector( new Decorator(a => StyxWoW.Me.IsCasting, new Action(ret => SpellManager.StopCasting())), new ActionAlwaysSucceed())))))); } catch { CLULogger.DiagnosticLog("Summon Spell {0} not supported for your Class / Specc ({1}/{2})", name, Me.Class, Me.Specialization); return(null); } }
public void PrintReport() { // var spells = spellList.OrderByDescending(x => x.Value); // var seconds = DateTime.Now.Subtract(start).TotalSeconds; var minutes = DateTime.Now.Subtract(this.start).TotalMinutes; var apm = (int)(this.spellCasts / minutes); CLULogger.Log("CLU stats report:"); CLULogger.Log("Runtime: {0} minutes", Math.Round(minutes * 10.0) / 10.0); CLULogger.Log("Spells cast: {0}", this.spellCasts > 1000 ? ((Math.Round(this.spellCasts / 100.0) * 10) + "k") : this.spellCasts.ToString(CultureInfo.InvariantCulture)); CLULogger.Log("Average APM: {0}", apm); CLULogger.Log("------------------------------------------"); foreach (KeyValuePair <string, int> spell in this.spellList) { CLULogger.Log(spell.Key + " was cast " + spell.Value + " time(s)."); } CLULogger.Log("------------------------------------------"); foreach (KeyValuePair <string, List <DateTime> > spell in this.spellInterval) { var lastInterval = this.start; var output = "0 "; for (int x = 0; x < spell.Value.Count - 1; ++x) { var interval = spell.Value[x]; var difference = interval - lastInterval; output = output + string.Format(", {0} ", Math.Round(difference.TotalSeconds * 100.0) / 100.0); lastInterval = interval; } CLULogger.Log(spell.Key + " intervals: "); Logging.Write(" " + output); } }
/// <summary>This will: loop assemblies, /// loop types, /// filter types that are a subclass of RotationBase and not the abstract, /// create an instance of a RotationBase subclass so we can interigate KeySpell within the RotationBase subclass, /// Check if the character has the Keyspell, /// Set the active rotation to the matching RotationBase subclass.</summary> private void QueryClassTree() { try { Type type = typeof(RotationBase); //no need to get ALL Assemblies, need only the executed ones IEnumerable <Type> types = Assembly.GetExecutingAssembly().GetTypes().Where(p => p.IsSubclassOf(type)); //_rotations.AddRange(new TypeLoader<RotationBase>(null)); this._rotations = new List <RotationBase>(); foreach (Type x in types) { ConstructorInfo constructorInfo = x.GetConstructor(new Type[] { }); if (constructorInfo != null) { var rb = constructorInfo.Invoke(new object[] { }) as RotationBase; if (rb != null && SpellManager.HasSpell(rb.KeySpellId)) { CLULogger.TroubleshootLog(" Using " + rb.Name + " rotation. Character has " + rb.KeySpell); this._rotations.Add(rb); } else { if (rb != null) { //TroubleshootLog(" Skipping " + rb.Name + " rotation. Character is missing " + rb.KeySpell); } } } } // If there is more than one rotation then display the selector for the user, otherwise just load the one and only. if (this._rotations.Count > 1) { string value = "null"; if ( GUIHelpers.RotationSelector ("[CLU] " + Version + " Rotation Selector", this._rotations, "Please select your prefered rotation:", ref value) == DialogResult.OK) { this.SetActiveRotation(this._rotations.First(x => value != null && x.Name == value)); } } else { if (this._rotations.Count == 0) { CLULogger.Log("Couldn't finde a rotation for you, Contact us!"); StopBot("Unable to find Active Rotation"); } else { RotationBase r = this._rotations.FirstOrDefault(); if (r != null) { CLULogger.Log("Found rotation: " + r.Name); this.SetActiveRotation(r); } } } } catch (ReflectionTypeLoadException ex) { var sb = new StringBuilder(); foreach (Exception exSub in ex.LoaderExceptions) { sb.AppendLine(exSub.Message); if (exSub is FileNotFoundException) { var exFileNotFound = exSub as FileNotFoundException; if (!string.IsNullOrEmpty(exFileNotFound.FusionLog)) { sb.AppendLine("CLU Log:"); sb.AppendLine(exFileNotFound.FusionLog); } } sb.AppendLine(); } string errorMessage = sb.ToString(); CLULogger.Log(" Woops, we could not set the rotation."); CLULogger.Log(errorMessage); StopBot(" Unable to find Active Rotation: " + ex); } }
/// <summary> /// Main MultiCastMacro call: checks if MultiCastMacro MT or FT is active, also checks for LoS and if we can cast the specified spell /// If zero(0) is present: return to primary or previous rotation /// If one(1) is present: run MT or FT then return to primary or previous rotation /// </summary> public static void isMultiCastMacroInUse() { using (StyxWoW.Memory.AcquireFrame()) { try { MultiCastMacroMT = Lua.GetReturnVal <int>("return MultiCastMT", 0); MultiCastMacroFT = Lua.GetReturnVal <int>("return MultiCastFT", 0); whatSpell = Lua.GetReturnVal <String>("return spellName", 0); } catch { CLULogger.DiagnosticLog("Lua failed in Macro.isMultiCastMacroInUse"); } } if (MultiCastMacroMT > 0 || MultiCastMacroFT > 0) { if (whatSpell == null) { CLULogger.Log("Please enter a spell!"); resetAllMacros(); } else { SpellManager.Spells.TryGetValue(whatSpell, out _Spell); if (!_Spell.IsValid) { CLULogger.Log("Can't Cast Spell, invalid!"); resetAllMacros(); } if (_Spell.CooldownTimeLeft > SpellManager.GlobalCooldownLeft) { CLULogger.Log("Can't Cast Spell, on CD!"); resetAllMacros(); } } } if (MultiCastMacroMT > 0) { if (SpellManager.GlobalCooldown || Me.IsCasting) { return; } if (Me.CurrentTarget.InLineOfSight) { if (SpellManager.CanCast(whatSpell)) { try { Lua.DoString("RunMacroText(\"/cast " + whatSpell + "\")"); } catch { CLULogger.DiagnosticLog("Lua failed in Macro.isMultiCastMacroInUse"); } SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location); CLULogger.Log("Casting " + whatSpell); resetMacro("MultiCastMT"); } } else { resetMacro("MultiCastMT"); } } else if (MultiCastMacroFT > 0) { if (SpellManager.GlobalCooldown || Me.IsCasting) { return; } if (Me.FocusedUnit.InLineOfSight) { if (SpellManager.CanCast(whatSpell)) { try { Lua.DoString("RunMacroText(\"/cast [@focus] " + whatSpell + "\")"); } catch { CLULogger.DiagnosticLog("Lua failed in Macro.isMultiCastMacroInUse"); } SpellManager.ClickRemoteLocation(Me.FocusedUnit.Location); CLULogger.Log("Casting " + whatSpell); resetMacro("MultiCastFT"); } } else { resetMacro("MultiCastFT"); } } }
public static Composite CreateDefaultRestBehaviour() { return // Don't f*****g run the rest behavior (or any other) if we're dead or a ghost. Thats all. (new Decorator( ret => !StyxWoW.Me.IsDead && !StyxWoW.Me.IsGhost && !StyxWoW.Me.IsCasting && CLUSettings.Instance.EnableMovement && BotPoi.Current.Type != PoiType.Loot, new PrioritySelector( // Make sure we wait out res sickness. F**k the classes that can deal with it. :O new Decorator( ret => StyxWoW.Me.HasAura("Resurrection Sickness"), new Action(ret => { })), // Wait while cannibalizing new Decorator( ret => StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Cannibalize" && (StyxWoW.Me.HealthPercent < 95 || (StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent < 95)), new Sequence( new Action(ret => CLULogger.Log("Waiting for Cannibalize")), new ActionAlwaysSucceed())), // Cannibalize support goes before drinking/eating new Decorator( ret => (StyxWoW.Me.HealthPercent <= CLUSettings.Instance.MinHealth || (StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent <= CLUSettings.Instance.MinMana)) && SpellManager.CanCast("Cannibalize") && CorpseAround, new Sequence( new Action(ret => Navigator.PlayerMover.MoveStop()), Spell.CreateWaitForLagDuration(), new Action(ret => SpellManager.Cast("Cannibalize")), new WaitContinue(1, ret => false, new ActionAlwaysSucceed()))), // Check if we're allowed to eat (and make sure we have some food. Don't bother going further if we have none. new Decorator( ret => !StyxWoW.Me.IsSwimming && StyxWoW.Me.HealthPercent <= CLUSettings.Instance.MinHealth && !StyxWoW.Me.HasAura("Food") && Consumable.GetBestFood(false) != null && !StyxWoW.Me.IsCasting, new PrioritySelector( new Decorator( ret => StyxWoW.Me.IsMoving, new Action(ret => Navigator.PlayerMover.MoveStop())), new Sequence( new Action( ret => { Styx.CommonBot.Rest.FeedImmediate(); }), Spell.CreateWaitForLagDuration()))), // Make sure we're a class with mana, if not, just ignore drinking all together! Other than that... same for food. new Decorator( ret => // TODO: Does this Druid check need to be still in here? !StyxWoW.Me.IsSwimming && (StyxWoW.Me.PowerType == WoWPowerType.Mana || StyxWoW.Me.Class == WoWClass.Druid) && StyxWoW.Me.ManaPercent <= CLUSettings.Instance.MinMana && !StyxWoW.Me.HasAura("Drink") && Consumable.GetBestDrink(false) != null && !StyxWoW.Me.IsCasting, new PrioritySelector( new Decorator( ret => StyxWoW.Me.IsMoving, new Action(ret => Navigator.PlayerMover.MoveStop())), new Sequence( new Action(ret => { Styx.CommonBot.Rest.DrinkImmediate(); }), Spell.CreateWaitForLagDuration()))), // This is to ensure we STAY SEATED while eating/drinking. No reason for us to get up before we have to. new Decorator( ret => (StyxWoW.Me.HasAura("Food") && StyxWoW.Me.HealthPercent < 95) || (StyxWoW.Me.HasAura("Drink") && StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent < 95), new ActionAlwaysSucceed()), new Decorator( ret => ((StyxWoW.Me.PowerType == WoWPowerType.Mana && StyxWoW.Me.ManaPercent <= CLUSettings.Instance.MinMana) || StyxWoW.Me.HealthPercent <= CLUSettings.Instance.MinHealth) && !StyxWoW.Me.CurrentMap.IsBattleground, new Action(ret => CLULogger.Log("We have no food/drink. Waiting to recover our health/mana back"))) ))); }