public static Composite CreateRestoShamanCombatBehaviorSolo() { return(new PrioritySelector( Helpers.Common.EnsureReadyToAttackFromMediumRange(), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown(), new PrioritySelector( CreateRestoDiagnosticOutputBehavior(on => null), 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") ) ) )); }
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") ) ) ) ) )); }
public static Composite CreateShamanEnhancementNormalPull() { return(new PrioritySelector( new Decorator(req => Me.Level < 20, Helpers.Common.EnsureReadyToAttackFromMediumRange()), new Decorator(req => Me.Level >= 20, Helpers.Common.EnsureReadyToAttackFromMelee()), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown(), new PrioritySelector( CreateEnhanceDiagnosticOutputBehavior(), Common.CreateShamanDpsShieldBehavior(), Totems.CreateTotemsBehavior(), Movement.WaitForFacing(), Movement.WaitForLineOfSpellSight(), Spell.Cast("Feral Lunge", ret => ShamanSettings.UseFeralLunge), Spell.Cast("Lightning Bolt", ret => !ShamanSettings.AvoidMaelstromDamage && StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Unleash Elements", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.TemporaryEnchantment.Id == 5), new Decorator( req => Spell.UseAOE, new PrioritySelector( Spell.Cast("Flame Shock", req => StyxWoW.Me.HasAura("Unleash Flame")), Spell.Buff("Flame Shock", true, req => Me.CurrentTarget.Elite || (!Me.CurrentTarget.IsTrivial() && Unit.UnfriendlyUnits(12).Count() > 1)) ) ), Spell.Cast("Frost Shock"), Spell.Cast("Lightning Bolt", ret => Me.Level < 20 || Me.CurrentTarget.IsFlying || !Movement.CanNavigateToMelee(Me.CurrentTarget)) ) ) )); }
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) ) ) ) ) ) ) ) )); }
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 Composite CreateShamanEnhancementNormalCombat() { return(new PrioritySelector( Helpers.Common.EnsureReadyToAttackFromMelee(), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown(), new PrioritySelector( SingularRoutine.MoveBehaviorInlineToCombat(BehaviorType.Heal), SingularRoutine.MoveBehaviorInlineToCombat(BehaviorType.CombatBuffs), CreateEnhanceDiagnosticOutputBehavior(), Helpers.Common.CreateInterruptBehavior(), Totems.CreateTotemsBehavior(), Movement.WaitForFacing(), Movement.WaitForLineOfSpellSight(), Spell.BuffSelf("Feral Spirit", ret => !Me.CurrentTarget.IsTrivial() && NeedFeralSpirit), // Artifact Weapon new Decorator( ret => ShamanSettings.UseArtifactOnlyInAoE && Unit.NearbyUnitsInCombatWithMeOrMyStuff.Count() > 1, new PrioritySelector( Spell.Cast("Doom Winds", ret => ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.OnCooldown) ) ), Spell.Cast("Doom Winds", ret => !ShamanSettings.UseArtifactOnlyInAoE && ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.OnCooldown), new Decorator( req => AttackEvenIfGhostWolf, new PrioritySelector( Dispelling.CreatePurgeEnemyBehavior("Purge"), Common.CreateShamanDpsShieldBehavior(), // Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), // pull more logic (use instants first, then ranged pulls if possible) Spell.CastOnGround("Lightning Surge Totem", on => Clusters.GetBestUnitForCluster(Unit.NearbyUnfriendlyUnits, ClusterType.Radius, 8f).Location, ret => ShamanSettings.UseLightningSurgeTotem && SingularRoutine.CurrentWoWContext == WoWContext.Normal && Unit.UnfriendlyUnits(8).Count() >= ShamanSettings.LightningSurgeTotemCount), Spell.Cast("Ascendance", req => Me.HealthPercent <= ShamanSettings.AscendanceHealthPercent), Spell.Cast("Lava Lash", req => Me.HasActiveAura("Hot Hand")), Spell.Cast("Windsong"), Spell.Cast("Rockbiter", req => (Common.HasTalent(ShamanTalents.Boulderfist) && !Me.HasActiveAura("Boulderfist")) || (Common.HasTalent(ShamanTalents.Landslide) && !Me.HasActiveAura("Landslide"))), Spell.Cast("Frostbrand", req => Common.HasTalent(ShamanTalents.Hailstorm) && !Me.HasActiveAura("Frostbrand")), Spell.Cast("Boulderfist", req => Me.CurrentMaelstrom < 130 && Spell.GetCharges("Boulderfist") >= 2), Spell.Cast("Flametongue", req => !Me.HasActiveAura("Flametongue")), Spell.Cast("Feral Spirit", ret => NeedFeralSpirit), Spell.Cast("Earthen Spike"), Spell.Cast("Crash Lightning", when => Unit.UnfriendlyUnitsNearTarget(10).Count(u => u.TaggedByMe || !u.TaggedByOther) >= 2), Spell.Cast("Stormstrike"), Spell.Cast("Crash Ligthning", req => Common.HasTalent(ShamanTalents.CrashingStorm)), Spell.Cast("Lava Lash", req => Me.CurrentMaelstrom > 110), Spell.Cast("Sundering", req => SingularRoutine.CurrentWoWContext != WoWContext.Instances), Spell.Cast("Rockbiter"), Spell.Cast("Lightning Bolt", req => !Me.CurrentTarget.IsWithinMeleeRange), // won't happen often, but if at range and no abilities enter ghost wolf CreateInCombatGapCloser() ) ) ) ), Movement.CreateMoveToMeleeBehavior(true) )); }
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) ) ) ) ) ) ) ) )); }
public static Composite CreateShamanCombatBuffsPVP() { return(new PrioritySelector( Totems.CreateTotemsBehavior(), Spell.BuffSelf("Astral Shift", ret => Me.HealthPercent < ShamanSettings.AstralShiftPercent || Common.StressfulSituation), Spell.BuffSelf(WoWTotem.StoneBulwark.ToSpellId(), ret => !Me.IsMoving && (Common.StressfulSituation || Me.HealthPercent < ShamanSettings.StoneBulwarkTotemPercent && !Totems.Exist(WoWTotem.EarthElemental))), Spell.BuffSelf("Shamanistic Rage", ret => Me.HealthPercent < 70 || Me.ManaPercent < 70 || Common.StressfulSituation), // hex someone if they are not current target, attacking us, and 12 yds or more away new PrioritySelector( ctx => Unit.NearbyUnfriendlyUnits .Where(u => (u.CreatureType == WoWCreatureType.Beast || u.CreatureType == WoWCreatureType.Humanoid) && (u.Aggro || u.PetAggro || (u.Combat && u.IsTargetingMeOrPet)) && u.Distance.Between(10, 30) && Me.IsSafelyFacing(u) && u.InLineOfSpellSight && Me.GotTarget() && u.Location.Distance(Me.CurrentTarget.Location) > 10) .OrderByDescending(u => u.Distance) .FirstOrDefault(), Spell.Cast("Hex", onUnit => (WoWUnit)onUnit) ), new Decorator( req => { if (!Unit.ValidUnit(Me.CurrentTarget)) { return false; } if (Me.Specialization == WoWSpec.ShamanEnhancement && !Me.CurrentTarget.IsWithinMeleeRange) { return false; } if (Me.CurrentTarget.TimeToDeath() > 5 || Me.CurrentTarget.HealthPercent > 20 || Me.HealthPercent < Me.CurrentTarget.HealthPercent) { return true; } if (Unit.UnfriendlyUnits(40).Count(u => u.IsTargetingMyStuff()) >= 2) { return true; } return false; }, new PrioritySelector( Spell.BuffSelfAndWait(PartyBuff.BloodlustSpellName, req => ShamanSettings.UseBloodlust && MovementManager.IsClassMovementAllowed && IsPvpFightWorthLusting, gcd: HasGcd.No ), Spell.BuffSelf( "Ascendance", req => ShamanSettings.UseAscendance && ((Me.GotTarget() && Me.CurrentTarget.HealthPercent > 70) || Unit.NearbyUnfriendlyUnits.Count() > 1), gcd: HasGcd.No ), Spell.BuffSelf( "Elemental Mastery", req => !PartyBuff.WeHaveBloodlust, gcd: HasGcd.No ) ) ) // , Spell.BuffSelf("Spiritwalker's Grace", ret => Me.IsMoving && Me.Combat) )); }
public static Composite CreateShamanCombatBuffs() { return(new Decorator( req => !Unit.IsTrivial(Me.CurrentTarget), new PrioritySelector( Totems.CreateTotemsBehavior(), // hex someone if they are not current target, attacking us, and 12 yds or more away new Decorator( req => Me.GotTarget() && (TalentManager.CurrentSpec != WoWSpec.ShamanEnhancement || !ShamanSettings.AvoidMaelstromDamage), new PrioritySelector( new PrioritySelector( ctx => Unit.NearbyUnfriendlyUnits .Where(u => (u.CreatureType == WoWCreatureType.Beast || u.CreatureType == WoWCreatureType.Humanoid) && Me.CurrentTargetGuid != u.Guid && (u.Aggro || u.PetAggro || (u.Combat && u.IsTargetingMeOrPet)) && !u.IsCrowdControlled() && u.SpellDistance().Between(10, 30) && Me.IsSafelyFacing(u) && u.InLineOfSpellSight && u.Location.Distance(Me.CurrentTarget.Location) > 10) .OrderByDescending(u => u.Distance) .FirstOrDefault(), Spell.Cast("Hex", onUnit => (WoWUnit)onUnit) ), // bind someone if we can new PrioritySelector( ctx => Unit.NearbyUnfriendlyUnits .Where(u => u.CreatureType == WoWCreatureType.Elemental && Me.CurrentTargetGuid != u.Guid && (u.Aggro || u.PetAggro || (u.Combat && u.IsTargetingMeOrPet)) && !u.IsCrowdControlled() && u.Distance.Between(10, 30) && Me.IsSafelyFacing(u) && u.InLineOfSpellSight && u.Location.Distance(Me.CurrentTarget.Location) > 10) .OrderByDescending(u => u.Distance) .FirstOrDefault(), Spell.Cast("Bind Elemental", onUnit => (WoWUnit)onUnit) ) ) ), new Decorator( ret => ShamanSettings.UseBloodlust && MovementManager.IsClassMovementAllowed, Spell.BuffSelf( PartyBuff.BloodlustSpellName, req => { // when Solo, use it if in a stressful fight if (SingularRoutine.CurrentWoWContext == WoWContext.Normal) { if (Unit.GroupMembers.Any(m => m.IsAlive && m.Distance < 100)) { return false; } return Common.StressfulSituation; } // should be manually cast when LazyRaiding, or by DungeonBuddy if (SingularRoutine.CurrentWoWContext == WoWContext.Instances) { return !Me.GroupInfo.IsInRaid && Me.CurrentTarget.IsBoss(); } return false; } ) ), Spell.BuffSelf("Ascendance", ret => ShamanSettings.UseAscendance && SingularRoutine.CurrentWoWContext == WoWContext.Normal && Common.StressfulSituation), Spell.BuffSelf("Elemental Mastery", ret => !PartyBuff.WeHaveBloodlust) // , Spell.BuffSelf("Spiritwalker's Grace", ret => Me.IsMoving && Me.Combat) ) )); }
public static Composite CreateRestoShamanHealingOnlyBehavior(bool selfOnly, bool moveInRange) { HealerManager.NeedHealTargeting = true; PrioritizedBehaviorList behavs = new PrioritizedBehaviorList(); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.AncestralSwiftness), "Unleash Elements", "Unleash Elements", Spell.Buff("Unleash Elements", ret => (WoWUnit)ret, ret => (Me.IsMoving || ((WoWUnit)ret).GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.AncestralSwiftness) && Common.IsImbuedForHealing(Me.Inventory.Equipped.MainHand) )); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.AncestralSwiftness), String.Format("Ancestral Swiftness @ {0}%", SingularSettings.Instance.Shaman.Heal.AncestralSwiftness), "Ancestral Swiftness", new Sequence( Spell.BuffSelf("Ancestral Swiftness", ret => ((WoWUnit)ret).GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.AncestralSwiftness), Spell.Heal("Greater Healing Wave", ret => (WoWUnit)ret) )); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.GreaterHealingWave), "Greater Healing Wave", "Greater Healing Wave", Spell.Heal("Greater Healing Wave", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.GreaterHealingWave)); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.HealingWave), "Healing Wave", "Healing Wave", Spell.Heal("Healing Wave", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.HealingWave)); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.HealingSurge), "Healing Surge", "Healing Surge", Spell.Heal("Healing Surge", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.HealingSurge)); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.ChainHeal), "Chain Heal", "Chain Heal", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( new PrioritySelector( context => Clusters.GetBestUnitForCluster(ChainHealPlayers, ClusterType.Chained, ChainHealHopRange), Spell.Heal( "Chain Heal", ret => (WoWPlayer)ret, ret => Clusters.GetClusterCount((WoWPlayer)ret, ChainHealPlayers, ClusterType.Chained, ChainHealHopRange) >= 3) ) ) ) ); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.HealingRain), "Healing Rain", "Healing Rain", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, new PrioritySelector( context => Clusters.GetBestUnitForCluster(Unit.NearbyFriendlyPlayers.Cast <WoWUnit>(), ClusterType.Radius, 10f), Spell.CastOnGround( "Healing Rain", ret => ((WoWPlayer)ret).Location, ret => (StyxWoW.Me.GroupInfo.IsInRaid ? 3 : 2) < Clusters.GetClusterCount((WoWPlayer)ret, Unit.NearbyFriendlyPlayers.Cast <WoWUnit>(), ClusterType.Radius, 10f)) ) ) ); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.SpiritLinkTotem), "Spirit Link Totem", "Spirit Link Totem", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, Spell.Cast( "Spirit Link Totem", ret => (WoWPlayer)ret, ret => Unit.NearbyFriendlyPlayers.Count( p => p.GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.SpiritLinkTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.SpiritLink)) >= (Me.GroupInfo.IsInRaid ? 3 : 2) ) ) ); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.HealingTideTotemPercent), "Healing Tide Totem", "Healing Tide Totem", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, Spell.Cast( "Healing Tide Totem", ret => Unit.NearbyFriendlyPlayers.Count(p => p.GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.HealingTideTotemPercent && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingTide)) >= (Me.GroupInfo.IsInRaid ? 3 : 2) ) ) ); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.HealingStreamTotem), "Healing Stream Totem", "Healing Stream Totem", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, Spell.Cast( "Healing Stream Totem", ret => Unit.NearbyFriendlyPlayers.Count(p => p.GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.HealingStreamTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingTide)) >= (Me.GroupInfo.IsInRaid ? 3 : 2) && !Totems.Exist(WoWTotemType.Water) ) ) ); behavs.AddBehavior(HealthToPriority(SingularSettings.Instance.Shaman.Heal.Ascendance), "Ascendance", "Ascendance", new Decorator( ret => StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid, Spell.BuffSelf( "Ascendance", ret => Unit.NearbyFriendlyPlayers.Count(p => p.GetPredictedHealthPercent() < SingularSettings.Instance.Shaman.Heal.Ascendance) >= (Me.GroupInfo.IsInRaid ? 3 : 2) ) ) ); behavs.OrderBehaviors(); behavs.ListBehaviors(); return(new PrioritySelector( ctx => selfOnly ? StyxWoW.Me : HealerManager.Instance.FirstUnit, // ctx => selfOnly ? StyxWoW.Me : GetHealTarget(), Spell.WaitForCast(), new Decorator( ret => Me.IsCasting, new ActionAlwaysSucceed()), new Decorator( ret => ret != null && ((WoWUnit)ret).GetPredictedHealthPercent() <= SingularSettings.Instance.IgnoreHealTargetsAboveHealth, new PrioritySelector( new Sequence( new Decorator( ret => guidLastHealTarget != ((WoWUnit)ret).Guid, new Action(ret => { guidLastHealTarget = ((WoWUnit)ret).Guid; Logger.WriteDebug(Color.LightGreen, "Heal Target - {0} {1:F1}% @ {2:F1} yds", ((WoWUnit)ret).SafeName(), ((WoWUnit)ret).GetPredictedHealthPercent(), ((WoWUnit)ret).Distance); })), new Action(ret => { return RunStatus.Failure; }) ), /* * new Sequence( * new Action(ret => Logger.WriteDebug(Color.LightGreen, "-- past spellcast")), * new Action(ret => { return RunStatus.Failure; }) * ), */ new Decorator( ret => !SpellManager.GlobalCooldown, new PrioritySelector( /* * new Sequence( * new Action(ret => Logger.WriteDebug(Color.LightGreen, "-- past gcd")), * new Action(ret => { return RunStatus.Failure; }) * ), */ Totems.CreateTotemsBehavior(), Spell.Heal("Earth Shield", ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret) && Group.Tanks.All(t => !t.HasMyAura("Earth Shield"))), // Just pop RT on CD. Plain and simple. Calling GetBestRiptideTarget will see if we can spread RTs (T12 2pc) Spell.Heal("Riptide", ret => GetBestRiptideTarget((WoWPlayer)ret), ret => !Me.HasAnyAura("Tidal Waves", "Ancestral Swiftness") && (((WoWPlayer)ret).GetPredictedHealthPercent() > 15 || Spell.GetSpellCooldown("Ancestral Swiftness").TotalMinutes > 0f) // use Ancestral Swiftness value to check ), behavs.GenerateBehaviorTree(), Spell.Heal("Riptide", ret => GetBestRiptideTarget((WoWPlayer)ret), ret => !Me.HasAura("Ancestral Swiftness")) #if false , new Sequence( new Action(ret => Logger.WriteDebug(Color.LightGreen, "No Action - stunned:{0} silenced:{1}" , Me.Stunned || Me.IsStunned() , Me.Silenced )), new Action(ret => { return RunStatus.Failure; }) ) , new Decorator( ret => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget && !Unit.NearbyFriendlyPlayers.Any(u => u.IsInMyPartyOrRaid), new PrioritySelector( Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.Cast("Earth Shock"), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )) #endif ) ), new Decorator( ret => moveInRange, Movement.CreateMoveToRangeAndStopBehavior(ret => (WoWUnit)ret, ret => 38f)) ) ) )); }
public static Composite CreateElementalNormalCombat() { return(new PrioritySelector( Helpers.Common.EnsureReadyToAttackFromLongRange(), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown(), new PrioritySelector( Helpers.Common.CreateInterruptBehavior(), Totems.CreateTotemsBehavior(), Movement.WaitForFacing(), Movement.WaitForLineOfSpellSight(), Dispelling.CreatePurgeEnemyBehavior("Purge"), Common.CreateShamanDpsShieldBehavior(), Spell.BuffSelf("Thunderstorm", ret => Unit.NearbyUnfriendlyUnits.Count(u => u.Distance < 10f) >= 3), Common.CastElementalBlast(), Spell.CastOnGround("Lightning Surge Totem", on => Clusters.GetBestUnitForCluster(Unit.NearbyUnfriendlyUnits, ClusterType.Radius, 8f).Location, ret => ShamanSettings.UseLightningSurgeTotem && SingularRoutine.CurrentWoWContext == WoWContext.Normal && Unit.UnfriendlyUnits(8).Count() >= ShamanSettings.LightningSurgeTotemCount), Spell.BuffSelf("Earth Elemental", ret => ShamanSettings.EarthElementalHealthPercent <= Me.HealthPercent), Spell.BuffSelf("Totem Mastery", req => !Me.HasAura("Ember Totem")), // Only one buff should need to be checked. Spell.Buff("Flame Shock", true, req => !Me.CurrentTarget.HasMyAura("Flame Shock") && Me.CurrentTarget.TimeToDeath(int.MaxValue) > 6), Spell.Cast("Fire Elemental"), Spell.Cast("Earth Shock", req => MaelstormDeficit <= 0), Spell.Cast("Ascendance"), Spell.BuffSelf("Elemental Mastery"), Spell.Cast("Lava Burst"), Spell.CastOnGround("Earthquake Totem", on => Clusters.GetBestUnitForCluster(Unit.NearbyUnfriendlyUnits, ClusterType.Radius, 8f).Location, req => Spell.UseAOE && Me.CurrentTarget.Distance < 34 && (Me.ManaPercent > ShamanSettings.EarthquakeMaelPercent || Me.GetAuraTimeLeft("Lucidity") > TimeSpan.Zero) && Unit.UnfriendlyUnitsNearTarget(10f).Count() >= ShamanSettings.EarthquakeCount - 1), Spell.Cast("Earth Shock", req => Me.CurrentMaelstrom >= 90), // Artifact Weapon new Decorator( ret => ShamanSettings.UseArtifactOnlyInAoE && Unit.UnfriendlyUnitsNearTarget(10f).Count() > 1, // Focused toward Chain Lightning new PrioritySelector( Spell.Cast("Stormkeeper", ret => ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.OnCooldown || !Common.HasTalent(ShamanTalents.Ascendance) || (ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.AtHighestDPSOpportunity && Common.HasTalent(ShamanTalents.Ascendance) && Spell.GetSpellCooldown("Ascendance") > TimeSpan.FromSeconds(15)) ) ) ), Spell.Cast("Stormkeeper", ret => ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.OnCooldown || !Common.HasTalent(ShamanTalents.Ascendance) || (ShamanSettings.UseDPSArtifactWeaponWhen == UseDPSArtifactWeaponWhen.AtHighestDPSOpportunity && Common.HasTalent(ShamanTalents.Ascendance) && Spell.GetSpellCooldown("Ascendance") > TimeSpan.FromSeconds(15)) ), Spell.Cast("Chain Lightning", ret => Spell.UseAOE && Unit.UnfriendlyUnitsNearTarget(10f).Count() > 1 && !Unit.UnfriendlyUnitsNearTarget(10f).Any(u => u.IsCrowdControlled())), Spell.Cast("Lightning Bolt") ) ) // Movement.CreateMoveToUnitBehavior( on => StyxWoW.Me.CurrentTarget, 38f, 33f) // Movement.CreateMoveToRangeAndStopBehavior(ret => Me.CurrentTarget, ret => NormalPullDistance) )); }
public static Composite CreateElementalNormalPull() { return(new PrioritySelector( Helpers.Common.EnsureReadyToAttackFromLongRange(), Spell.WaitForCastOrChannel(), new Decorator( ret => !Spell.IsGlobalCooldown(), new PrioritySelector( Common.CreateShamanDpsShieldBehavior(), Totems.CreateTotemsBehavior(), Spell.BuffSelf("Totem Mastery", req => !Me.HasAura("Ember Totem")), // Only one buff should need to be checked. Movement.WaitForFacing(), Movement.WaitForLineOfSpellSight(), // grinding or questing, if target meets these cast Flame Shock if possible // 1. mob is less than 12 yds, so no benefit from delay in Lightning Bolt missile arrival // 2. area has another player competing for mobs (we want to tag the mob quickly) new Decorator( ret => { if (StyxWoW.Me.CurrentTarget.IsHostile && StyxWoW.Me.CurrentTarget.Distance < 12) { Logger.WriteDiagnostic("NormalPull: fast pull since hostile target is {0:F1} yds away", StyxWoW.Me.CurrentTarget.Distance); return true; } WoWPlayer nearby = ObjectManager.GetObjectsOfType <WoWPlayer>(true, false).FirstOrDefault(p => !p.IsMe && p.DistanceSqr <= 40 * 40); if (nearby != null) { Logger.WriteDiagnostic("NormalPull: fast pull since player {0} nearby @ {1:F1} yds", nearby.SafeName(), nearby.Distance); return true; } return false; }, new PrioritySelector( // have a big attack loaded up, so don't waste it Spell.Cast("Earth Shock", ret => StyxWoW.Me.HasAura("Lightning Shield", 5)), Spell.Buff("Flame Shock", true, req => SpellManager.HasSpell("Lava Burst")), Spell.Cast("Earth Shock", ret => !SpellManager.HasSpell("Flame Shock")) ) ), // have a big attack loaded up, so don't waste it Spell.Cast("Earth Shock", ret => StyxWoW.Me.HasAura("Lightning Shield", 5)), // otherwise, start with Lightning Bolt so we can follow with an instant // to maximize damage at initial aggro Spell.Cast("Lightning Bolt"), // we are moving so throw an instant of some type Spell.Buff("Flame Shock", true, req => SpellManager.HasSpell("Lava Burst")), Spell.Buff("Lava Burst", true, req => Me.GotTarget() && Me.CurrentTarget.HasMyAura("Flame Shock")), Spell.Cast("Earth Shock") ) ) // Movement.CreateMoveToUnitBehavior( on => StyxWoW.Me.CurrentTarget, 38f, 33f) )); }