Exemple #1
0
        public static Composite CreateRestoDruidPull()
        {
            return(new PrioritySelector(
                       HealerManager.CreateStayNearTankBehavior(),
                       new Decorator(
                           req => !HealerManager.Instance.TargetList.Any(h => h.IsAlive && !h.IsMe && h.Distance < 40),
                           new PrioritySelector(
                               Helpers.Common.EnsureReadyToAttackFromLongRange(),
                               Spell.WaitForCastOrChannel(),
                               new Decorator(
                                   req => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(
                                       Helpers.Common.CreateInterruptBehavior(),

                                       Movement.WaitForFacing(),
                                       Movement.WaitForLineOfSpellSight(),

                                       Spell.Buff("Moonfire"),
                                       Spell.Cast("Wrath"),
                                       Movement.CreateMoveToUnitBehavior(on => Me.CurrentTarget, 35f, 30f)
                                       )
                                   )
                               )
                           )
                       ));
        }
        public static Composite CreateHolyHeal()
        {
            return(new PrioritySelector(
                       CreateHolyDiagnosticOutputBehavior("HEAL"),

                       HealerManager.CreateStayNearTankBehavior(),
                       // Group heals
                       new Decorator(
                           ret => Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),
                           CreateHolyHealOnlyBehavior(false, true)
                           ),

                       // Solo heals
                       new Decorator(
                           ret => !Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),
                           new PrioritySelector(
                               Spell.Cast("Desperate Prayer", ret => Me, ret => Me.Combat && Me.HealthPercent < PriestSettings.DesperatePrayerHealth),

                               // keep heal buffs on if glyphed
                               Spell.BuffSelf("Prayer of Mending", ret => Me.Combat && Me.HealthPercent <= 90),
                               Spell.BuffSelf("Renew", ret => Me.Combat && Me.HealthPercent <= 95),

                               Common.CreatePsychicScreamBehavior(),

                               Spell.Cast("Flash Heal",
                                          ctx => Me,
                                          ret => Me.HealthPercent <= PriestSettings.ShadowHeal),

                               Spell.Cast("Flash Heal",
                                          ctx => Me,
                                          ret => !Me.Combat && Me.PredictedHealthPercent(includeMyHeals: true) <= 90)
                               )
                           )));
        }
Exemple #3
0
        public static Composite CreateMistweaverCombatBehaviorBattlegrounds()
        {
            return(new Decorator(
                       ret => !Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),

                       new PrioritySelector(

                           CreateMistWeaverDiagnosticOutputBehavior(on => MyHealTarget),

                           CancelSoothingMistAsNeeded(),

                           HealerManager.CreateMeleeHealerMovementBehavior(),

                           new Decorator(
                               req => HealerManager.AllowHealerDPS(),

                               new PrioritySelector(

                                   CreateMistweaverMoveToEnemyTarget(),

                                   new Decorator(
                                       ret => !Spell.IsGlobalCooldown(),
                                       new PrioritySelector(

                                           new Decorator(
                                               req => Me.GotTarget() && Me.CurrentTarget.IsWithinMeleeRange,
                                               Helpers.Common.CreateAutoAttack()
                                               ),

                                           Helpers.Common.CreateInterruptBehavior(),

                                           Spell.Cast("Paralysis",
                                                      onu => Unit.NearbyUnfriendlyUnits
                                                      .FirstOrDefault(u => u.IsCasting && u.Distance.Between(9, 20) && Me.IsSafelyFacing(u))),

                                           Spell.Cast("Leg Sweep", ret => Spell.UseAOE && SingularRoutine.CurrentWoWContext == WoWContext.Normal && Me.CurrentTarget.IsWithinMeleeRange),

                                           Spell.Cast(SpinningCraneKick, ret => Spell.UseAOE && Unit.NearbyUnfriendlyUnits.Count(u => u.Distance <= 8) >= MonkSettings.SpinningCraneKickCnt),

                                           Spell.Cast("Rising Sun Kick"),
                                           Spell.Cast("Blackout Kick", req => Me.GetAuraStacks("Teachings of the Monastery") >= 3),
                                           Spell.Cast("Tiger Palm")
                                           )
                                       ),

                                   Spell.Cast("Roll", ret => MovementManager.IsClassMovementAllowed && !MonkSettings.DisableRoll && Me.CurrentTarget.Distance > minDistRollAllowed)
                                   )
                               ),

                           new Decorator(
                               ret => Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),
                               new PrioritySelector(
                                   CreateMistweaverMonkHealing(selfOnly: false),
                                   Helpers.Common.CreateInterruptBehavior()
                                   )
                               )
                           )
                       ));
        }
Exemple #4
0
 public static Composite CreateDiscOutOfCombatHeal()
 {
     return(new Decorator(
                ret => !Spell.IsGlobalCooldown(),
                new PrioritySelector(ctx => HealerManager.FindLowestHealthTarget(),
                                     Spell.Cast("Flash Heal", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < 95),
                                     Spell.Cast("Plea", mov => false, on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < 100)
                                     )
                ));
 }
Exemple #5
0
        public static Composite CreateRestoDruidHealBehavior()
        {
            return(new PrioritySelector(
                       CreateRestoDiagnosticOutputBehavior(),

                       HealerManager.CreateStayNearTankBehavior(),

                       new Decorator(
                           ret => HealerManager.Instance.TargetList.Any(h => h.Distance < 40 && h.IsAlive && !h.IsMe),
                           new PrioritySelector(
                               CreateRestoDruidHealOnlyBehavior()
                               )
                           )
                       ));
        }
Exemple #6
0
        public static Composite CreateRestoShamanCombatBehaviorBattlegrounds()
        {
            return(new PrioritySelector(

                       Spell.WaitForCastOrChannel(),

                       CreateRestoDiagnosticOutputBehavior(on => HealerManager.Instance.FirstUnit),

                       new Decorator(
                           ret => !Spell.IsGlobalCooldown() && HealerManager.Instance.TargetList.Any(t => !t.IsMe && t.IsAlive),
                           new PrioritySelector(
                               HealerManager.CreateStayNearTankBehavior(),
                               CreateRestoShamanHealingOnlyBehavior(selfOnly: false)
                               )
                           ),

                       new Decorator(
                           ret => !Spell.IsGlobalCooldown() && HealerManager.AllowHealerDPS(),
                           new PrioritySelector(

                               Helpers.Common.EnsureReadyToAttackFromMediumRange(),

                               Spell.WaitForCastOrChannel(),

                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(

                                       Helpers.Common.CreateInterruptBehavior(),
                                       Totems.CreateTotemsBehavior(),

                                       Movement.WaitForFacing(),
                                       Movement.WaitForLineOfSpellSight(),

                                       Dispelling.CreatePurgeEnemyBehavior("Purge"),

                                       Common.CastElementalBlast(),
                                       Spell.Buff("Flame Shock", 3, on => Me.CurrentTarget, req => true),
                                       Spell.Cast("Lava Burst"),
                                       Spell.Cast("Frost Shock"),
                                       Spell.Cast("Chain Lightning", ret => Spell.UseAOE && Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2 && !Unit.UnfriendlyUnitsNearTarget(12f).Any(u => u.IsCrowdControlled())),
                                       Spell.Cast("Lightning Bolt")
                                       )
                                   )
                               )
                           )
                       ));
        }
Exemple #7
0
        public static Composite CreateRestoDruidCombat()
        {
            return(new PrioritySelector(
                       HealerManager.CreateStayNearTankBehavior(),
                       new Decorator(
                           req => HealerManager.AllowHealerDPS(),
                           new PrioritySelector(
                               Helpers.Common.EnsureReadyToAttackFromLongRange(),
                               Spell.WaitForCastOrChannel(),
                               new Decorator(
                                   req => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(
                                       Helpers.Common.CreateInterruptBehavior(),

                                       Movement.WaitForFacing(),
                                       Movement.WaitForLineOfSpellSight(),

                                       Common.CastForm(ShapeshiftForm.Moonkin, req => Common.HasTalent(DruidTalents.BalanceAffinity) && Me.Shapeshift != ShapeshiftForm.Moonkin && !Utilities.EventHandlers.IsShapeshiftSuppressed),

                                       Spell.Cast("Moonfire", on => Unit.NearbyUnitsInCombatWithUsOrOurStuff.FirstOrDefault(u => u.GetAuraTimeLeft("Moonfire").TotalSeconds < 1.8 && u.TimeToDeath(int.MaxValue) > 4)),
                                       Spell.Cast("Sunfire", on => Unit.NearbyUnitsInCombatWithUsOrOurStuff.FirstOrDefault(u => u.GetAuraTimeLeft("Sunfire").TotalSeconds < 1.8 && u.TimeToDeath(int.MaxValue) > 4)),
                                       Spell.Cast(
                                           "Starsurge",
                                           on => Unit.UnitsInCombatWithUsOrOurStuff(40).Where(u => !u.IsCrowdControlled() && u.InLineOfSpellSight).OrderByDescending(u => (uint)u.HealthPercent).FirstOrDefault(),
                                           req => true,
                                           cancel => HealerManager.CancelHealerDPS()
                                           ),
                                       Spell.Cast(
                                           "Lunar Strike",
                                           on => Unit.UnitsInCombatWithUsOrOurStuff(40).Where(u => !u.IsCrowdControlled() && u.InLineOfSpellSight).OrderByDescending(u => (uint)u.HealthPercent).FirstOrDefault(),
                                           req => true,
                                           cancel => HealerManager.CancelHealerDPS()
                                           ),
                                       Spell.Cast(
                                           "Solar Wrath",
                                           on => Unit.UnitsInCombatWithUsOrOurStuff(40).Where(u => !u.IsCrowdControlled() && u.InLineOfSpellSight).OrderByDescending(u => (uint)u.HealthPercent).FirstOrDefault(),
                                           req => true,
                                           cancel => HealerManager.CancelHealerDPS()
                                           )
                                       )
                                   )
                               )
                           )
                       ));
        }
        public static Composite CreateHolyCombat()
        {
            return(new PrioritySelector(
                       new Decorator(
                           ret => HealerManager.AllowHealerDPS(),
                           new PrioritySelector(
                               Helpers.Common.EnsureReadyToAttackFromMediumRange(),
                               Spell.WaitForCastOrChannel(),

                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(

                                       Helpers.Common.CreateInterruptBehavior(),

                                       Movement.WaitForFacing(),
                                       Movement.WaitForLineOfSpellSight(),

                                       Dispelling.CreatePurgeEnemyBehavior("Dispel Magic"),
                                       Spell.Buff("Shadow Word: Pain", true),
                                       Spell.Buff("Holy Word: Chastise"),
                                       Spell.Buff("Shadow Word: Pain", true, on =>
            {
                WoWUnit unit = Unit.NearbyUnfriendlyUnits
                               .FirstOrDefault(
                    u => (u.TaggedByMe || u.Aggro) &&
                    u.Guid != Me.CurrentTargetGuid &&
                    u.IsTargetingMeOrPet &&
                    !u.HasMyAura("Shadow Word: Pain") &&
                    !u.IsCrowdControlled()
                    );
                return unit;
            }),
                                       Common.CreateHolyFireBehavior(),
                                       Spell.Cast("Smite", mov => true, on => Me.CurrentTarget, req => true, cancel => HealerManager.CancelHealerDPS())
                                       )
                                   )
                               )
                           )
                       ));
        }
