/// <summary>Creates an interrupt spell cast composite. This attempts to use spells in order of range (shortest to longest). /// behavior consists only of spells that apply to current toon based upon class, spec, and race /// </summary> public static Composite CreateInterruptBehavior() { if ( SingularSettings.Instance.InterruptTarget == CheckTargets.None ) return new ActionAlwaysFail(); Composite actionSelectTarget; if (SingularSettings.Instance.InterruptTarget == CheckTargets.Current) actionSelectTarget = new Action( ret => { WoWUnit u = Me.CurrentTarget; _unitInterrupt = IsInterruptTarget(u) ? u : null; if (_unitInterrupt != null && SingularSettings.Debug) Logger.WriteDebug("Possible Interrupt Target: {0} @ {1:F1} yds casting {2} #{3} for {4} ms", _unitInterrupt.SafeName(), _unitInterrupt.Distance, _unitInterrupt.CastingSpell.Name, _unitInterrupt.CastingSpell.Id, _unitInterrupt.CurrentCastTimeLeft.TotalMilliseconds ); } ); else // if ( SingularSettings.Instance.InterruptTarget == InterruptType.All ) { actionSelectTarget = new Action( ret => { _unitInterrupt = Unit.NearbyUnitsInCombatWithMeOrMyStuff.Where(u => IsInterruptTarget(u)).OrderBy( u => u.Distance ).FirstOrDefault(); if (_unitInterrupt != null && SingularSettings.Debug) Logger.WriteDebug("Possible Interrupt Target: {0} @ {1:F1} yds casting {2} #{3} for {4} ms", _unitInterrupt.SafeName(), _unitInterrupt.Distance, _unitInterrupt.CastingSpell.Name, _unitInterrupt.CastingSpell.Id, _unitInterrupt.CurrentCastTimeLeft.TotalMilliseconds); } ); } PrioritySelector prioSpell = new PrioritySelector(); #region Pet Spells First! if (Me.Class == WoWClass.Warlock) { // this will be either a Optical Blast or Spell Lock prioSpell.AddChild( Spell.Cast( "Command Demon", on => _unitInterrupt, ret => _unitInterrupt != null && _unitInterrupt.Distance < 40 && Singular.ClassSpecific.Warlock.Common.GetCurrentPet() == WarlockPet.Felhunter ) ); } #endregion #region Melee Range if ( Me.Class == WoWClass.Paladin ) prioSpell.AddChild( Spell.Cast("Rebuke", ctx => _unitInterrupt)); if ( Me.Class == WoWClass.Rogue) { prioSpell.AddChild( Spell.Cast("Kick", ctx => _unitInterrupt)); prioSpell.AddChild( Spell.Cast("Gouge", ctx => _unitInterrupt, ret => !_unitInterrupt.IsBoss() && Me.IsSafelyFacing(_unitInterrupt))); } if ( Me.Class == WoWClass.Warrior) prioSpell.AddChild( Spell.Cast("Pummel", ctx => _unitInterrupt)); if ( Me.Class == WoWClass.Monk ) prioSpell.AddChild( Spell.Cast("Spear Hand Strike", ctx => _unitInterrupt)); if ( Me.Class == WoWClass.Druid) { // Spell.Cast("Skull Bash (Cat)", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Cat)); // Spell.Cast("Skull Bash (Bear)", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Bear)); prioSpell.AddChild( Spell.Cast("Skull Bash", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Bear || StyxWoW.Me.Shapeshift == ShapeshiftForm.Cat)); prioSpell.AddChild( Spell.Cast("Mighty Bash", ctx => _unitInterrupt, ret => !_unitInterrupt.IsBoss() && _unitInterrupt.IsWithinMeleeRange)); } if ( Me.Class == WoWClass.DeathKnight) prioSpell.AddChild( Spell.Cast("Mind Freeze", ctx => _unitInterrupt)); if ( Me.Race == WoWRace.Pandaren ) prioSpell.AddChild( Spell.Cast("Quaking Palm", ctx => _unitInterrupt)); #endregion #region 8 Yard Range if ( Me.Race == WoWRace.BloodElf ) prioSpell.AddChild(Spell.Cast("Arcane Torrent", ctx => _unitInterrupt, req => _unitInterrupt.Distance < 8 && !Unit.NearbyUnfriendlyUnits.Any(u => u.IsSensitiveDamage( 8)))); if ( Me.Race == WoWRace.Tauren) prioSpell.AddChild(Spell.Cast("War Stomp", ctx => _unitInterrupt, ret => _unitInterrupt.Distance < 8 && !_unitInterrupt.IsBoss() && !Unit.NearbyUnfriendlyUnits.Any(u => u.IsSensitiveDamage( 8)))); #endregion #region 10 Yards if (Me.Class == WoWClass.Paladin) prioSpell.AddChild( Spell.Cast("Hammer of Justice", ctx => _unitInterrupt)); if (Me.Specialization == WoWSpec.DruidBalance ) prioSpell.AddChild( Spell.Cast("Hammer of Justice", ctx => _unitInterrupt)); if (Me.Class == WoWClass.Warrior) prioSpell.AddChild( Spell.Cast("Disrupting Shout", ctx => _unitInterrupt)); #endregion #region 25 yards if ( Me.Class == WoWClass.Shaman) prioSpell.AddChild( Spell.Cast("Wind Shear", ctx => _unitInterrupt, req => Me.IsSafelyFacing(_unitInterrupt))); #endregion #region 30 yards if (Me.Specialization == WoWSpec.PaladinProtection) prioSpell.AddChild( Spell.Cast("Avenger's Shield", ctx => _unitInterrupt)); if (Me.Class == WoWClass.Shaman) // Gag Order only works on non-bosses due to it being a silence, not an interrupt! prioSpell.AddChild( Spell.Cast("Heroic Throw", ctx => _unitInterrupt, ret => TalentManager.HasGlyph("Gag Order") && !_unitInterrupt.IsBoss())); if ( Me.Class == WoWClass.Priest ) prioSpell.AddChild( Spell.Cast("Silence", ctx => _unitInterrupt)); if (Me.Class == WoWClass.DeathKnight) prioSpell.AddChild(Spell.Cast("Strangulate", ctx => _unitInterrupt)); if (Me.Class == WoWClass.Mage) prioSpell.AddChild(Spell.Cast("Frostjaw", ctx => _unitInterrupt)); #endregion #region 40 yards if ( Me.Class == WoWClass.Mage) prioSpell.AddChild( Spell.Cast("Counterspell", ctx => _unitInterrupt)); if ( Me.Class == WoWClass.Hunter) prioSpell.AddChild( Spell.Cast("Silencing Shot", ctx => _unitInterrupt)); if ( Me.Class == WoWClass.Druid) prioSpell.AddChild( Spell.Cast("Solar Beam", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Moonkin)); if (Me.Specialization == WoWSpec.ShamanElemental || Me.Specialization == WoWSpec.ShamanEnhancement ) prioSpell.AddChild( Spell.Cast("Solar Beam", ctx => _unitInterrupt, ret => true)); #endregion return new Throttle( new Sequence( actionSelectTarget, new Decorator( ret => _unitInterrupt != null, // majority of these are off GCD, so throttle all to avoid most fail messages new Throttle( TimeSpan.FromMilliseconds(500), prioSpell ) ) ) ); }
/// <summary>Creates an interrupt spell cast composite. This attempts to use spells in order of range (shortest to longest). /// behavior consists only of spells that apply to current toon based upon class, spec, and race /// </summary> public static Composite CreateInterruptBehavior() { Composite actionSelectTarget; if (Me.CurrentTarget != null) { actionSelectTarget = new Action( ret => { WoWUnit u = Me.CurrentTarget; _unitInterrupt = IsInterruptTarget(u) ? u : null; if (_unitInterrupt != null) { Logging.WriteDiagnostic("Possible Interrupt Target: {0} @ {1:F1} yds casting {2} #{3} for {4} ms", _unitInterrupt.SafeName(), _unitInterrupt.Distance, _unitInterrupt.CastingSpell.Name, _unitInterrupt.CastingSpell.Id, _unitInterrupt.CurrentCastTimeLeft.TotalMilliseconds); } } ); } else // if ( SingularSettings.Instance.InterruptTarget == InterruptType.All ) { actionSelectTarget = new Action( ret => { _unitInterrupt = Unit.NearbyUnfriendlyUnits.Where(u => IsInterruptTarget(u)).OrderBy(u => u.Distance).FirstOrDefault(); if (_unitInterrupt != null) { Logging.WriteDiagnostic("Possible Interrupt Target: {0} @ {1:F1} yds casting {2} #{3} for {4} ms", _unitInterrupt.SafeName(), _unitInterrupt.Distance, _unitInterrupt.CastingSpell.Name, _unitInterrupt.CastingSpell.Id, _unitInterrupt.CurrentCastTimeLeft.TotalMilliseconds); } } ); } PrioritySelector prioSpell = new PrioritySelector(); #region Pet Spells First! if (Me.Class == WoWClass.Warlock) { // this will be either a Optical Blast or Spell Lock prioSpell.AddChild( Spell.Cast( "Command Demon", on => _unitInterrupt, ret => _unitInterrupt != null && _unitInterrupt.Distance < 40 ) ); } #endregion #region Melee Range if (Me.Class == WoWClass.Paladin) { prioSpell.AddChild(Spell.Cast("Rebuke", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Rogue) { prioSpell.AddChild(Spell.Cast("Kick", ctx => _unitInterrupt, true)); prioSpell.AddChild(Spell.Cast("Gouge", ctx => _unitInterrupt, ret => !_unitInterrupt.IsBoss() && Me.IsSafelyFacing(_unitInterrupt))); } if (Me.Class == WoWClass.Warrior) { prioSpell.AddChild(Spell.Cast("Pummel", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Monk) { prioSpell.AddChild(Spell.Cast("Spear Hand Strike", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Druid) { // Spell.Cast("Skull Bash (Cat)", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Cat)); // Spell.Cast("Skull Bash (Bear)", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Bear)); prioSpell.AddChild(Spell.Cast("Skull Bash", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Bear || StyxWoW.Me.Shapeshift == ShapeshiftForm.Cat, true)); prioSpell.AddChild(Spell.Cast("Mighty Bash", ctx => _unitInterrupt, ret => !_unitInterrupt.IsBoss() && _unitInterrupt.IsWithinMeleeRange)); } if (Me.Class == WoWClass.DeathKnight) { prioSpell.AddChild(Spell.Cast("Mind Freeze", ctx => _unitInterrupt, true)); } if (Me.Race == WoWRace.Pandaren) { prioSpell.AddChild(Spell.Cast("Quaking Palm", ctx => _unitInterrupt)); } #endregion #region 8 Yard Range if (Me.Race == WoWRace.BloodElf) { prioSpell.AddChild(Spell.Cast("Arcane Torrent", ctx => _unitInterrupt, req => _unitInterrupt.Distance < 8 && !Unit.NearbyUnfriendlyUnits.Any(u => u.IsSensitiveDamage(8f)), true)); } if (Me.Race == WoWRace.Tauren) { prioSpell.AddChild(Spell.Cast("War Stomp", ctx => _unitInterrupt, ret => _unitInterrupt.Distance < 8 && !_unitInterrupt.IsBoss() && !Unit.NearbyUnfriendlyUnits.Any(u => u.IsSensitiveDamage(8f)))); } #endregion #region 10 Yards if (Me.Class == WoWClass.Paladin) { prioSpell.AddChild(Spell.Cast("Hammer of Justice", ctx => _unitInterrupt)); } if (Me.Specialization == WoWSpec.DruidBalance) { prioSpell.AddChild(Spell.Cast("Hammer of Justice", ctx => _unitInterrupt)); } if (Me.Class == WoWClass.Warrior) { prioSpell.AddChild(Spell.Cast("Disrupting Shout", ctx => _unitInterrupt, true)); } #endregion #region 25 yards if (Me.Class == WoWClass.Shaman) { prioSpell.AddChild(Spell.Cast("Wind Shear", ctx => _unitInterrupt, req => Me.IsSafelyFacing(_unitInterrupt), true)); } #endregion #region 30 yards if (Me.Specialization == WoWSpec.PaladinProtection) { prioSpell.AddChild(Spell.Cast("Avenger's Shield", ctx => _unitInterrupt)); } if (Me.Class == WoWClass.Shaman) { // Gag Order only works on non-bosses due to it being a silence, not an interrupt! prioSpell.AddChild(Spell.Cast("Heroic Throw", ctx => _unitInterrupt, ret => TalentManager.HasGlyph("Gag Order") && !_unitInterrupt.IsBoss())); } if (Me.Class == WoWClass.Priest) { prioSpell.AddChild(Spell.Cast("Silence", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.DeathKnight) { prioSpell.AddChild(Spell.Cast("Strangulate", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Mage) { prioSpell.AddChild(Spell.Cast("Frostjaw", ctx => _unitInterrupt)); } #endregion #region 40 yards if (Me.Class == WoWClass.Mage) { prioSpell.AddChild(Spell.Cast("Counterspell", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Hunter) { prioSpell.AddChild(Spell.Cast("Silencing Shot", ctx => _unitInterrupt, true)); } if (Me.Class == WoWClass.Druid) { prioSpell.AddChild(Spell.Cast("Solar Beam", ctx => _unitInterrupt, ret => StyxWoW.Me.Shapeshift == ShapeshiftForm.Moonkin, true)); } if (Me.Specialization == WoWSpec.ShamanElemental || Me.Specialization == WoWSpec.ShamanEnhancement) { prioSpell.AddChild(Spell.Cast("Solar Beam", ctx => _unitInterrupt, true)); } #endregion return(new Sequence( actionSelectTarget, new Decorator( ret => _unitInterrupt != null, // majority of these are off GCD, so throttle all to avoid most fail messages new Throttle(TimeSpan.FromMilliseconds(500), prioSpell) ) )); }