Blood Death Knightt
Introduction
This custom class is built around the Raid Bot, this can be found here: http://www.thebuddyforum.com/honorb...45436-botbase-raidbot-30fps-cc-execution.html. I have used Noxxic.com, Elitist Jerks, MMO Champion to get the best rotation and priority order.
This custom class does not pop Anti-Magic Shield, or interrupt spells so you will have to do that manually.
It also does not taunt as in DS most groups use 2 tanks and I didn't want it taunting off the other.
Media
I have used this in LFR and got feedback from Healers that I was a good tank.
Source - Last Update: 27th February 2012 @ 19:48PM - Reason: Nearby unfriendly unit changes
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Styx.Combat.CombatRoutine;
using TreeSharp;
using CommonBehaviors.Actions;
using Styx;
using Styx.Logic.Combat;
using Styx.WoWInternals.WoWObjects;
using Styx.Logic.Pathing;
using Styx.Helpers;
using System.Drawing;
using Styx.WoWInternals;
namespace RaidBot
{
public class DeathKnightBloodRoutine : CombatRoutine
{
//
// Damage Reduction
private const int DEATH_PACT_HEALTH = 60;
private const int DEATH_COIL_HEALTH = 70;
private const int VAMPIRIC_BLOOD_HEALTH = 40;
private const int ICEBOUND_FORTITUDE_HEALTH = 30;
private const int EMPOWER_RUNE_WEAPON_EMERGENCY_HEALTH = 40;
private const int DEATH_STRIKE_HEALTH = 90;
//
// Army of the Dead
private const int ARMY_OF_THE_DEAD_HEALTH = 60;
#region Delegates
public delegate WoWUnit UnitSelectionDelegate(object context);
public delegate bool SimpleBooleanDelegate(object context);
public delegate WoWPoint LocationRetriverDelegate(object context);
#endregion
public override WoWClass Class
{
get { return WoWClass.DeathKnight; }
}
public override string Name
{
get { return "Blood DeathKnight"; }
}
private Composite _root;
public override Composite CombatBehavior
{
get
{
return _root ?? (_root = GetCombatBehavior());
}
}
private Composite GetCombatBehavior()
{
return new PrioritySelector(
EnsureTarget(),
//
// Healing Cooldowns
Cast("Death Pact", ret => StyxWoW.Me.HealthPercent < DEATH_PACT_HEALTH && StyxWoW.Me.GotAlivePet),
Cast("Rune Tap", ret => StyxWoW.Me.HealthPercent < 90 || StyxWoW.Me.ActiveAuras.ContainsKey("Will of the Necropolis")),
Cast("Death Coil", ret => StyxWoW.Me, ctx => StyxWoW.Me.HealthPercent < DEATH_COIL_HEALTH && StyxWoW.Me.ActiveAuras.ContainsKey("Lichborne")),
//
// Threat Cooldowns
Cast("Dancing Rune Weapon", ret => NearbyUnfriendlyUnits().Count() > 2),
//
// Damage Reduction Cooldowns
Cast("Bone Shield"), // Keep Bone Shield on CD
Cast("Vampiric Blood", ret => StyxWoW.Me.HealthPercent < VAMPIRIC_BLOOD_HEALTH),
Cast("Lichborne", ret => StyxWoW.Me.HealthPercent < DEATH_COIL_HEALTH && StyxWoW.Me.CurrentRunicPower >= 60),
Cast("Raise Dead", ret => StyxWoW.Me.HealthPercent < DEATH_PACT_HEALTH),
Cast("Icebound Fortitude", ret => StyxWoW.Me.HealthPercent < ICEBOUND_FORTITUDE_HEALTH),
Cast("Empower Rune Weapon", ret => StyxWoW.Me.HealthPercent < EMPOWER_RUNE_WEAPON_EMERGENCY_HEALTH && !SpellManager.CanCast("Death Strike")),
//
// Army of the Dead
Cast("Army of the Dead", ret => StyxWoW.Me.HealthPercent < ARMY_OF_THE_DEAD_HEALTH),
Cast("Outbreak", ret => !HasMyAuraTimeLeft(StyxWoW.Me.CurrentTarget, "Frost Fever", 1) || !HasMyAuraTimeLeft(StyxWoW.Me.CurrentTarget, "Blood Plague", 1)),
new Decorator(ret => NearbyUnfriendlyUnits(15f).Count() > 2,
new PrioritySelector(
CastOnGround("Death and Decay", ret => StyxWoW.Me.CurrentTarget.Location),
Cast("Pestilence", ret => HasMyAuraTimeLeft(StyxWoW.Me.CurrentTarget, "Frost Fever", 1) && HasMyAuraTimeLeft(StyxWoW.Me.CurrentTarget, "Blood Plague", 1) &&
NearbyUnfriendlyUnits(10f).Count(u => !HasMyAuraTimeLeft(u, "Frost Fever", 1) && !HasMyAuraTimeLeft(u, "Blood Plague", 1)) > 0),
Cast("Death Strike", ret =>
StyxWoW.Me.UnholyRuneCount + StyxWoW.Me.FrostRuneCount + StyxWoW.Me.DeathRuneCount >= 4
|| StyxWoW.Me.HealthPercent < 90 && !StyxWoW.Me.ActiveAuras.ContainsKey("Blood Shield")
|| StyxWoW.Me.HealthPercent < DEATH_STRIKE_HEALTH
),
new Decorator(ret => NearbyUnfriendlyUnits(15f).Count() > 3,
Cast("Blood Boil", ret => StyxWoW.Me.BloodRuneCount >= 1)
),
new Decorator(ret => NearbyUnfriendlyUnits(15f).Count() == 3,
Cast("Heart Strike", ret => StyxWoW.Me.BloodRuneCount == 2)
),
Cast("Rune Strike", ret => (StyxWoW.Me.CurrentRunicPower >= 60 || StyxWoW.Me.HealthPercent > 90) && ((StyxWoW.Me.UnholyRuneCount == 0 || StyxWoW.Me.FrostRuneCount == 0) && StyxWoW.Me.DeathRuneCount == 0))
)
),
new Decorator(ret => NearbyUnfriendlyUnits(15f).Count() <= 2,
new PrioritySelector(
Cast("Death Strike", ret =>
StyxWoW.Me.UnholyRuneCount + StyxWoW.Me.FrostRuneCount + StyxWoW.Me.DeathRuneCount >= 4
|| StyxWoW.Me.HealthPercent < 90 && !StyxWoW.Me.ActiveAuras.ContainsKey("Blood Shield")
|| StyxWoW.Me.HealthPercent < DEATH_STRIKE_HEALTH
),
Cast("Heart Strike", ret => StyxWoW.Me.BloodRuneCount == 2),
Cast("Rune Strike", ret => (StyxWoW.Me.CurrentRunicPower >= 60 || StyxWoW.Me.HealthPercent > 90) && ((StyxWoW.Me.UnholyRuneCount == 0 || StyxWoW.Me.FrostRuneCount == 0) && StyxWoW.Me.DeathRuneCount == 0))
)
)
);
}
public Composite Cast(string spellName)
{
return Cast(spellName, ret => StyxWoW.Me.CurrentTarget);
}
public Composite Cast(string spellName, UnitSelectionDelegate unit)
{
return Cast(spellName, unit, ret => true);
}
public Composite Cast(string spellName, SimpleBooleanDelegate requirement)
{
return Cast(spellName, ret => StyxWoW.Me.CurrentTarget, requirement);
}
public Composite Cast(string spellName, UnitSelectionDelegate unit, SimpleBooleanDelegate requirement)
{
return new Decorator(
ctx => SpellManager.CanCast(SpellManager.Spells[spellName], unit(ctx), false, false, true) && requirement(ctx),
new TreeSharp.Action(
ret =>
{
Logging.Write(Color.Crimson, "Spell Cast[{0}]", spellName);
SpellManager.Cast(spellName, unit(ret));
}
)
);
}
public Composite CastOnGround(string spellName, LocationRetriverDelegate onLocation)
{
return CastOnGround(spellName, onLocation, ret => true);
}
public Composite CastOnGround(string spellName, LocationRetriverDelegate onLocation, SimpleBooleanDelegate requirement)
{
return new Decorator(
ret =>
requirement(ret) && onLocation != null && SpellManager.CanCast(spellName)
&& (StyxWoW.Me.Location.Distance(onLocation(ret)) <= SpellManager.Spells[spellName].MaxRange || SpellManager.Spells[spellName].MaxRange == 0),
new Sequence(
new TreeSharp.Action(ret => SpellManager.Cast(spellName)),
new WaitContinue(1, ret => StyxWoW.Me.CurrentPendingCursorSpell != null && StyxWoW.Me.CurrentPendingCursorSpell.Name == spellName, new ActionAlwaysSucceed()),
new TreeSharp.Action(ret => LegacySpellManager.ClickRemoteLocation(onLocation(ret)))
)
);
}
public Composite EnsureTarget()
{
return new Decorator(ctx => StyxWoW.Me.CurrentTarget == null, new ActionAlwaysSucceed());
}
public bool HasMyAuraTimeLeft(WoWUnit unit, string aura, int timeLeft)
{
return unit.GetAllAuras().Any(a => a.Name == aura && a.CreatorGuid == StyxWoW.Me.Guid && a.TimeLeft.TotalSeconds > timeLeft);
}
public IEnumerable<WoWUnit> NearbyUnfriendlyUnits()
{
return NearbyUnfriendlyUnits(12f);
}
public IEnumerable<WoWUnit> NearbyUnfriendlyUnits(float distance)
{
var dist = distance * distance;
return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
p => ValidUnit(p) && p.Location.DistanceSqr(StyxWoW.Me.Location) <= dist).ToList();
}
private bool ValidUnit(WoWUnit p)
{
if (!p.CanSelect || !p.Attackable)
return false;
if (p.IsFriendly)
return false;
if (p.Dead)
return false;
if (p.IsPet || p.OwnedByRoot != null)
return false;
if (p.IsNonCombatPet || p.IsCritter)
return false;
return true;
}
}
}
Credits
- Singular Developers
- Apoc
Last edited: