Edit: I've now been running heroics for a few days with with IB and this CC, and I consider it mature and the best hpally healbot available, but that's just me
.
I've been running my 75~ paladin through dungeons as holy spec with this, with InstanceBuddy. It probably has some issues but has been completing VH/DTK reasonably.
Most of the thresholds are harcoded, and furthermore it does not use the AoE heal because it was driving me oom, so thats commented out. It will also only beacon the tank (as defined by lfd roles).

I've been running my 75~ paladin through dungeons as holy spec with this, with InstanceBuddy. It probably has some issues but has been completing VH/DTK reasonably.
Most of the thresholds are harcoded, and furthermore it does not use the AoE heal because it was driving me oom, so thats commented out. It will also only beacon the tank (as defined by lfd roles).
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Styx.Combat.CombatRoutine;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.Logic.Combat;
using Styx.Helpers;
using Styx.Logic.Pathing;
using Styx;
using Styx.Logic;
using System.Threading;
using TreeSharp;
using Action = TreeSharp.Action;
namespace HolyPvE
{
class HolyPvE : CombatRoutine
{
private WoWUnit lastCast;
private WoWUnit tank;
private Random rng;
private void Log(params string[] list)
{
string msg = "[" + DateTime.Now.ToString("hh:mm:ss") + "] ";
foreach (string s in list)
{
msg += s + " ";
}
Logging.Write(msg);
}
public override void Combat()
{
if (Me != null && Me.IsValid && Me.IsAlive && Me.IsInInstance)
{
ObjectManager.Update();
tank = GetTank();
if (tank == null)
{
tank = Me;
}
if (StyxWoW.GlobalCooldown || CancelHeal())
{
//Log("gcd/cancelheal");
return;
}
else if (Self())
{
//Log("self");
return;
}
else if (Healing())
{
//Log("heal");
return;
}
else if (Cleansing())
{
//Log("cleanse");
return;
}
else if (Judge())
{
//Log("judge");
return;
}
else if (Buff())
{
//Log("buff");
return;
}
else
{
//Log("nothing");
}
}
}
private bool Judge()
{
//if (!isAuraActive("Judgements of the Pure"))
//{
WoWUnit u = (from unit in ObjectManager.GetObjectsOfType<WoWUnit>(false, false)
where unit.IsHostile
where !unit.Dead
where unit.CurrentTargetGuid == tank.Guid
where unit.Distance < 20
where unit.InLineOfSight
select unit
).FirstOrDefault();
if (u != null && CC("Judgement", u))
{
C("Judgement", u);
return true;
}
//}
return false;
}
private bool MoveTo(WoWUnit u)
{
if (rng == null)
{
rng = new Random();
}
if (!Me.IsMoving && u != null && u.Distance > 10)
{
Navigator.MoveTo(WoWMathHelper.CalculatePointAtSide(u.Location, u.Rotation, rng.Next(10), rng.Next(2) == 1));
return true;
}
else
{
return false;
}
}
private bool CancelHeal()
{
if (Me.IsCasting && (lastCast != null && !lastCast.Dead && lastCast.HealthPercent >= 85))
{
lastCast = null;
SpellManager.StopCasting();
return true;
}
else if (Me.IsCasting)
{
return true;
}
else
{
return false;
}
}
private WoWPlayer GetTank()
{
foreach (WoWPlayer p in Me.PartyMembers)
{
if (IsTank(p))
{
return p;
}
}
return null;
}
private string DeUnicodify(string s)
{
StringBuilder sb = new StringBuilder();
byte[] bytes = Encoding.UTF8.GetBytes(s);
foreach (byte b in bytes)
{
if (b != 0)
sb.Append("\\" + b);
}
return sb.ToString();
}
private bool IsTank(WoWPlayer p)
{
return Lua.GetReturnValues("return UnitGroupRolesAssigned('" + DeUnicodify(p.Name) + "')").First() == "TANK";
}
private bool Self()
{
if (Me.HealthPercent < 50 && CC("Divine Shield") && !isAuraActive("Forbearance"))
{
C("Divine Shield");
return true;
}
else if (Me.ManaPercent <= 75 && CC("Divine Plea"))
{
C("Divine Plea");
return true;
}
else
{
return false;
}
}
private bool Healing()
{
WoWPlayer tar = GetHealTarget();
if (tar != null)
{
if (tar.Distance > 40 || !tar.InLineOfSight)
{
MoveTo(tar);
return true;
}
else
{
String s = null;
bool needCast = false;
double hp = tar.HealthPercent;
if (Me.Combat && hp < 50 &&
((!isAuraActive("Divine Favor") && CC("Divine Favor")) ||
(!isAuraActive("Aura Mastery") && CC("Aura Mastery")) ||
(!isAuraActive("Avenging Wrath") && CC("Avenging Wrath")))
)
{
Log("Anti-Wipe mode engaged!");
ChainSpells("Divine Favor", "Aura Mastery", "Avenging Wrath");
}
if (hp < 30 && !tar.ActiveAuras.ContainsKey("Forbearance") && CC("Lay on Hands", tar))
{
s = "Lay on Hands";
}
else if (hp < 30 && tar.Guid != tank.Guid && !tar.ActiveAuras.ContainsKey("Forbearance") && CC("Hand of Protection", tar))
{
s = "Hand of Protection";
}
else if (tar.Guid == tank.Guid && BeaconNeedsRefresh(tank))
{
s = "Beacon of Light";
}
else if (Me.CurrentHolyPower == 3)
{
s = "Word of Glory";
}
else if (CC("Holy Shock", tar))
{
s = "Holy Shock";
}
else if (Me.IsMoving)
{
WoWMovement.MoveStop();
Log("Stopping movement");
return true;
}
else if (isAuraActive("Infusion of Light") || isAuraActive("Speed of Light"))
{
s = "Holy Light";
needCast = true;
}
else if (hp < 50)
{
s = "Flash of Light";
needCast = true;
}
else
{
s = "Holy Light";
needCast = true;
}
if (s != null && CC(s, tar))
{
C(s, tar);
if (!needCast)
{
MoveTo(tar);
}
return true;
}
else
{
MoveTo(tar);
return false;
}
}
}
else
{
return false;
}
}
private bool CC(string spell, WoWUnit target)
{
return SpellManager.CanCast(spell, target);
}
private bool CC(string spell)
{
return SpellManager.CanCast(spell);
}
private void ChainSpells(params string[] spells)
{
string macro = "";
foreach (string s in spells)
{
macro += "CastSpellByName(\"" + s + "\", true);";
}
Lua.DoString(macro);
}
private bool C(string spell, WoWUnit target)
{
if (SpellManager.Cast(spell, target))
{
Log(spell + " @ " + target);
lastCast = target;
return true;
}
else
{
return false;
}
}
private bool C(string spell)
{
lastCast = null;
Log("Self-cast: " + spell);
return SpellManager.Cast(spell);
}
private bool Cleansing()
{
WoWPlayer p = GetCleanseTarget();
if (p != null)
{
if (p.Distance > 40 || !p.InLineOfSight)
{
MoveTo(p);
return true;
}
else if (CC("Cleanse", p))
{
C("Cleanse", p);
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
private WoWPlayer GetCleanseTarget()
{
return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
orderby unit.HealthPercent ascending
where !unit.Dead
where !unit.IsGhost
where unit.Distance < 80
where NeedsCleanse(unit)
select unit).FirstOrDefault();
}
private bool NeedsCleanse(WoWPlayer p)
{
foreach (WoWAura a in p.ActiveAuras.Values)
{
if (a.IsHarmful)
{
WoWDispelType t = a.Spell.DispelType;
if (t == WoWDispelType.Disease || t == WoWDispelType.Magic || t == WoWDispelType.Poison)
{
return true;
}
}
}
return false;
}
private WoWPlayer GetHealTarget()
{
return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
orderby unit.HealthPercent ascending
where !unit.Dead
where !unit.IsGhost
where unit.Distance < 80
where unit.HealthPercent < 85
select unit).FirstOrDefault();
}
private IEnumerable<WoWPlayer> GetResurrectTargets()
{
return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(false, false)
orderby unit.Distance ascending
where unit.Dead
where unit.IsInMyPartyOrRaid
where !unit.IsGhost
where unit.Distance < 100
select unit);
}
private bool Resurrecting()
{
foreach(WoWPlayer p in GetResurrectTargets())
{
if(Blacklist.Contains(p.Guid, true))
{
continue;
}
else
{
if (p.Distance > 40 || !p.InLineOfSight)
{
MoveTo(p);
return true;
}
else if (CC("Redemption", p) && C("Redemption", p))
{
Blacklist.Add(p, new TimeSpan(0, 0, 15));
return true;
}
else
{
return false;
}
}
}
return false;
}
private bool Buff()
{
if (Resurrecting())
{
return true;
}
if (!isAuraActive("Seal of Insight"))
{
C("Seal of Insight");
return true;
}
if (!IsPaladinAura("Concentration Aura"))
{
C("Concentration Aura");
return true;
}
if (BeaconNeedsRefresh(tank))
{
C("Beacon of Light", tank);
return true;
}
foreach (WoWPlayer p in Me.PartyMembers)
{
if (p.Distance < 0 || p.Distance > 40 || p.Dead || p.IsGhost)
continue;
if (isAuraActive("Mark of the Wild", p) && !isAuraActive("Blessing of Might", p))
{
C("Blessing of Might", p);
return true;
}
else if (isAuraActive("Blessing of Kings", p) && !isAuraActive("Blessing of Might", p) && p.ActiveAuras["Blessing of Kings"].CreatorGuid != Me.Guid)
{
C("Blessing of Might", p);
return true;
}
else if (!isAuraActive("Blessing of Kings", p) && !isAuraActive("Mark of the Wild", p))
{
C("Blessing of Kings", p);
return true;
}
}
return false;
}
private bool isAuraActive(string name)
{
return isAuraActive(name, Me);
}
private bool isAuraActive(string name, WoWUnit u)
{
return u.ActiveAuras.ContainsKey(name);
}
private bool BeaconNeedsRefresh(WoWUnit u)
{
if (isAuraActive("Beacon of Light", u))
{
return u.ActiveAuras["Beacon of Light"].TimeLeft.TotalSeconds <= 5;
}
else
{
return true;
}
}
private bool IsPaladinAura(string aura)
{
string s = Lua.GetReturnVal<string>("return UnitAura(\"player\", \"" + aura + "\")", 0);
return s != null;
}
public override sealed string Name { get { return "HolyPvE"; } }
public override WoWClass Class { get { return WoWClass.Paladin; } }
private static LocalPlayer Me { get { return ObjectManager.Me; } }
public override bool NeedRest { get { return false; } }
public override bool NeedPullBuffs { get { Combat(); return false; } }
public override bool NeedCombatBuffs { get { Combat(); return false; } }
public override bool NeedPreCombatBuffs { get { Combat(); return false; } }
}
}
Last edited: