//private static WoWUnit _moveToHealTarget = null; //private static WoWUnit _lastMoveToTarget = null; public static Composite CreateHolyHealOnlyBehavior(bool selfOnly, bool moveInRange) { if (SingularRoutine.CurrentWoWContext == WoWContext.Normal) { return(new ActionAlwaysFail()); } HealerManager.NeedHealTargeting = true; PrioritizedBehaviorList behavs = new PrioritizedBehaviorList(); int cancelHeal = Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, Math.Max(PriestSettings.HolyHeal.Heal, PriestSettings.HolyHeal.Renew)); Logger.WriteDebugInBehaviorCreate("Priest Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal); if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None) { int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999; behavs.AddBehavior(dispelPriority, "Dispel", null, Common.CreatePriestDispelBehavior()); } #region Save the Group if (PriestSettings.HolyHeal.DivineHymn != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.HolyHeal.DivineHymn) + 300, "Divine Hymn @ " + PriestSettings.HolyHeal.DivineHymn + "% MinCount: " + PriestSettings.HolyHeal.CountDivineHymn, "Divine Hymn", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Divine Hymn", PriestSettings.HolyHeal.DivineHymn, 0, 40, PriestSettings.HolyHeal.CountDivineHymn), new Decorator( ret => ret != null, Spell.Cast("Divine Hymn", mov => false, on => (WoWUnit)on, req => true, cancel => false) ) ) ) ); } if (PriestSettings.HolyHeal.GuardianSpirit != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.HolyHeal.GuardianSpirit) + 300, "Guardian Spirit @ " + PriestSettings.HolyHeal.GuardianSpirit + "%", "Guardian Spirit", Spell.Cast("Guardian Spirit", mov => false, on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.HolyHeal.GuardianSpirit ) ); } if (PriestSettings.LightOfTuure != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.LightOfTuure) + 300, "Light of T'uure @ " + PriestSettings.LightOfTuure + "%", "Light of T'uure", Spell.Cast("Light of T'uure", mov => false, on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.LightOfTuure && !((WoWUnit)req).HasAura("Light of T'uure") && Group.Tanks.Contains(((WoWUnit)req)) ) ); } #endregion #region AoE Heals int maxDirectHeal = Math.Max(PriestSettings.HolyHeal.FlashHeal, PriestSettings.HolyHeal.Heal); // instant, so cast this first ALWAYS if (PriestSettings.HolyHeal.HolyWordSanctify != 0) { behavs.AddBehavior(398, "Holy Word: Sanctify @ " + PriestSettings.HolyHeal.HolyWordSanctify + "% MinCount: " + PriestSettings.HolyHeal.CountHolyWordSanctify, "Holy Word: Sanctify", new Decorator( ret => true, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Holy Word: Sanctify", PriestSettings.HolyHeal.HolyWordSanctify, 40, 10, PriestSettings.HolyHeal.CountHolyWordSanctify), new Decorator( ret => ret != null, Spell.CastOnGround("Holy Word: Sanctify", on => (WoWUnit)on, req => true, false) ) ) ) ); } if (PriestSettings.HolyHeal.PrayerOfMending != 0) { behavs.AddBehavior(397, "Prayer of Mending @ " + PriestSettings.HolyHeal.PrayerOfMending + "%", "Prayer of Mending", Spell.Cast("Prayer of Mending", mov => true, on => (WoWUnit)on, req => !((WoWUnit)req).IsMe && ((WoWUnit)req).HealthPercent <PriestSettings.HolyHeal.PrayerOfMending, cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal ) ); } /* * behavs.AddBehavior(HealthToPriority(PriestSettings.HolyHeal.HolyLevel90Talent) + 200, "Divine Star", * "Divine Star", * new Decorator( * ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, * new Decorator( * ret => * Clusters.GetClusterCount(Me, * HealerManager.Instance.TargetList.Where( * u => u.HealthPercent < PriestSettings.HolyHeal.CountLevel90Talent).ToList(), * ClusterType.PathToUnit, 4) >= PriestSettings.HolyHeal.CountLevel90Talent, * Spell.Cast("Divine Star", on => (WoWUnit)on, req => true) * ) * ) * ); */ if (PriestSettings.HolyHeal.HolyLevel90Talent != 0) { behavs.AddBehavior(397, "Halo @ " + PriestSettings.HolyHeal.HolyLevel90Talent + "% MinCount: " + PriestSettings.HolyHeal.CountLevel90Talent, "Halo", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new Decorator( ret => ret != null && HealerManager.Instance.TargetList.Count( u => u.IsAlive && u.HealthPercent < PriestSettings.HolyHeal.HolyLevel90Talent && u.Distance < 30) >= PriestSettings.HolyHeal.CountLevel90Talent && Unit.UnfriendlyUnits(30).Any(u => u.Combat && !u.IsCrowdControlled()), Spell.Cast("Halo", req => true) ) ) ); } if (PriestSettings.HolyHeal.BindingHeal != 0) { behavs.AddBehavior(396, "Binding Heal @ " + PriestSettings.HolyHeal.BindingHeal + "% MinCount: 2", "Binding Heal", Spell.Cast("Binding Heal", mov => true, on => (WoWUnit)on, req => !((WoWUnit)req).IsMe && ((WoWUnit)req).HealthPercent < PriestSettings.HolyHeal.BindingHeal && Me.HealthPercent <PriestSettings.HolyHeal.BindingHeal, cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal ) ); } if (PriestSettings.HolyHeal.CircleOfHealing != 0) { behavs.AddBehavior(395, "Circle of Healing @ " + PriestSettings.HolyHeal.CircleOfHealing + "% MinCount: " + PriestSettings.HolyHeal.CountCircleOfHealing, "Circle of Healing", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Circle of Healing", PriestSettings.HolyHeal.CircleOfHealing, 40, 30, PriestSettings.HolyHeal.CountCircleOfHealing), Spell.Cast("Circle of Healing", on => (WoWUnit)on) ) ) ); } if (PriestSettings.HolyHeal.PrayerOfHealing != 0) { behavs.AddBehavior(394, "Prayer of Healing @ " + PriestSettings.HolyHeal.PrayerOfHealing + "% MinCount: " + PriestSettings.HolyHeal.CountPrayerOfHealing, "Prayer of Healing", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Prayer of Healing", PriestSettings.HolyHeal.PrayerOfHealing, 40, 20, PriestSettings.HolyHeal.CountPrayerOfHealing), Spell.Cast("Prayer of Healing", on => (WoWUnit)on) ) ) ); } #endregion /* * HolyWordSanctify Holy Word: Sanctify * HolyWordSerenity Holy Word: Serenity * CircleOfHealing Circle of Healing * PrayerOfHealing Prayer of Healing * DivineHymn Divine Hymn * GuardianSpirit Guardian Spirit * VoidShift Void Shift */ #region Direct Heals if (maxDirectHeal != 0) // Nuke a Flash Heal { behavs.AddBehavior(400, "Surge of Light @ " + maxDirectHeal + "%", "Flash Heal", Spell.Cast("Flash Heal", mov => false, on => (WoWUnit)on, req => Me.HasActiveAura("Surge of Light") && ((WoWUnit)req).HealthPercent < 85 ) ); } if (PriestSettings.HolyHeal.HolyWordSerenity != 0) { behavs.AddBehavior(HealthToPriority(1) + 4, "Holy Word: Serenity @ " + PriestSettings.HolyHeal.HolyWordSerenity + "%", "Holy Word: Serenity", Spell.CastHack("Holy Word: Serenity", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.HolyHeal.HolyWordSerenity ) ); } var cmt = ""; var flashHealHealth = PriestSettings.HolyHeal.FlashHeal; if (!SpellManager.HasSpell("Heal")) { flashHealHealth = Math.Max(flashHealHealth, PriestSettings.HolyHeal.Heal); cmt = "(Adjusted for Heal)"; } if (flashHealHealth != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.HolyHeal.FlashHeal), "Flash Heal @ " + flashHealHealth + "% " + cmt, "Flash Heal", Spell.Cast("Flash Heal", mov => true, on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent <flashHealHealth, cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal ) ); } if (PriestSettings.HolyHeal.Heal != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.HolyHeal.Heal), "Heal @ " + PriestSettings.HolyHeal.Heal + "%", "Heal", Spell.Cast("Heal", mov => true, on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent <PriestSettings.HolyHeal.Heal, cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal ) ); } #endregion #region Tank - Low Priority Buffs if (PriestSettings.HolyHeal.Renew != 0) { behavs.AddBehavior(HealthToPriority(102), "Tank - Buff Renew @ " + PriestSettings.HolyHeal.Renew + "%", "Renew", // roll Renew on Tanks Spell.Cast("Renew", on => { WoWUnit unit = HealerManager.GetBestTankTargetForHOT("Renew", PriestSettings.HolyHeal.Renew); if (unit != null && Spell.CanCastHack("Renew", unit, skipWowCheck: true)) { Logger.WriteDebug("Buffing RENEW ON TANK: {0}", unit.SafeName()); return(unit); } return(null); }) ); } #endregion #region Lowest Priority Healer Tasks if (SingularRoutine.CurrentWoWContext == WoWContext.Instances) { behavs.AddBehavior(HealthToPriority(103), "Lightwell", "Lightwell", new Throttle(TimeSpan.FromSeconds(20), new Sequence( new Action(r => { _lightwellTarget = Group.Tanks.FirstOrDefault(t => { if (t.IsAlive && t.Combat && t.GotTarget() && t.CurrentTarget.IsBoss()) { if (t.Distance < 40 && t.SpellDistance(t.CurrentTarget) < 15) { Logger.WriteDiagnostic("Lightwell: found target {0}", t.SafeName()); return(true); } } return(false); }); return(_lightwellTarget == null ? RunStatus.Failure : RunStatus.Success); }), Spell.CastOnGround("Lightwell", location => WoWMathHelper.CalculatePointFrom(Me.Location, _lightwellTarget.Location, (float)Math.Min(10.0, _lightwellTarget.Distance / 2)), req => _lightwellTarget != null, false, desc => string.Format("10 yds from {0}", _lightwellTarget.SafeName()) ) ) ) ); } #endregion behavs.OrderBehaviors(); if (selfOnly == false && CompositeBuilder.CurrentBehaviorType == BehaviorType.Combat) { behavs.ListBehaviors(); } return(new PrioritySelector( ctx => selfOnly ? StyxWoW.Me : HealerManager.FindLowestHealthTarget(), // HealerManager.Instance.FirstUnit, Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown() && ret != null, behavs.GenerateBehaviorTree() ), new Decorator( ret => moveInRange, Movement.CreateMoveToUnitBehavior( ret => Battlegrounds.IsInsideBattleground ? (WoWUnit)ret : Group.Tanks.Where(a => a.IsAlive).OrderBy(a => a.Distance).FirstOrDefault(), 35f ) ) )); }
public static Composite CreateDiscHealOnlyBehavior() { if (SingularRoutine.CurrentWoWContext == WoWContext.Normal) { return(new ActionAlwaysFail()); } HealerManager.NeedHealTargeting = true; PrioritizedBehaviorList behavs = new PrioritizedBehaviorList(); int cancelHeal = (int)Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, PriestSettings.DiscHeal.Heal); cancelHeal = (int)Math.Max(cancelHeal, PriestSettings.DiscHeal.FlashHeal); Logger.WriteDebugInBehaviorCreate("Priest Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal); if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None) { int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999; behavs.AddBehavior(dispelPriority, "Dispel", null, Common.CreatePriestDispelBehavior()); } #region Save the Group behavs.AddBehavior(HealthToPriority(PriestSettings.DiscHeal.PainSuppression) + PriEmergencyBase, "Pain Suppression @ " + PriestSettings.DiscHeal.PainSuppression + "%", "Pain Suppression", new Decorator( req => Me.Combat, Spell.Cast("Pain Suppression", mov => false, on => (WoWUnit)on, req => ((WoWUnit)req).IsPlayer && ((WoWUnit)req).HealthPercent < PriestSettings.DiscHeal.PainSuppression ) ) ); behavs.AddBehavior(HealthToPriority(PriestSettings.DiscHeal.PowerWordBarrier) + PriEmergencyBase, "Power Word: Barrier @ " + PriestSettings.DiscHeal.PowerWordBarrier + "%", "Power Word: Barrier", new Decorator( ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid), new PrioritySelector( context => GetBestPowerWordBarrierTarget(), new Decorator( ret => ret != null, new PrioritySelector( new Sequence( new Action(r => Logger.WriteDebug("PW:B - attempting cast")), Spell.CastOnGround("Power Word: Barrier", on => (WoWUnit)on, req => true, false) ), new Action(ret => { if (ret != null) { if (!((WoWUnit)ret).IsValid) { Logger.WriteDebug("PW:B - FAILED - Healing Target object became invalid"); } else if (((WoWUnit)ret).Distance > 40) { Logger.WriteDebug("PW:B - FAILED - Healing Target moved out of range"); } else if (!Spell.CanCastHack("Power Word: Barrier")) { Logger.WriteDebug("PW:B - FAILED - Spell.CanCastHack() said NO to Power Word: Barrier"); } else if (GameWorld.IsInLineOfSpellSight(StyxWoW.Me.GetTraceLinePos(), ((WoWUnit)ret).Location)) { Logger.WriteDebug("PW:B - FAILED - Spell.CanCastHack() unit location not in Line of Sight"); } else if (Spell.IsSpellOnCooldown("Power Word: Barrier")) { Logger.WriteDebug("PW:B - FAILED - Power Word: Barrier is on cooldown"); } else { Logger.WriteDebug("PW:B - Something FAILED with Power Word: Barrier cast sequence (target={0}, h={1:F1}%, d={2:F1} yds, spellmax={3:F1} yds, cooldown={4})", ((WoWUnit)ret).SafeName(), ((WoWUnit)ret).HealthPercent, ((WoWUnit)ret).Distance, Spell.ActualMaxRange("Power Word: Barrier", (WoWUnit)ret), Spell.IsSpellOnCooldown("Power Word: Barrier") ); } } return(RunStatus.Failure); }) ) ) ) ) ); #endregion #region Tank Buffing behavs.AddBehavior(HealthToPriority(99) + PriHighBase, "Power Word: Shield - Tank", "Power Word: Shield", new Decorator( req => Me.Combat, Spell.Buff( "Power Word: Shield", on => Group.Tanks .FirstOrDefault(u => u.IsAlive && CanWePwsUnit(u) && Spell.CanCastHack("Power Word: Shield", u)) ) ) ); behavs.AddBehavior(HealthToPriority(99) + PriHighBase, "Plea - Tank Attonement", "Plea", new Decorator( req => Me.Combat, Spell.Cast( "Plea", on => Group.Tanks .FirstOrDefault(u => u.IsAlive && !u.HasActiveAura("Atonement") && Spell.CanCastHack("Plea", u)) ) ) ); #endregion #region Save the Highest Priority Targets const int SaveEssential = 30; behavs.AddBehavior(HealthToPriority(SaveEssential) + PriSaveEssential, "Save Highest Priority Target below " + SaveEssential + "%", "Shadow Mend", new Decorator( req => Me.Combat, new PrioritySelector( ctx => HealerManager.FindHighestPriorityTarget(), Spell.HandleOffGCD(Spell.Buff("Power Infusion", on => Me, req => req != null, gcd: HasGcd.No)), Spell.Buff( "Power Word: Shield", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.DiscHeal.PowerWordShield && CanWePwsUnit((WoWUnit)req) ), Spell.Cast( "Plea", on => (WoWUnit)on, req => !((WoWUnit)req).HasActiveAura("Atonement") ), Spell.Cast( "Shadow Mend", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.DiscHeal.ShadowMend ) ) ) ); #endregion #region AoE Heals if (PriestSettings.DiscHeal.DiscLevel90Talent != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.DiscHeal.DiscLevel90Talent) + PriAoeBase, "Halo @ " + PriestSettings.DiscHeal.DiscLevel90Talent + "% MinCount: " + PriestSettings.DiscHeal.CountLevel90Talent, "Halo", new Decorator( ret => SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds || SingularRoutine.CurrentWoWContext == WoWContext.Instances, new Decorator( ret => ret != null && HealerManager.Instance.TargetList.Count(u => u.IsAlive && u.HealthPercent < PriestSettings.DiscHeal.DiscLevel90Talent && u.Distance < 30) >= PriestSettings.DiscHeal.CountLevel90Talent && Spell.CanCastHack("Halo", (WoWUnit)ret), new PrioritySelector( Spell.HandleOffGCD(Spell.BuffSelf("Archangel", req => ((WoWUnit)req) != null && Me.HasAura("Evangelism", 5))), Spell.CastOnGround("Halo", on => (WoWUnit)on, req => true) ) ) ) ); } if (PriestSettings.DiscHeal.DiscLevel90Talent != 0) { behavs.AddBehavior(HealthToPriority(PriestSettings.DiscHeal.DiscLevel90Talent) + PriAoeBase, "Cascade @ " + PriestSettings.DiscHeal.DiscLevel90Talent + "% MinCount: " + PriestSettings.DiscHeal.CountLevel90Talent, "Cascade", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Cascade", PriestSettings.DiscHeal.DiscLevel90Talent, 40, 30, PriestSettings.DiscHeal.CountLevel90Talent), new Decorator( ret => ret != null && Spell.CanCastHack("Cascade", (WoWUnit)ret), new PrioritySelector( Spell.HandleOffGCD(Spell.BuffSelf("Archangel", req => Me.HasAura("Evangelism", 5))), Spell.Cast("Cascade", mov => true, on => (WoWUnit)on, req => true) ) ) ) ) ); } if (PriestSettings.DiscHeal.PowerWordRadiance != 0) { behavs.AddBehavior(99 + PriAoeBase, "Power Word: Radiance", "Power Word: Radiance", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => HealerManager.GetBestCoverageTarget("Power Word: Radiance", PriestSettings.DiscHeal.PowerWordRadiance, 40, 30, PriestSettings.DiscHeal.CountPowerWordRadiance, o => o != null && !((WoWUnit)o).HasActiveAura("Atonement")), CastBuffsBehavior("Power Word: Radiance"), Spell.Cast("Power Word: Radiance", on => (WoWUnit)on) ) ) ); } #endregion #region Direct Heals if (PriestSettings.DiscHeal.Plea != 0) { behavs.AddBehavior(100 + PriSingleBase, "Atonement Plea @ " + PriestSettings.DiscHeal.Plea + "%", "Plea", new Decorator( req => !((WoWUnit)req).HasActiveAura("Atonement"), new PrioritySelector( CastBuffsBehavior("Plea"), Spell.Cast("Plea", mov => false, on => (WoWUnit)on, req => true, cancel => false ) ) ) ); } if (HasReflectiveShield) { behavs.AddBehavior(100 + PriSingleBase, "Power Word: Shield Self (Glyph of Reflective Shield)", "Power Word: Shield", Spell.BuffSelf("Power Word: Shield", req => CanWePwsUnit(Me) && Unit.NearbyUnitsInCombatWithUsOrOurStuff.Any()) ); } if (PriestSettings.DiscHeal.PowerWordShield != 0) { behavs.AddBehavior(99 + PriSingleBase, "Power Word: Shield @ " + PriestSettings.DiscHeal.PowerWordShield + "%", "Power Word: Shield", Spell.Buff("Power Word: Shield", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < PriestSettings.DiscHeal.PowerWordShield && CanWePwsUnit((WoWUnit)req)) ); } #endregion behavs.OrderBehaviors(); behavs.ListBehaviors(); return(new PrioritySelector( ctx => HealerManager.FindHighestPriorityTarget(), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown() && ret != null, behavs.GenerateBehaviorTree() ) )); }