Exemple #9
0
        /// <summary>
        /// non-combat heal to top people off and avoid lifebloom, buffs, etc.
        /// </summary>
        /// <param name="selfOnly"></param>
        /// <returns></returns>
        public static Composite CreateRestoNonCombatHeal(bool selfOnly = false)
        {
            return(new PrioritySelector(
                       ctx => selfOnly || !Me.IsInGroup() ? StyxWoW.Me : HealerManager.FindLowestHealthTarget(), // HealerManager.Instance.FirstUnit,

                       new Decorator(
                           req => req != null && ((WoWUnit)req).Combat && ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < SingularSettings.Instance.IgnoreHealTargetsAboveHealth,
                           CreateRestoDruidHealOnlyBehavior()
                           ),

                       new Decorator(
                           req => req != null && !((WoWUnit)req).Combat && ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < SingularSettings.Instance.IgnoreHealTargetsAboveHealth,

                           new Sequence(
                               new Action(on => Logger.WriteDebug("NonCombatHeal on {0}: health={1:F1}% predicted={2:F1}% +mine={3:F1}", ((WoWUnit)on).SafeName(), ((WoWUnit)on).HealthPercent, ((WoWUnit)on).PredictedHealthPercent(), ((WoWUnit)on).PredictedHealthPercent(includeMyHeals: true))),
                               new PrioritySelector(
                                   // BUFFS First
                                   Spell.Buff("Rejuvenation", 1, on => (WoWUnit)on, req => ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < 95),
                                   Spell.Buff("Regrowth", 1, on => (WoWUnit)on, req => !glyphRegrowth && ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < 80),

                                   // Direct Heals After
                                   Spell.Cast("Healing Touch", on => (WoWUnit)on, req => ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < 65),
                                   Spell.Cast("Regrowth", on => (WoWUnit)on, req => ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < 75),

                                   // if Moving, spread Rejuv around on those that need to be topped off
                                   new Decorator(
                                       req => Me.IsMoving,
                                       new PrioritySelector(
                                           ctx => HealerManager.Instance.TargetList.FirstOrDefault(h => h.HealthPercent < 95 && !h.HasMyAura("Rejuvenation") && Spell.CanCastHack("Rejuvenation", (WoWUnit)ctx, skipWowCheck: true)),
                                           Spell.Buff("Rejuvenation", on => (WoWUnit)on)
                                           )
                                       )
                                   )
                               )
                           )
                       ));
        }
        //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
                               )
                           )
                       ));
        }
Exemple #11
0
        public static Composite EnhancementCombat()
        {
            return(new PrioritySelector(
                       //new Decorator(ret => AdvancedAI.PvPRot,
                       //              EnhancementShamanPvP.CreateESPvPCombat),

                       Spell.Cast("Healing Stream Totem", ret => Me.HealthPercent < 80 && !Totems.Exist(WoWTotemType.Water)),
                       Spell.Cast("Healing Tide Totem", ret => HealerManager.GetCountWithHealth(55) > 6 && !Totems.Exist(WoWTotemType.Water)),

                       //burst
                       new Decorator(ret => AdvancedAI.Burst,
                                     new PrioritySelector(
                                         Spell.Cast("Stormlash Totem", ret => !Me.HasAura("Stormlash Totem")),
                                         Spell.Cast("Elemental Mastery"),
                                         Spell.Cast("Fire Elemental Totem"),
                                         Spell.Cast("Feral Spirit"),
                                         Spell.Cast("Ascendance", ret => !Me.HasAura("Ascendance")))),

                       //new Decorator(ret => Unit.UnfriendlyUnits(10).Count() >= 3,
                       //            CreateAoe()),

                       Spell.Cast("Searing Totem", ret => Me.GotTarget && Me.CurrentTarget.SpellDistance() < Totems.GetTotemRange(WoWTotem.Searing) - 2f && !Totems.Exist(WoWTotemType.Fire)),

                       Spell.Cast("Unleash Elements", ret => SpellManager.HasSpell("Unleashed Fury")),

                       Spell.Cast("Elemental Blast", ret => Me.HasAura("Maelstrom Weapon", 1)),

                       new Decorator(ret => Me.HasAura("Maelstrom Weapon", 5),
                                     new PrioritySelector(
                                         Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2),
                                         Spell.Cast("Lightning Bolt"))),

                       //StormBlast
                       new Decorator(ret => (Me.HasAura("Ascendance") && !WoWSpell.FromId(115356).Cooldown),
                                     new Action(ret => Lua.DoString("RunMacroText('/cast Stormblast')"))),

                       Spell.Cast("Stormstrike"),
                       Spell.Cast("Flame Shock", ret => Me.CachedHasAura("Unleash Flame") && !Me.CurrentTarget.HasMyAura("Flame Shock")),
                       Spell.Cast("Lava Lash"),
                       Spell.Cast("Flame Shock", ret => (Me.CachedHasAura("Unleash Flame") && Me.CurrentTarget.CachedGetAuraTimeLeft("Flame Shock") < 10) || !Me.CurrentTarget.HasMyAura("Flame Shock")),

                       Spell.Cast("Unleash Elements"),
                       new Decorator(ret => Me.HasAura("Maelstrom Weapon", 3) && !Me.HasAura("Ascendance"),
                                     new PrioritySelector(
                                         Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2),
                                         Spell.Cast("Lightning Bolt"))),
                       // need to make it at <2
                       Spell.Cast("Ancestral Swiftness", ret => !Me.HasAura("Maelstrom Weapon")),
                       Spell.Cast("Lighting Bolt", ret => Me.HasAura("Ancestral Swiftness")),
                       Spell.Cast("Earth Shock"),

                       Spell.Cast("Earth Elemental Totem", ret => Me.CurrentTarget.IsBoss && SpellManager.Spells["Fire Elemental Totem"].CooldownTimeLeft.Seconds >= 50)));

            //need more gear
            //new Decorator(ret => Me.HasAura("Maelstrom Weapon", 1) && !Me.HasAura("Ascendance"),
            //    new PrioritySelector(
            //        Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2),
            //        Spell.Cast("Lightning Bolt")
            //        )
            //    )
            //    );
        }
Exemple #12
0
        public static Composite CreateDpsShamanOffHealBehavior()
        {
            HealerManager.NeedHealTargeting = true;
            PrioritizedBehaviorList behavs = new PrioritizedBehaviorList();
            int cancelHeal = (int)Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, ShamanSettings.OffHealSettings.HealingSurge);

            bool moveInRange = (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds);

            Logger.WriteDebugInBehaviorCreate("Shaman Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal);

/*
 *          int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999;
 *          if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None)
 *              behavs.AddBehavior(dispelPriority, "Cleanse Spirit", null, Dispelling.CreateDispelBehavior());
 */
            #region Save the Group

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.OffHealSettings.AncestralSwiftness) + 500,
                               String.Format("Oh Shoot Heal @ {0}%", ShamanSettings.OffHealSettings.AncestralSwiftness),
                               null,
                               new Decorator(
                                   ret => (Me.Combat || ((WoWUnit)ret).Combat) && ((WoWUnit)ret).PredictedHealthPercent() < ShamanSettings.OffHealSettings.AncestralSwiftness,
                                   new PrioritySelector(
                                       Spell.HandleOffGCD(Spell.BuffSelf("Ancestral Swiftness")),
                                       Spell.Cast("Healing Surge", on => (WoWUnit)on)
                                       )
                                   )
                               );

            #endregion

            #region AoE Heals

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.OffHealSettings.HealingStreamTotem) + 300,
                               string.Format("Healing Stream Totem @ {0}%", ShamanSettings.OffHealSettings.HealingStreamTotem),
                               "Healing Stream Totem",
                               new Decorator(
                                   ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid,
                                   Spell.Cast(
                                       "Healing Stream Totem",
                                       on => (!Me.Combat || Totems.Exist(WoWTotemType.Water)) ? null : HealerManager.Instance.TargetList.FirstOrDefault(p => p.PredictedHealthPercent() < ShamanSettings.OffHealSettings.HealingStreamTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingStream))
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.OffHealSettings.HealingRain) + 200,
                               string.Format("Healing Rain @ {0}% Count={1}", ShamanSettings.OffHealSettings.HealingRain, ShamanSettings.OffHealSettings.MinHealingRainCount),
                               "Healing Rain",
                               Spell.CastOnGround("Healing Rain", on => Restoration.GetBestHealingRainTarget(), req => HealerManager.Instance.TargetList.Count() > 1, false)
                               );

            #endregion

            #region Single Target Heals

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.OffHealSettings.HealingSurge),
                               string.Format("Healing Surge @ {0}%", ShamanSettings.OffHealSettings.HealingSurge),
                               "Healing Surge",
                               Spell.Cast("Healing Surge",
                                          mov => true,
                                          on => (WoWUnit)on,
                                          req => ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < ShamanSettings.OffHealSettings.HealingSurge,
                                          cancel => ((WoWUnit)cancel).HealthPercent > cancelHeal
                                          )
                               );

            #endregion

            behavs.OrderBehaviors();

            if (Singular.Dynamics.CompositeBuilder.CurrentBehaviorType == BehaviorType.Heal)
            {
                behavs.ListBehaviors();
            }

            return(new PrioritySelector(
                       ctx => HealerManager.FindLowestHealthTarget(), // HealerManager.Instance.FirstUnit,

                       new Decorator(
                           ret => ret != null && (Me.Combat || ((WoWUnit)ret).Combat || ((WoWUnit)ret).PredictedHealthPercent() <= 99),

                           new PrioritySelector(
                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(

                                       Totems.CreateTotemsBehavior(),

                                       /*
                                        *                          Spell.Cast("Earth Shield",
                                        *                              ret => (WoWUnit)ret,
                                        *                              ret => ret is WoWUnit && Group.Tanks.Contains((WoWUnit)ret) && Group.Tanks.All(t => !t.HasMyAura("Earth Shield"))),
                                        */

                                       behavs.GenerateBehaviorTree(),

                                       new Decorator(
                                           ret => moveInRange,
                                           new Sequence(
                                               new Action(r => _moveToHealUnit = (WoWUnit)r),
                                               new PrioritySelector(
                                                   Movement.CreateMoveToLosBehavior(on => _moveToHealUnit),
                                                   Movement.CreateMoveToUnitBehavior(on => _moveToHealUnit, 30f, 25f)
                                                   )
                                               )
                                           )
                                       )
                                   )
                               )
                           )
                       ));
        }
Exemple #13
0
        public static Composite CreateMistweaverCombatBehaviorInstances()
        {
            return(new PrioritySelector(

                       CancelSoothingMistAsNeeded(),
                       CreateMistWeaverDiagnosticOutputBehavior(on => MyHealTarget),

                       new Decorator(
                           req => true,
                           new PrioritySelector(
                               // HealerManager.CreateMeleeHealerMovementBehavior( Common.CreateMonkCloseDistanceBehavior( min => 30, on => (WoWUnit) on)),
                               HealerManager.CreateStayNearTankBehavior(Common.CreateMonkCloseDistanceBehavior(min => 30, on => (WoWUnit)on)),

                               /*
                                *                  new Decorator(
                                *                      unit => MovementManager.IsClassMovementAllowed
                                *                          && !MonkSettings.DisableRoll
                                *                          && (unit as WoWUnit).SpellDistance() > 10
                                *                          && Me.IsSafelyFacing(unit as WoWUnit, 5f),
                                *                      Spell.Cast("Roll")
                                *                      )
                                *                  ),
                                */
                               new Decorator(
                                   ret => Me.Combat && HealerManager.AllowHealerDPS(),
                                   new PrioritySelector(

                                       CreateMistweaverMoveToEnemyTarget(),
                                       new Decorator(
                                           req => Me.GotTarget() && Me.CurrentTarget.IsAlive,
                                           Movement.CreateFaceTargetBehavior()
                                           ),

                                       Spell.WaitForCastOrChannel(),

                                       #region Spinning Crane Kick progress handler

                                       new Decorator(
                                           req => Me.HasActiveAura("Spinning Crane Kick"), // don't wait for Rushing Jade Wind since we can cast
                                           new PrioritySelector(
                                               new Action(r =>
            {
                Logger.WriteFile(SpinningCraneKick + ": in progress with {0} ms left", (long)Me.GetAuraTimeLeft(SpinningCraneKick).TotalMilliseconds);
                return RunStatus.Failure;
            }),
                                               new Decorator(
                                                   req =>
            {
                if (Me.GetAuraTimeLeft(SpinningCraneKick).TotalMilliseconds < 333)
                {
                    return false;
                }

                int countFriendly = Unit.NearbyGroupMembersAndPets.Count(u => u.SpellDistance() <= 8);
                if (countFriendly >= 3)
                {
                    return false;
                }

                if (HealerManager.CancelHealerDPS())
                {
                    Logger.Write(LogColor.Cancel, "/cancel {0} since only {1} friendly targets hit and cannot DPS", SpinningCraneKick, countFriendly);
                    return true;
                }

                int countEnemy = Unit.NearbyUnfriendlyUnits.Count(u => u.SpellDistance() <= 8);
                if ((countFriendly + countEnemy) < 3)
                {
                    Logger.Write(LogColor.Cancel, "/cancel {0} since only {1} friendly and {2} enemy targets hit", SpinningCraneKick, countFriendly, countEnemy);
                    return true;
                }
                return false;
            },
                                                   new Sequence(
                                                       new Action(r => Me.CancelAura(SpinningCraneKick)),
                                                       new Wait(1, until => !Me.HasActiveAura(SpinningCraneKick), new ActionAlwaysFail())
                                                       )
                                                   ),

                                               // dont go past here if SCK active
                                               new ActionAlwaysSucceed()
                                               )
                                           ),
                                       #endregion

                                       new Decorator(
                                           ret => !Spell.IsGlobalCooldown(),
                                           new PrioritySelector(

                                               new Decorator(
                                                   req => Me.GotTarget() && Me.CurrentTarget.IsWithinMeleeRange,
                                                   Helpers.Common.CreateAutoAttack()
                                                   ),

                                               Helpers.Common.CreateInterruptBehavior(),

                                               Spell.Cast("Leg Sweep", ret => Spell.UseAOE && SingularRoutine.CurrentWoWContext == WoWContext.Normal && Me.CurrentTarget.IsWithinMeleeRange),

                                               Spell.Cast(
                                                   SpinningCraneKick,
                                                   ret => Spell.UseAOE && HealerManager.AllowHealerDPS() && Unit.NearbyUnfriendlyUnits.Count(u => u.SpellDistance() <= 8) >= MonkSettings.SpinningCraneKickCnt
                                                   ),

                                               Spell.Cast("Rising Sun Kick"),
                                               Spell.Cast("Blackout Kick", req => Me.GetAuraStacks("Teachings of the Monastery") >= 3),
                                               Spell.Cast("Tiger Palm")
                                               )
                                           ),

                                       Spell.Cast("Roll",
                                                  req => MovementManager.IsClassMovementAllowed &&
                                                  !MonkSettings.DisableRoll &&
                                                  Me.CurrentTarget.Distance > minDistRollAllowed
                                                  )
                                       )
                                   )
                               )
                           ),

                       new Decorator(
                           ret => !Spell.IsGlobalCooldown() && Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),
                           new PrioritySelector(
                               CreateMistweaverMonkHealing(selfOnly: false),
                               new Decorator(
                                   req => true,
                                   Helpers.Common.CreateInterruptBehavior()
                                   )
                               )
                           ),

                       Spell.WaitForCastOrChannel()
                       ));
        }
Exemple #14
0
        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()
                           )
                       ));
        }
Exemple #15
0
        public static Composite CreateFeralHeal()
        {
            return(new PrioritySelector(
                       CreateFeralDiagnosticOutputBehavior("Combat"),

                       Spell.BuffSelf("Survival Instincts", req => Me.HealthPercent < DruidSettings.SurvivalInstinctsHealth),

                       Spell.Cast(
                           "Regrowth",
                           on =>
            {
                int pstime = (int)Me.GetAuraTimeLeft("Predatory Swiftness").TotalMilliseconds;
                if (pstime < 150)
                {
                    return null;
                }

                WoWUnit unit = null;
                if (Common.HasTalent(DruidTalents.Bloodtalons) && (Me.ComboPoints >= 4 || pstime < 1650))
                {
                    unit = Unit.GroupMembers
                           .Where(u => u.IsAlive && Spell.CanCastHack("Regrowth", u))
                           .OrderBy(u => (int)u.HealthPercent)
                           .FirstOrDefault();

                    if (unit == null && Spell.CanCastHack("Regrowth", Me))
                    {
                        unit = Me;
                    }

                    if (unit != null)
                    {
                        Logger.Write(LogColor.Hilite, "^Bloodtalons: buffing bleeds");
                    }

                    return unit;
                }

                // raids: don't waste a GCD on healing without a buff
                if (SingularRoutine.CurrentHealContext == HealingContext.Raids)
                {
                    return null;
                }

                // else: find lowest health unit
                unit = HealerManager.NeedHealTargeting
                            ? HealerManager.FindHighestPriorityTarget()
                            : Unit.GroupMembers
                       .Where(u => u.IsAlive && Spell.CanCastHack("Regrowth", u))
                       .OrderBy(u => (int)u.HealthPercent)
                       .FirstOrDefault();

                if (unit != null)
                {
                    if (unit.HealthPercent < DruidSettings.PredSwiftnessHealingTouchHealth)
                    {
                        return unit;
                    }
                    if (unit.HealthPercent < 90 && pstime < 1650)
                    {
                        return unit;
                    }
                    unit = null;
                }

                return unit;
            }
                           )
                       ));
        }
Exemple #16
0
        //private static WoWUnit _moveToHealTarget = null;
        //private static WoWUnit _lastMoveToTarget = null;

        // temporary lol name ... will revise after testing
        public static Composite CreateHealingOnlyBehavior(bool selfOnly, bool moveInRange)
        {
            BehaviorType behaveType = Dynamics.CompositeBuilder.CurrentBehaviorType;

            if (SingularRoutine.CurrentWoWContext == WoWContext.Normal)
            {
                return(new ActionAlwaysFail());
            }

            HealerManager.NeedHealTargeting = true;
            PrioritizedBehaviorList behavs = new PrioritizedBehaviorList();
            int cancelHeal    = (int)Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, Math.Max(DruidSettings.Heal.HealingTouch, DruidSettings.Heal.Regrowth));
            int maxDirectHeal = Math.Max(DruidSettings.Heal.HealingTouch, DruidSettings.Heal.Regrowth);

            Logger.WriteDebugInBehaviorCreate("Druid Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal);

            #region Cleanse

            if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None)
            {
                int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999;
                behavs.AddBehavior(dispelPriority, "Nature's Cure", "Nature's Cure", Dispelling.CreateDispelBehavior());
            }

            #endregion

            #region Save the Group

            // Tank: Rebirth
            if (Helpers.Common.CombatRezTargetSetting != CombatRezTarget.None)
            {
                behavs.AddBehavior(799, "Rebirth Tank/Healer", "Rebirth",
                                   Helpers.Common.CreateCombatRezBehavior("Rebirth", filter => true, requirements => true)
                                   );
            }

            if (DruidSettings.Heal.HeartOfTheWild != 0)
            {
                behavs.AddBehavior(795, "Heart of the Wild @ " + DruidSettings.Heal.HeartOfTheWild + "% MinCount: " + DruidSettings.Heal.CountHeartOfTheWild, "Heart of the Wild",
                                   new Decorator(
                                       ret => Me.IsInGroup(),
                                       Spell.BuffSelf(
                                           "Heart of the Wild",
                                           req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.HeartOfTheWild &&
                                           DruidSettings.Heal.CountHeartOfTheWild <= HealerManager.Instance.TargetList
                                           .Count(p => p.IsAlive && p.HealthPercent <= DruidSettings.Heal.HeartOfTheWild && p.Location.DistanceSquared(((WoWUnit)req).Location) <= 30 * 30)
                                           )
                                       )
                                   );
            }

            if (DruidSettings.Heal.Tranquility != 0)
            {
                behavs.AddBehavior(798, "Tranquility @ " + DruidSettings.Heal.Tranquility + "% MinCount: " + DruidSettings.Heal.CountTranquility, "Tranquility",
                                   new Decorator(
                                       ret => Me.IsInGroup(),
                                       Spell.Cast(
                                           "Tranquility",
                                           mov => true,
                                           on => (WoWUnit)on,
                                           req => HealerManager.Instance.TargetList.Count(h => h.IsAlive && h.HealthPercent < DruidSettings.Heal.Tranquility && h.SpellDistance() < 40) >= DruidSettings.Heal.CountTranquility,
                                           cancel => false
                                           )
                                       )
                                   );
            }

            if (DruidSettings.Heal.Swiftmend != 0)
            {
                behavs.AddBehavior(797, "Swiftmend Direct @ " + DruidSettings.Heal.Swiftmend + "%", "Swiftmend",
                                   new Decorator(
                                       ret => (!Spell.IsSpellOnCooldown("Swiftmend") || Spell.GetCharges("Force of Nature") > 0) &&
                                       ((WoWUnit)ret).PredictedHealthPercent(includeMyHeals: true) < DruidSettings.Heal.Swiftmend &&
                                       (Me.IsInGroup()) &&
                                       Spell.CanCastHack("Rejuvenation", (WoWUnit)ret, skipWowCheck: true),
                                       new Sequence(
                                           new DecoratorContinue(
                                               req => !((WoWUnit)req).HasAnyAura("Rejuvenation", "Regrowth"),
                                               new PrioritySelector(
                                                   Spell.Buff("Rejuvenation", on => (WoWUnit)on),
                                                   Spell.Cast("Regrowth", on => (WoWUnit)on, req => !glyphRegrowth, cancel => false)
                                                   )
                                               ),
                                           new Wait(TimeSpan.FromMilliseconds(500), until => ((WoWUnit)until).HasAnyAura("Rejuvenation", "Regrowth"), new ActionAlwaysSucceed()),
                                           new Wait(TimeSpan.FromMilliseconds(1500), until => !Spell.IsGlobalCooldown() && !Spell.IsCastingOrChannelling(), new ActionAlwaysSucceed()),
                                           new PrioritySelector(
                                               Spell.Cast("Force of Nature", on => (WoWUnit)on, req => Spell.GetCharges("Force of Nature") > 1),
                                               Spell.Cast("Swiftmend", on => (WoWUnit)on)
                                               )
                                           )
                                       )
                                   );
            }

            #endregion

            #region Tank Buffing


            // Priority Buff: buff Mastery: Harmony
            if (Me.Level >= 80 && DruidSettings.Heal.BuffHarmony)
            {
                behavs.AddBehavior(100 + PriHighBase, "Buff Harmony w/ Healing Touch", "Healing Touch",
                                   new Sequence(
                                       Spell.Cast(
                                           "Healing Touch",
                                           mov => true,
                                           on => (WoWUnit)on,
                                           req =>
                {
                    if (Me.GetAuraTimeLeft("Harmony").TotalMilliseconds > 1500)
                    {
                        return(false);
                    }
                    if (((WoWUnit)req).HealthPercent < maxDirectHeal)
                    {
                        return(false);
                    }
                    if (Spell.DoubleCastContains(Me, "Harmony"))
                    {
                        return(false);
                    }
                    if (!Spell.CanCastHack("Healing Touch", (WoWUnit)req))
                    {
                        return(false);
                    }

                    Logger.Write(LogColor.Hilite, "^Harmony: buffing with Healing Touch");
                    return(true);
                },
                                           cancel => Me.GetAuraTimeLeft("Harmony").TotalMilliseconds > 1500 &&
                                           ((WoWUnit)cancel).HealthPercent > cancelHeal
                                           ),
                                       new Action(r => Spell.UpdateDoubleCast("Harmony", Me))
                                       )
                                   );
            }

            // Tank: Lifebloom
            behavs.AddBehavior(99 + PriHighBase, "Lifebloom - Tank", "Lifebloom",
                               Spell.Buff("Lifebloom", on => GetLifebloomTarget(), req => Me.Combat)
                               );

            // Tank: Rejuv if Lifebloom not trained yet
            if (DruidSettings.Heal.Rejuvenation != 0)
            {
                behavs.AddBehavior(98 + PriHighBase, "Rejuvenation - Tank", "Rejuvenation",
                                   Spell.Buff("Rejuvenation", on =>
                {
                    WoWUnit unit = GetBestTankTargetFor("Rejuvenation");
                    if (unit != null && Spell.CanCastHack("Rejuvenation", unit, skipWowCheck: true))
                    {
                        Logger.WriteDebug("Buffing Rejuvenation ON TANK: {0}", unit.SafeName());
                        return(unit);
                    }
                    return(null);
                })
                                   );
            }

            if (DruidSettings.Heal.Ironbark != 0)
            {
                if (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds)
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.Ironbark) + PriHighBase, "Ironbark @ " + DruidSettings.Heal.Ironbark + "%", "Ironbark",
                                       Spell.Buff("Ironbark", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.Ironbark)
                                       );
                }
                else
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.Ironbark) + PriHighBase, "Ironbark - Tank @ " + DruidSettings.Heal.Ironbark + "%", "Ironbark",
                                       Spell.Buff("Ironbark", on => Group.Tanks.FirstOrDefault(u => u.IsAlive && u.HealthPercent < DruidSettings.Heal.Ironbark && !u.HasActiveAura("Ironbark")))
                                       );
                }
            }

            if (DruidSettings.Heal.CenarionWard != 0)
            {
                if (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds)
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.CenarionWard) + PriHighBase, "Cenarion Ward @ " + DruidSettings.Heal.CenarionWard + "%", "Cenarion Ward",
                                       Spell.Buff("Cenarion Ward", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.CenarionWard)
                                       );
                }
                else
                {
                    behavs.AddBehavior(100 + PriHighBase, "Cenarion Ward - Tanks", "Cenarion Ward",
                                       Spell.Buff("Cenarion Ward", on => GetLifebloomTarget(), req => Me.Combat)
                                       );
                }
            }

            if (DruidSettings.Heal.NaturesVigil != 0)
            {
                if (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds)
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.NaturesVigil) + PriHighBase, "Nature's Vigil @ " + DruidSettings.Heal.NaturesVigil + "%", "Nature's Vigil",
                                       Spell.Buff("Nature's Vigil", on => (WoWUnit)on, req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.NaturesVigil)
                                       );
                }
                else
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.NaturesVigil) + PriHighBase, "Nature's Vigil - Tank @ " + DruidSettings.Heal.NaturesVigil + "%", "Nature's Vigil",
                                       Spell.Buff("Nature's Vigil", on => Group.Tanks.FirstOrDefault(u => u.IsAlive && u.HealthPercent < DruidSettings.Heal.NaturesVigil && !u.HasActiveAura("Nature's Vigil")))
                                       );
                }
            }

            if (DruidSettings.Heal.TreeOfLife != 0)
            {
                behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.TreeOfLife) + PriHighBase, "Incarnation: Tree of Life @ " + DruidSettings.Heal.TreeOfLife + "% MinCount: " + DruidSettings.Heal.CountTreeOfLife, "Incarnation: Tree of Life",
                                   Spell.BuffSelf("Incarnation: Tree of Life",
                                                  req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.TreeOfLife &&
                                                  DruidSettings.Heal.CountTreeOfLife <= HealerManager.Instance.TargetList.Count(h => h.IsAlive && h.HealthPercent < DruidSettings.Heal.TreeOfLife))
                                   );
            }

            #endregion

            #region AoE Heals

            if (DruidSettings.Heal.Efflorescence != 0)
            {
                behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.Efflorescence) + PriAoeBase, "Efflorescence @ " + DruidSettings.Heal.Efflorescence, "Efflorescence",
                                   new Decorator(
                                       ret => Me.IsInGroup(),
                                       CreateMushroomSetBehavior()
                                       )
                                   );
            }

            if (DruidSettings.Heal.WildGrowth != 0)
            {
                behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.WildGrowth) + PriAoeBase, "Wild Growth @ " + DruidSettings.Heal.WildGrowth + "% MinCount: " + DruidSettings.Heal.CountWildGrowth, "Wild Growth",
                                   new Decorator(
                                       ret => Me.IsInGroup(),
                                       new PrioritySelector(
                                           // ctx => HealerManager.GetBestCoverageTarget("Wild Growth", Settings.Heal.WildGrowth, 40, 30, Settings.Heal.CountWildGrowth),
                                           Spell.Buff(
                                               "Wild Growth",
                                               on => (WoWUnit)on,
                                               req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.WildGrowth &&
                                               DruidSettings.Heal.CountWildGrowth <= HealerManager.Instance.TargetList
                                               .Count(p => p.IsAlive && p.HealthPercent <= DruidSettings.Heal.WildGrowth && p.Location.DistanceSquared(((WoWUnit)req).Location) <= 30 * 30))
                                           )
                                       )
                                   );
            }

            #endregion

            #region Direct Heals

            // Regrowth above ToL: Lifebloom so we use Clearcasting procs
            behavs.AddBehavior(200 + PriSingleBase, "Regrowth on Clearcasting", "Regrowth",
                               new Sequence(
                                   CastRegrowth(
                                       on =>
            {
                if (Spell.DoubleCastContains(Me, "Clearcasting"))
                {
                    return(null);
                }

                double clearLeft = Me.GetAuraTimeLeft("Clearcasting").TotalMilliseconds;

                // ignore if less than regrowth cast time left
                if (clearLeft < Spell.GetSpellCastTime("Regrowth").TotalMilliseconds)
                {
                    return(null);
                }

                WoWUnit target       = (WoWUnit)on;
                double healthPercent = target == null ? 0.0 : target.HealthPercent;

                // clearLeft > 3000, so clear target if not needed now and try again next pass
                if (target != null)
                {
                    // still have enough time remaining on Clearcasting buff, so hold free Regrowth a bit longer to see if greater need arises
                    if (healthPercent > maxDirectHeal)
                    {
                        target = null;
                    }
                    else if (!Spell.CanCastHack("Regrowth", target))
                    {
                        target = null;
                    }
                }

                if (target != null)
                {
                    Logger.Write(LogColor.Hilite, "^Clearcasting: Regrowth at Health {0:F1}%", healthPercent);
                }

                return(target);
            },
                                       req => true,
                                       cancel => ((WoWUnit)cancel).HealthPercent > cancelHeal && Me.GetAuraTimeLeft("Clearcasting").TotalMilliseconds > 4000 && !((WoWUnit)cancel).GetAuraTimeLeft("Lifebloom").TotalMilliseconds.Between(Me.CurrentCastTimeLeft.TotalMilliseconds, 8750)
                                       ),

                                   // add double cast entry to make sure we don't try to reuse immediately
                                   new Action(r => Spell.UpdateDoubleCast("Clearcasting", Me, 500))
                                   )
                               );

            behavs.AddBehavior(198 + PriSingleBase, "Rejuvenation @ " + DruidSettings.Heal.Rejuvenation + "%", "Rejuvenation",
                               new PrioritySelector(
                                   Spell.Buff("Rejuvenation",
                                              1,
                                              on => (WoWUnit)on,
                                              req => ((WoWUnit)req).HealthPercent < DruidSettings.Heal.Rejuvenation
                                              )
                                   )
                               );

            if (DruidSettings.Heal.HealingTouch != 0)
            {
                // roll 3 Rejuvs if Glyph of Rejuvenation equipped
                if (glyphRejuv)
                {
                    // make priority 1 higher than Noursh (-1 here due to way HealerManager.HealthToPriority works)
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.HealingTouch - 1) + PriSingleBase, "Roll 3 Rejuvenations for Glyph", "Rejuvenation",
                                       new PrioritySelector(
                                           Spell.Buff("Rejuvenation",
                                                      1,
                                                      on =>
                    {
                        // iterate through so we can stop at either 3 with rejuv or first without
                        int cntHasAura = 0;
                        foreach (WoWUnit h in HealerManager.Instance.TargetList)
                        {
                            if (h.IsAlive)
                            {
                                if (!h.HasKnownAuraExpired("Rejuvenation", 1))
                                {
                                    cntHasAura++;
                                    if (cntHasAura >= 3)
                                    {
                                        return(null);
                                    }
                                }
                                else
                                {
                                    if (h.InLineOfSpellSight)
                                    {
                                        return(h);
                                    }
                                }
                            }
                        }

                        return(null);
                    },
                                                      req => true
                                                      )
                                           )
                                       );
                }
            }


            int  regrowthInstead   = 0;
            bool healingTouchKnown = SpellManager.HasSpell("Healing Touch");

            if (DruidSettings.Heal.HealingTouch != 0)
            {
                string whyRegrowth = "";
                if (SpellManager.HasSpell("Regrowth"))
                {
                    if (!healingTouchKnown)
                    {
                        regrowthInstead = Math.Max(DruidSettings.Heal.Regrowth, DruidSettings.Heal.HealingTouch);
                        whyRegrowth     = "Regrowth (since Healing Touch unknown) @ ";
                    }
                }

                if (regrowthInstead != 0)
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.HealingTouch) + PriSingleBase, whyRegrowth + regrowthInstead + "%", "Regrowth",
                                       new PrioritySelector(
                                           Spell.Cast(
                                               sp => (Me.Combat || !healingTouchKnown) ? "Regrowth" : "Healing Touch",
                                               mov => true,
                                               on => (WoWUnit)on,
                                               req => ((WoWUnit)req).HealthPercent <regrowthInstead,
                                                                                    cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal
                                               )
                                           )
                                       );
                }
                else
                {
                    behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.HealingTouch) + PriSingleBase, "Healing Touch @ " + DruidSettings.Heal.HealingTouch + "%", "Healing Touch",
                                       new PrioritySelector(
                                           Spell.Cast("Healing Touch",
                                                      mov => true,
                                                      on => (WoWUnit)on,
                                                      req => ((WoWUnit)req).HealthPercent <DruidSettings.Heal.HealingTouch,
                                                                                           cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal
                                                      )
                                           )
                                       );
                }
            }

            if (DruidSettings.Heal.Regrowth != 0 && regrowthInstead == 0)
            {
                behavs.AddBehavior(HealerManager.HealthToPriority(DruidSettings.Heal.Regrowth) + PriSingleBase, "Regrowth @ " + DruidSettings.Heal.Regrowth + "%", "Regrowth",
                                   new PrioritySelector(
                                       Spell.Cast("Regrowth",
                                                  mov => true,
                                                  on => (WoWUnit)on,
                                                  req => ((WoWUnit)req).HealthPercent <DruidSettings.Heal.Regrowth,
                                                                                       cancel => ((WoWUnit)cancel).HealthPercent> cancelHeal
                                                  )
                                       )
                                   );
            }

            #endregion

            #region Lowest Priority Healer Tasks

            behavs.AddBehavior(3, "Rejuvenation while Moving @ " + SingularSettings.Instance.IgnoreHealTargetsAboveHealth + "%", "Rejuvenation",
                               new Decorator(
                                   req => Me.IsMoving,
                                   Spell.Buff("Rejuvenation",
                                              on => HealerManager.Instance.TargetList.FirstOrDefault(h => h.IsAlive && h.HealthPercent < SingularSettings.Instance.IgnoreHealTargetsAboveHealth && !h.HasMyAura("Rejuvenation") && Spell.CanCastHack("Rejuvenation", h, true)),
                                              req => true
                                              )
                                   )
                               );

            #endregion

            behavs.OrderBehaviors();

            if (selfOnly == false && Singular.Dynamics.CompositeBuilder.CurrentBehaviorType == BehaviorType.Heal)
            {
                behavs.ListBehaviors();
            }

            return(new PrioritySelector(
                       ctx => selfOnly ? StyxWoW.Me : HealerManager.FindHighestPriorityTarget(), // 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 ShadowCombat()
        {
            return(new PrioritySelector(

                       //new Decorator(ret => Me.IsCasting && (Me.ChanneledSpell == null || Me.ChanneledSpell.Id != MindFlay), new Action(ret => { return RunStatus.Success; })),
                       new Decorator(ret => !Me.Combat || Me.Mounted || !Me.CurrentTarget.IsAlive || !Me.GotTarget /*|| Me.ChanneledSpell.Name == "Hymn of Hope"*/,
                                     new ActionAlwaysSucceed()),

                       new Decorator(ret => Me.ChanneledSpell != null,
                                     new PrioritySelector(
                                         new Decorator(ret => Me.ChanneledSpell.Name == "Hymn of Hope",
                                                       Spell.WaitForCastOrChannel()))),

                       Hymn(),
                       MassDispel(),

                       new Decorator(ret => AdvancedAI.Burst,
                                     new PrioritySelector(
                                         Spell.Cast("Lifeblood"),
                                         new Action(ret => { Item.UseHands(); return RunStatus.Failure; }),
                                         new Action(ret => { Item.UseTrinkets(); return RunStatus.Failure; }),
                                         new Decorator(ret => Me.CurrentTarget.IsBoss(),
                                                       new PrioritySelector(
                                                           Spell.Cast("Shadowfiend", ret => Spell.GetSpellCooldown("Shadowfiend").TotalMilliseconds < 10),
                                                           Spell.Cast("Mindbender", ret => Spell.GetSpellCooldown("Mindbender").TotalMilliseconds < 10),
                                                           Spell.Cast("Power Infusion", ret => SpellManager.HasSpell("Power Infusion") && Spell.GetSpellCooldown("Power Infusion").TotalMilliseconds < 10))))),

                       Spell.Cast("Void Shift", on => VoidTank),
                       Spell.Cast("Prayer of Mending", on => Me, ret => Me.HealthPercent <= 85),
                       new Throttle(1,
                                    Spell.Cast("Vampiric Embrace", ret => HealerManager.GetCountWithHealth(55) > 4)),

                       new Decorator(
                           ret => Me.GotTarget && Me.ChanneledSpell != null,
                           new PrioritySelector(
                               new Decorator(
                                   ret => Me.ChanneledSpell.Name == "Mind Flay" &&
                                   CMF && !SpellManager.HasSpell("Solace and Insanity"),
                                   new Sequence(
                                       new Action(ret => Logging.WriteDiagnostic("/cancel Mind Flay on {0} @ {1:F1}%", Me.CurrentTarget.SafeName(), Me.CurrentTarget.HealthPercent)),
                                       new Action(ret => SpellManager.StopCasting()),
                                       new WaitContinue(TimeSpan.FromMilliseconds(500), ret => Me.ChanneledSpell == null, new ActionAlwaysSucceed()))))),

                       new Decorator(ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() > 2 && AdvancedAI.Aoe,
                                     CreateAOE()),
                       //Spell.Cast("Shadow Word: Pain", ret => Orbs == 3 && Me.CurrentTarget.CachedHasAura("Shadow Word: Pain") && Me.CurrentTarget.CachedGetAuraTimeLeft("Shadow Word: Pain") <= 6),
                       //Spell.Cast("Vampiric Touch", ret => Orbs == 3 && Me.CurrentTarget.CachedHasAura("Vampiric Touch") && Me.CurrentTarget.CachedGetAuraTimeLeft("Shadow Word: Pain") <= 6),
                       //Spell.Cast("Devouring Plague", ret => Orbs == 3 && Me.CurrentTarget.CachedGetAuraTimeLeft("Shadow Word: Pain") >= 6 && Me.CurrentTarget.CachedGetAuraTimeLeft("Vampiric Touch") >= 6),
                       Spell.Cast("Devouring Plague", ret => Orbs == 3),

                       Spell.Cast("Mind Blast", ret => Orbs < 3),
                       new Throttle(2,
                                    new PrioritySelector(
                                        Spell.Cast("Shadow Word: Death", ret => Orbs < 3))),
                       //new Throttle(2,
                       //    new PrioritySelector(
                       //        Spell.Cast("Mind Flay", ret => Me.CurrentTarget.CachedHasAura("Devouring Plague")))),
                       Spell.Cast("Mind Flay", on => Me.CurrentTarget, ret => SpellManager.HasSpell("Solace and Insanity") && Me.CurrentTarget.CachedHasAura("Devouring Plague")),
                       new Throttle(1,
                                    new PrioritySelector(
                                        Spell.Cast("Shadow Word: Pain", ret => !Me.CurrentTarget.CachedHasAura("Shadow Word: Pain") || Me.CurrentTarget.HasAuraExpired("Shadow Word: Pain", 3)))),
                       new Throttle(TimeSpan.FromMilliseconds(1500),
                                    new PrioritySelector(
                                        Spell.Cast("Vampiric Touch", ret => !Me.CurrentTarget.CachedHasAura("Vampiric Touch") || Me.CurrentTarget.HasAuraExpired("Vampiric Touch", 4)))),
                       Spell.Cast("Mind Spike", ret => Me.HasAura(87160)),
                       Spell.Cast("Halo", ret => Me.CurrentTarget.Distance < 30),
                       Spell.Cast("Cascade"),
                       Spell.Cast("Divine Star"),
                       //new Throttle(1,
                       //    new PrioritySelector(
                       Spell.Cast("Mind Flay", on => Me.CurrentTarget, ret => !CMF),
                       Spell.Cast("Shadow Word: Death", ret => Me.IsMoving),
                       Spell.Cast("Shadow Word: Pain", ret => Me.IsMoving)));
        }
Exemple #18
0
        public static Composite CreateRestoShamanCombatBehaviorInstances()
        {
#if OLD_APPROACH
            return(new PrioritySelector(

                       ctx => HealerManager.Instance.TargetList.Any(t => !t.IsMe && t.IsAlive),

                       Safers.EnsureTarget(),
                       Movement.CreateFaceTargetBehavior(),

                       Spell.WaitForCastOrChannel(),

                       new Decorator(
                           ret => !Spell.IsGlobalCooldown(),
                           new PrioritySelector(

                               CreateRestoDiagnosticOutputBehavior(on => Me.CurrentTarget),

                               new Decorator(
                                   ret => (bool)ret,
                                   new PrioritySelector(
                                       HealerManager.CreateStayNearTankBehavior(),
                                       CreateRestoShamanHealingOnlyBehavior(selfOnly: false),
                                       Helpers.Common.CreateInterruptBehavior(),
                                       Dispelling.CreatePurgeEnemyBehavior("Purge"),
                                       Totems.CreateTotemsBehavior(),
                                       Spell.Cast("Lightning Bolt", ret => TalentManager.HasGlyph("Telluric Currents"))
                                       )
                                   ),

                               new Decorator(
                                   ret => !((bool)ret),
                                   new PrioritySelector(
                                       CreateRestoDiagnosticOutputBehavior(on => HealerManager.Instance.FirstUnit),
                                       Spell.Cast("Elemental Blast"),
                                       Spell.Buff("Flame Shock", true, on => Me.CurrentTarget, req => true, 3),
                                       Spell.Cast("Lava Burst"),
                                       Spell.Cast("Frost Shock"),
                                       Spell.Cast("Chain Lightning", ret => Spell.UseAOE && Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2 && !Unit.UnfriendlyUnitsNearTarget(12f).Any(u => u.IsCrowdControlled())),
                                       Spell.Cast("Lightning Bolt")
                                       )
                                   )

                               )
                           )
                       ));
#else
            return(new PrioritySelector(

                       Spell.WaitForCastOrChannel(),
                       CreateRestoDiagnosticOutputBehavior(on => HealerManager.FindLowestHealthTarget()),

                       HealerManager.CreateStayNearTankBehavior(),

                       new Decorator(
                           ret => Me.Combat && HealerManager.AllowHealerDPS(),
                           new PrioritySelector(

                               Helpers.Common.EnsureReadyToAttackFromMediumRange(),
                               Movement.CreateFaceTargetBehavior(),
                               Spell.WaitForCastOrChannel(),

                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(
                                       Helpers.Common.CreateInterruptBehavior(),

                                       Totems.CreateTotemsBehavior(),

                                       Movement.WaitForFacing(),
                                       Movement.WaitForLineOfSpellSight(),

                                       Common.CastElementalBlast(cancel: c => HealerManager.CancelHealerDPS()),
                                       Spell.Buff("Flame Shock", 3, on => Me.CurrentTarget, req => true),
                                       Spell.Cast("Lava Burst", on => Me.CurrentTarget, req => true, cancel => HealerManager.CancelHealerDPS()),
                                       Spell.Cast("Frost Shock"),
                                       Spell.Cast("Chain Lightning", on => Me.CurrentTarget, req => Spell.UseAOE && Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2 && !Unit.UnfriendlyUnitsNearTarget(12f).Any(u => u.IsCrowdControlled()), cancel => HealerManager.CancelHealerDPS()),
                                       Spell.Cast("Lightning Bolt", on => Me.CurrentTarget, req => true, cancel => HealerManager.CancelHealerDPS())
                                       )
                                   )
                               )
                           ),

                       new Decorator(
                           ret => Unit.NearbyGroupMembers.Any(m => m.IsAlive && !m.IsMe),
                           new PrioritySelector(
                               CreateRestoShamanHealingOnlyBehavior(selfOnly: false),
                               Helpers.Common.CreateInterruptBehavior(),
                               Dispelling.CreatePurgeEnemyBehavior("Purge"),
                               Totems.CreateTotemsBehavior(),
                               new Decorator(
                                   req => TalentManager.HasGlyph("Telluric Currents"),
                                   new PrioritySelector(
                                       Safers.EnsureTarget(),
                                       Movement.CreateFaceTargetBehavior(),
                                       Spell.Cast("Lightning Bolt",
                                                  mov => true,
                                                  on => Unit.NearbyUnitsInCombatWithUsOrOurStuff
                                                  .Where(u => u.IsAlive && u.SpellDistance() < 40 && Me.IsSafelyFacing(u))
                                                  .OrderByDescending(u => u.HealthPercent)
                                                  .FirstOrDefault(),
                                                  req => !HealerManager.Instance.TargetList.Any(h => h.IsAlive && h.SpellDistance() < 40 && h.HealthPercent < ShamanSettings.RestoHealSettings.TelluricHealthCast),
                                                  cancel => HealerManager.Instance.TargetList.Any(h => h.IsAlive && h.SpellDistance() < 40 && h.HealthPercent < ShamanSettings.RestoHealSettings.TelluricHealthCancel)
                                                  )
                                       )
                                   )
                               )
                           )
                       ));
#endif
        }
        public static bool UpdateDiagnosticCastingState(bool retVal = false)
        {
            if (SingularSettings.Debug && SingularSettings.DebugSpellCasting)
            {
                if (SingularSettings.DebugSpellCasting)
                {
                    if (_lastIsGCD != Spell.IsGlobalCooldown())
                    {
                        _lastIsGCD = !_lastIsGCD;
                        Logger.WriteDebug("CastingState:  GCD={0} GCDTimeLeft={1}", _lastIsGCD.ToYN(), (int)Spell.GcdTimeLeft.TotalMilliseconds);
                    }
                    if (_lastIsCasting != Spell.IsCasting())
                    {
                        _lastIsCasting = !_lastIsCasting;
                        Logger.WriteDebug("CastingState:  Casting={0} CastTimeLeft={1}", _lastIsCasting.ToYN(), (int)Me.CurrentCastTimeLeft.TotalMilliseconds);
                    }
                    if (_lastIsChanneling != Spell.IsChannelling())
                    {
                        _lastIsChanneling = !_lastIsChanneling;
                        Logger.WriteDebug("ChannelingState:  Channeling={0} ChannelTimeLeft={1}", _lastIsChanneling.ToYN(), (int)Me.CurrentChannelTimeLeft.TotalMilliseconds);
                    }
                }
                if (_lastIsInVehicle != Me.InVehicle)
                {
                    _lastIsInVehicle = !_lastIsInVehicle;
                    Logger.WriteDebug("VehicleState:  InVehicle={0} ***", _lastIsInVehicle.ToYN());
                }

                if (_lastIsInCinematic != InCinematic())
                {
                    _lastIsInCinematic = !_lastIsInCinematic;
                    Logger.WriteDebug("CinematicState:  InCinematic={0} ***", _lastIsInCinematic.ToYN());
                }
                WoWSpell pending = Spell.GetPendingCursorSpell;
                if (_lastIsSpellPending != (pending != null))
                {
                    _lastIsSpellPending = !_lastIsSpellPending;
                    _lastSpellPending   = pending.Name;
                    Logger.WriteDebug("PendingState:  Pending Target={0}{1}", _lastIsSpellPending.ToYN(), !_lastIsSpellPending ? "" : ", Spell=" + _lastSpellPending);
                }

                if (SingularSettings.DebugSpellCasting)
                {
                    /// Special: provide diagnostics if healer
                    if (HealerManager.NeedHealTargeting && (_nextAbcWarning < DateTime.UtcNow) && !Me.IsCasting && !Me.IsChanneling && !Spell.IsGlobalCooldown(LagTolerance.No))
                    {
                        WoWUnit low = HealerManager.FindLowestHealthTarget();
                        if (low != null)
                        {
                            float lh = low.PredictedHealthPercent();
                            if (!SingularSettings.Instance.HealerCombatAllow && lh < 70)
                            {
                                Logger.WriteDebug("Healer ABC Warning: no cast in progress detected, low health {0} {1:F1}% @ {2:F1} yds", low.SafeName(), lh, low.SpellDistance());
                                _nextAbcWarning = DateTime.UtcNow + TimeSpan.FromSeconds(1);
                            }
                        }
                    }
                }
            }
            return(retVal);
        }
Exemple #20
0
        public static Composite CreateRestoShamanHealingOnlyBehavior(bool selfOnly = false)
        {
            HealerManager.NeedHealTargeting = true;
            PrioritizedBehaviorList behavs = new PrioritizedBehaviorList();
            int cancelHeal = (int)Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, Math.Max(ShamanSettings.RestoHealSettings.HealingWave, ShamanSettings.RestoHealSettings.HealingSurge));

            bool moveInRange = false;

            if (!selfOnly)
            {
                moveInRange = (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds);
            }

            Logger.WriteDebugInBehaviorCreate("Shaman Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal);

            int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999;

            if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None)
            {
                behavs.AddBehavior(dispelPriority, "Purify Spirit", null, Dispelling.CreateDispelBehavior());
            }

            #region Save the Group

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.SpiritLinkTotem) + 600, "Spirit Link Totem", "Spirit Link Totem",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   Spell.CastOnGround("Spirit Link Totem",
                                                      on => (WoWUnit)on,
                                                      ret => HealerManager.Instance.TargetList.Count(
                                                          p => p.PredictedHealthPercent() < ShamanSettings.RestoHealSettings.SpiritLinkTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.SpiritLink)) >= ShamanSettings.RestoHealSettings.MinSpiritLinkCount
                                                      )
                                   )
                               );

            #endregion

            #region AoE Heals

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.HealingTideTotem) + 400, "Healing Tide Totem", "Healing Tide Totem",
                               new Decorator(
                                   ret => (Me.Combat || ((WoWUnit)ret).Combat) &&
                                   (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid) &&
                                   (!Totems.Exist(WoWTotem.Cloudburst) || (Totems.GetTotem(WoWTotem.Cloudburst).Expires - DateTime.UtcNow).TotalMilliseconds < 1500),
                                   Spell.Cast(
                                       "Healing Tide Totem",
                                       on => Me,
                                       req => Me.Combat && HealerManager.Instance.TargetList.Count(p => p.PredictedHealthPercent() < ShamanSettings.RestoHealSettings.HealingTideTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingTide)) >= ShamanSettings.RestoHealSettings.MinHealingTideCount
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.HealingStreamTotem) + 300, "Healing Stream Totem", "Healing Stream Totem",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   Spell.Cast(
                                       "Healing Stream Totem",
                                       on =>
            {
                if (Totems.Exist(WoWTotemType.Water))
                {
                    return(null);
                }

                if (Spell.IsSpellOnCooldown(Totems.ToSpellId(WoWTotem.HealingStream)))
                {
                    return(null);
                }

                // if tank in group, make sure we are near the tank
                WoWUnit tank = HealerManager.TankToStayNear;
                if (tank != null)
                {
                    if (!HealerManager.IsTankSettledIntoFight(tank))
                    {
                        return(null);
                    }
                    if (tank.Distance > Totems.GetTotemRange(WoWTotem.HealingStream))
                    {
                        return(null);
                    }
                }

                WoWUnit unit = HealerManager.Instance.TargetList
                               .FirstOrDefault(
                    p => p.PredictedHealthPercent() < ShamanSettings.RestoHealSettings.HealingStreamTotem &&
                    p.Distance <= Totems.GetTotemRange(WoWTotem.HealingStream)
                    );

                return(unit);
            }
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.GiftoftheQueen) + 300, "Gift of the Queen", "Gift of the Queen",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   new PrioritySelector(
                                       context => GetBestGiftoftheQueenTarget(),
                                       new Decorator(
                                           ret => ret != null,
                                           Spell.CastOnGround("Gift of the Queen", on => (WoWUnit)on, req => true, false)
                                           )
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.CloudburstTotem) + 300, "Cloudburst Totem", "Cloudburst Totem",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   Spell.Cast(
                                       "Cloudburst Totem",
                                       on =>
            {
                if (Totems.Exist(WoWTotemType.Water))
                {
                    return(null);
                }

                if (Spell.IsSpellOnCooldown(Totems.ToSpellId(WoWTotem.Cloudburst)))
                {
                    return(null);
                }

                if (Unit.ValidUnit(Me.CurrentTarget) && (Me.CurrentTarget.TimeToDeath() < 20 || Unit.UnitsInCombatWithUsOrOurStuff().Count() < 3))
                {
                    return(null);
                }

                // if tank in group, make sure we are near the tank
                WoWUnit tank = HealerManager.TankToStayNear;
                if (tank != null)
                {
                    if (!HealerManager.IsTankSettledIntoFight(tank))
                    {
                        return(null);
                    }
                    if (tank.Distance > Totems.GetTotemRange(WoWTotem.Cloudburst))
                    {
                        return(null);
                    }
                }

                WoWUnit unit = HealerManager.Instance.TargetList
                               .Where(
                    p => p.HealthPercent < ShamanSettings.RestoHealSettings.CloudburstTotem &&
                    p.Distance <= Totems.GetTotemRange(WoWTotem.Cloudburst)
                    )
                               .OrderBy(p => (int)p.HealthPercent)
                               .FirstOrDefault();

                return(unit);
            }
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.HealingRain) + 200, "Healing Rain", "Healing Rain",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   new PrioritySelector(
                                       context => GetBestHealingRainTarget(),
                                       new Decorator(
                                           ret => ret != null,
                                           Spell.CastOnGround("Healing Rain", on => (WoWUnit)on, req => true, false)
                                           )
                                       )
                                   )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.ChainHeal) + 150, "Chain Heal", "Chain Heal",
                               new Decorator(
                                   ret => Me.Combat && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   new PrioritySelector(
                                       ctx => GetBestChainHealTarget(),
                                       new Decorator(
                                           ret => ret != null,
                                           new Sequence(
                                               new DecoratorContinue(
                                                   req => ((WoWUnit)req).HasAuraExpired("Riptide", TimeSpan.FromMilliseconds(ChainHealCastTime), true),
                                                   new Sequence(
                                                       Spell.Cast("Riptide", on => (WoWUnit)on, req => true, cancel => false),
                                                       new Wait(TimeSpan.FromMilliseconds(1500), until => !Spell.IsGlobalCooldown(LagTolerance.No), new ActionAlwaysSucceed()),
                                                       new Action(r => TidalWaveRefresh())
                                                       )
                                                   ),
                                               new WaitContinue(TimeSpan.FromMilliseconds(1500), until => !Spell.IsGlobalCooldown(LagTolerance.No), new ActionAlwaysSucceed()),
                                               Spell.Cast("Chain Heal", on => (WoWUnit)on),
                                               new Action(r => TidalWaveRefresh())
                                               )
                                           )
                                       )
                                   )
                               );

            #endregion

            #region Single Target Heals

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.HealingWave), "Healing Wave", "Healing Wave",
                               new Decorator(ret => ((WoWUnit)ret).PredictedHealthPercent() < ShamanSettings.RestoHealSettings.HealingWave,
                                             new Sequence(
                                                 new WaitContinue(TimeSpan.FromMilliseconds(1500), until => !Spell.IsGlobalCooldown(), new ActionAlwaysSucceed()),
                                                 new WaitContinue(2, until => !Spell.IsGlobalCooldown(), new ActionAlwaysSucceed()),
                                                 Spell.Cast("Healing Wave",
                                                            mov => true,
                                                            on => (WoWUnit)on,
                                                            req => true,
                                                            cancel => ((WoWUnit)cancel).HealthPercent > cancelHeal),
                                                 new Action(r => TidalWaveConsume())
                                                 )
                                             )
                               );

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.HealingSurge), "Healing Surge", "Healing Surge",
                               new Decorator(ret => ((WoWUnit)ret).PredictedHealthPercent() < ShamanSettings.RestoHealSettings.HealingSurge,
                                             new Sequence(
                                                 new WaitContinue(TimeSpan.FromMilliseconds(1500), until => !Spell.IsGlobalCooldown(), new ActionAlwaysSucceed()),
                                                 new WaitContinue(2, until => !Spell.IsGlobalCooldown(), new ActionAlwaysSucceed()),
                                                 Spell.Cast("Healing Surge",
                                                            mov => true,
                                                            on => (WoWUnit)on,
                                                            req => true,
                                                            cancel => ((WoWUnit)cancel).HealthPercent > cancelHeal),
                                                 new Action(r => TidalWaveConsume())
                                                 )
                                             )

                               );

            #endregion

            #region Healing Cooldowns

            behavs.AddBehavior(HealerManager.HealthToPriority(ShamanSettings.RestoHealSettings.Ascendance) + 100, "Ascendance", "Ascendance",
                               new Decorator(
                                   ret => ShamanSettings.UseAscendance && (StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid),
                                   Spell.BuffSelf(
                                       "Ascendance",
                                       ret => HealerManager.Instance.TargetList.Count(p => p.PredictedHealthPercent() < ShamanSettings.RestoHealSettings.Ascendance) >= ShamanSettings.RestoHealSettings.MinAscendanceCount
                                       )
                                   )
                               );

            #endregion

            behavs.OrderBehaviors();

            if (selfOnly == false && CompositeBuilder.CurrentBehaviorType == BehaviorType.Combat)
            {
                behavs.ListBehaviors();
            }


            return(new PrioritySelector(
                       ctx => selfOnly ? StyxWoW.Me : HealerManager.FindLowestHealthTarget(),
                       // HealerManager.Instance.FirstUnit,

                       CreateRestoDiagnosticOutputBehavior(ret => (WoWUnit)ret),

                       new Decorator(
                           ret =>
                           ret != null &&
                           (Me.Combat || ((WoWUnit)ret).Combat || ((WoWUnit)ret).PredictedHealthPercent() <= 99),

                           new PrioritySelector(
                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(

                                       Totems.CreateTotemsBehavior(),

                                       // roll Riptide on Tanks otherwise
                                       new Sequence(
                                           Spell.Cast("Riptide", on =>
            {
                WoWUnit unit = GetBestRiptideTankTarget();
                if (unit != null && Spell.CanCastHack("Riptide", unit, skipWowCheck: true))
                {
                    Logger.WriteDebug("Buffing RIPTIDE ON TANK: {0}", unit.SafeName());
                    return unit;
                }
                return null;
            }),
                                           new Action(r => TidalWaveRefresh())
                                           ),

                                       // cast Riptide if we are a low level
                                       CreateRestoShamanBuffRiptideLowLevel(),

                                       // cast Riptide if we need Tidal Waves -- skip if Ancestral Swiftness is
                                       CreateRestoShamanBuffTidalWaves(),

                                       behavs.GenerateBehaviorTree(),

                                       // cast Riptide if we need Tidal Waves -- skip if Ancestral Swiftness is
                                       new Decorator(
                                           ret =>
            {
                int rollCount =
                    HealerManager.Instance.TargetList.Count(
                        u => u.IsAlive && u.HasMyAura("Riptide"));
                // Logger.WriteDebug("GetBestRiptideTarget:  currently {0} group members have my Riptide", rollCount);
                return rollCount < ShamanSettings.RestoHealSettings.RollRiptideCount;
            },
                                           new Sequence(
                                               Spell.Cast("Riptide", on =>
            {
                // if tank needs Riptide, bail out on Rolling as they have priority
                if (GetBestRiptideTankTarget() != null)
                {
                    return null;
                }

                // get the best target from all wowunits in our group
                WoWUnit unit = GetBestRiptideTarget();
                if (unit != null)
                {
                    Logger.WriteDebug(Color.White, "ROLLING RIPTIDE on: {0}",
                                      unit.SafeName());
                }

                return unit;
            }),
                                               new Action(r => TidalWaveRefresh())
                                               )
                                           ),

                                       new Decorator(
                                           ret => moveInRange,
                                           new Sequence(
                                               new Action(r => _moveToHealUnit = (WoWUnit)r),
                                               new PrioritySelector(
                                                   Movement.CreateMoveToLosBehavior(on => _moveToHealUnit),
                                                   Movement.CreateMoveToUnitBehavior(on => _moveToHealUnit, 40f, 34f)
                                                   )
                                               )
                                           )
                                       )
                                   )
                               )
                           )
                       ));
        }
Exemple #21
0
        public static Composite CreateMonkOffHealBehavior()
        {
            HealerManager.NeedHealTargeting = SingularSettings.Instance.DpsOffHealAllowed;
            PrioritizedBehaviorList behavs = new PrioritizedBehaviorList();
            int cancelHeal = (int)Math.Max(SingularSettings.Instance.IgnoreHealTargetsAboveHealth, MonkSettings.OffHealSettings.Effuse);

            bool moveInRange = (SingularRoutine.CurrentWoWContext == WoWContext.Battlegrounds);

            Logger.WriteDebugInBehaviorCreate("Monk Healing: will cancel cast of direct heal if health reaches {0:F1}%", cancelHeal);

/*
 *          int dispelPriority = (SingularSettings.Instance.DispelDebuffs == RelativePriority.HighPriority) ? 999 : -999;
 *          if (SingularSettings.Instance.DispelDebuffs != RelativePriority.None)
 *              behavs.AddBehavior(dispelPriority, "Cleanse Spirit", null, Dispelling.CreateDispelBehavior());
 */
            #region Save the Group


            #endregion

            #region AoE Heals

            behavs.AddBehavior(
                Mistweaver.HealthToPriority(MonkSettings.MistHealSettings.ChiWave) + 400,
                String.Format("Chi Wave on {0} targets @ {1}%", MonkSettings.OffHealSettings.CountChiWaveTalent, MonkSettings.OffHealSettings.ChiWaveTalent),
                "Chi Wave",
                CreateClusterHeal("Chi Wave", ClusterType.Cone, MonkSettings.OffHealSettings.ChiWaveTalent, MonkSettings.OffHealSettings.CountChiWaveTalent, 40)
                );

            behavs.AddBehavior(
                Mistweaver.HealthToPriority(MonkSettings.MistHealSettings.ChiBurstTalent) + 400,
                String.Format("Chi Burst on {0} targets @ {1}%", MonkSettings.OffHealSettings.CountChiBurstTalent, MonkSettings.OffHealSettings.ChiBurstTalent),
                "Chi Burst",
                CreateClusterHeal("Chi Burst", ClusterType.Cone, MonkSettings.OffHealSettings.ChiBurstTalent, MonkSettings.OffHealSettings.CountChiBurstTalent, 40)
                );


            #endregion

            #region Single Target Heals

            behavs.AddBehavior(Mistweaver.HealthToPriority(MonkSettings.OffHealSettings.Effuse),
                               string.Format("Effuse @ {0}%", MonkSettings.OffHealSettings.Effuse),
                               "Effuse",
                               Spell.Cast("Effuse",
                                          mov => true,
                                          on => (WoWUnit)on,
                                          req => ((WoWUnit)req).PredictedHealthPercent(includeMyHeals: true) < MonkSettings.OffHealSettings.Effuse,
                                          cancel => ((WoWUnit)cancel).HealthPercent > cancelHeal
                                          )
                               );

            #endregion

            behavs.OrderBehaviors();

            if (Singular.Dynamics.CompositeBuilder.CurrentBehaviorType == BehaviorType.Heal)
            {
                behavs.ListBehaviors();
            }

            return(new PrioritySelector(
                       ctx => HealerManager.FindLowestHealthTarget(), // HealerManager.Instance.FirstUnit,

                       new Decorator(
                           ret => ret != null && (Me.Combat || ((WoWUnit)ret).Combat || ((WoWUnit)ret).PredictedHealthPercent() <= 99),

                           new PrioritySelector(
                               new Decorator(
                                   ret => !Spell.IsGlobalCooldown(),
                                   new PrioritySelector(

                                       behavs.GenerateBehaviorTree(),

                                       new Decorator(
                                           ret => moveInRange,
                                           new Sequence(
                                               new Action(r => _moveToHealUnit = (WoWUnit)r),
                                               new PrioritySelector(
                                                   Movement.CreateMoveToLosBehavior(on => _moveToHealUnit),
                                                   Movement.CreateMoveToUnitBehavior(on => _moveToHealUnit, 30f, 25f)
                                                   )
                                               )
                                           )
                                       )
                                   )
                               )
                           )
                       ));
        }