public static Composite CreateElementalPreCombatBuffsPvp() { return(new PrioritySelector( Common.CreateShamanDpsShieldBehavior(), Totems.CreateRecallTotems() )); }
public static Composite CreateEnhancementShamanPreCombatBuffs() { return(new PrioritySelector( new Decorator( ret => !Item.HasWeaponImbue(WoWInventorySlot.MainHand, "Windfury") && SpellManager.HasSpell("Windfury Weapon") && SpellManager.CanCast("Windfury Weapon", null, false, false), new Sequence( new Action(ret => Lua.DoString("CancelItemTempEnchantment(1) CancelItemTempEnchantment(2)")), new Action(ret => Logger.Write("Imbuing main hand weapon with Windfury")), new Action(ret => SpellManager.Cast("Windfury Weapon", null)))), new Decorator( ret => !Item.HasWeaponImbue(WoWInventorySlot.MainHand, "Flametongue") && !SpellManager.HasSpell("Windfury Weapon") && SpellManager.CanCast("Flametongue Weapon", null, false, false), new Sequence( new Action(ret => Lua.DoString("CancelItemTempEnchantment(1) CancelItemTempEnchantment(2)")), new Action(ret => Logger.Write("Imbuing main hand weapon with Flametongue")), new Action(ret => SpellManager.Cast("Flametongue Weapon", null)))), new Decorator( ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon && !Item.HasWeaponImbue(WoWInventorySlot.OffHand, "Flametongue") && StyxWoW.Me.Inventory.Equipped.MainHand != null && StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment != null && SpellManager.CanCast("Flametongue Weapon", null, false, false), new Sequence( new Action(ret => Lua.DoString("CancelItemTempEnchantment(2)")), new Action(ret => Logger.Write("Imbuing off hand weapon with Flametongue")), new Action(ret => SpellManager.Cast("Flametongue Weapon", null)))), Spell.Cast("Lightning Shield", ret => StyxWoW.Me, ret => !StyxWoW.Me.HasAura("Lightning Shield", 2)), new Decorator(ret => Totems.NeedToRecallTotems, new Action(ret => Totems.RecallTotems())) )); }
public static Composite CreateEnhancementShamanNormalPull() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Spell.Cast("Lightning Shield", ret => StyxWoW.Me, ret => !StyxWoW.Me.HasAura("Lightning Shield", 2)), new Decorator( ret => StyxWoW.Me.Level < 20, new PrioritySelector( new Decorator( ret => StyxWoW.Me.CurrentTarget.DistanceSqr < 40 * 40, Totems.CreateSetTotems()), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )), Common.CreateAutoAttack(true), new Decorator( ret => StyxWoW.Me.CurrentTarget.DistanceSqr < 20 * 20, Totems.CreateSetTotems()), Spell.Cast("Earth Shock"), Movement.CreateMoveToMeleeBehavior(true) )); }
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 CreateShamanEnhancementNormalPull() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Common.CreateShamanImbueMainHandBehavior(Imbue.Windfury, Imbue.Flametongue), Common.CreateShamanImbueOffHandBehavior(Imbue.Flametongue), Spell.BuffSelf("Lightning Shield"), new Decorator( ret => StyxWoW.Me.Level < 20, new PrioritySelector( Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )), Helpers.Common.CreateAutoAttack(true), new Decorator(ret => StyxWoW.Me.CurrentTarget.DistanceSqr < 20 * 20, Totems.CreateTotemsNormalBehavior()), Spell.Cast("Lightning Bolt", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Unleash Weapon", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.TemporaryEnchantment.Id == 5), Spell.Cast("Earth Shock"), Movement.CreateMoveToMeleeBehavior(true) )); }
public static Composite CreateShamanNonHealBehavior() { return (new PrioritySelector( new Decorator( ret => !StyxWoW.Me.Combat, Spell.Heal( "Healing Surge", ret => StyxWoW.Me, ret => StyxWoW.Me.HealthPercent <= 70) ), new Decorator( ret => StyxWoW.Me.Combat, new PrioritySelector( Spell.BuffSelf( "Healing Tide Totem", ret => Unit.NearbyFriendlyPlayers.Any( p => p.HealthPercent < SingularSettings.Instance.Shaman.HealingTideTotemPercent && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingTide))), Spell.BuffSelf( "Healing Stream Totem", ret => !Totems.Exist(WoWTotemType.Water) && Unit.NearbyFriendlyPlayers.Any( p => p.HealthPercent < SingularSettings.Instance.Shaman.HealHealingStreamTotem && p.Distance <= Totems.GetTotemRange(WoWTotem.HealingTide))), Spell.Heal( "Healing Surge", ret => StyxWoW.Me, ret => StyxWoW.Me.HealthPercent <= 30) ) ) )); }
public static Composite CreateEnhancementShamanInstancePullAndCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Totems.CreateSetTotems(), Common.CreateAutoAttack(true), Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Feral Spirit"), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( Spell.Cast("Unleash Elements"), Spell.BuffSelf("Magma Totem", ret => !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Magma)), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Lash", ret => StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") && StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), Spell.Cast("Fire Nova"), Spell.Cast("Chain Lightning", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Stormstrike"), Movement.CreateMoveToMeleeBehavior(true) )), // Totem stuff // Pop the ele on bosses Spell.BuffSelf("Fire Elemental Totem", ret => StyxWoW.Me.CurrentTarget.IsBoss() && StyxWoW.Me.CurrentTarget.DistanceSqr < 20 * 20 && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)), Spell.BuffSelf("Searing Totem", ret => StyxWoW.Me.CurrentTarget.Distance < Totems.GetTotemRange(WoWTotem.Searing) - 2f && !StyxWoW.Me.Totems.Any( t => t.Unit != null && t.WoWTotem == WoWTotem.Searing && t.Unit.Location.Distance(StyxWoW.Me.CurrentTarget.Location) < Totems.GetTotemRange(WoWTotem.Searing)) && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)), Spell.Cast("Stormstrike"), Spell.Cast("Primal Strike", ret => !SpellManager.HasSpell("Stormstrike")), Spell.Cast("Lava Lash", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), Spell.Cast("Lightning Bolt", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Unleash Elements"), Spell.Buff("Flame Shock", true, ret => StyxWoW.Me.HasAura("Unleash Wind") || !SpellManager.HasSpell("Unleash Elements")), Spell.Cast("Earth Shock", ret => StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 6), Movement.CreateMoveToMeleeBehavior(true) )); }
public static Composite CreateShamanEnhancementNormalCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Helpers.Common.CreateAutoAttack(true), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Common.CreateShamanImbueMainHandBehavior(Imbue.Windfury, Imbue.Flametongue), Common.CreateShamanImbueOffHandBehavior(Imbue.Flametongue), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Feral Spirit", ret => SingularSettings.Instance.Shaman.FeralSpiritCastOn == CastOn.All || (SingularSettings.Instance.Shaman.FeralSpiritCastOn == CastOn.Bosses && StyxWoW.Me.CurrentTarget.Elite) || (SingularSettings.Instance.Shaman.FeralSpiritCastOn == CastOn.Players && Unit.NearbyUnfriendlyUnits.Any(u => u.IsPlayer && u.Combat && u.IsTargetingMeOrPet))), Totems.CreateTotemsNormalBehavior(), Spell.BuffSelf("Elemental Mastery", ret => !StyxWoW.Me.HasAnyAura(Common.BloodlustName, "Time Warp", "Ancient Hysteria")), Common.CreateShamanInCombatBuffs(true), Spell.Cast("Stormstrike"), Spell.Buff("Flame Shock", true, ret => (StyxWoW.Me.HasAura("Unleash Flame") || !SpellManager.HasSpell("Unleash Elements")) && (StyxWoW.Me.CurrentTarget.Elite || (SpellManager.HasSpell("Fire Nova") && Unit.UnfriendlyUnitsNearTarget(10).Count(u => u.IsTargetingMeOrPet) >= 3))), Spell.Cast("Earth Shock", ret => StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 3 || !StyxWoW.Me.CurrentTarget.Elite || !SpellManager.HasSpell("Flame Shock")), Spell.Cast("Lava Lash", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), Spell.BuffSelf("Fire Nova", ret => StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") && Unit.NearbyUnfriendlyUnits.Count(u => u.IsTargetingMeOrPet && u.Location.DistanceSqr(StyxWoW.Me.CurrentTarget.Location) < 10 * 10) >= 3), Spell.Cast("Primal Strike", ret => !SpellManager.HasSpell("Stormstrike")), Spell.Cast("Unleash Elements"), new Decorator(ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5), new PrioritySelector( Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt") ) ), Movement.CreateMoveToMeleeBehavior(true) )); }
public static Composite CreateShamanElementalPvPPullAndCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), new Decorator( ret => !Common.InGCD, new PrioritySelector( Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), new Decorator( ret => Common.GetImbue(StyxWoW.Me.Inventory.Equipped.MainHand) == Imbue.None, Common.CreateShamanImbueMainHandBehavior(Imbue.Flametongue)), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Elemental Mastery", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat && (!SpellManager.HasSpell("Spiritwalker's Grace") || SpellManager.Spells["Spiritwalker's Grace"].Cooldown && !StyxWoW.Me.HasAura("Spiritwalker's Grace"))), Spell.BuffSelf("Thunderstorm", ret => StyxWoW.Me.IsStunned() && Unit.NearbyUnfriendlyUnits.Any(u => u.Distance < 10f)), Totems.CreateTotemsPvPBehavior(), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( // Pop the ele on bosses Spell.BuffSelf("Fire Elemental Totem", ret => !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)), Spell.CastOnGround("Earthquake", ret => StyxWoW.Me.CurrentTarget.Location), Spell.Cast("Chain Lightning", ret => Clusters.GetBestUnitForCluster(Unit.UnfriendlyUnitsNearTarget(15f), ClusterType.Chained, 12)) )), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Burst"), Spell.Cast("Earth Shock", ret => StyxWoW.Me.HasAura("Lightning Shield", 5) && StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 3), Spell.Cast("Unleash Elements", ret => StyxWoW.Me.IsMoving && !StyxWoW.Me.HasAura("Spiritwalker's Grace") && Common.IsImbuedForDPS(StyxWoW.Me.Inventory.Equipped.MainHand)), Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt") ) ), Movement.CreateMoveToTargetBehavior(true, 35f) )); }
public static Composite CreateShamanElementalPreCombatBuffs() { return(new PrioritySelector( Common.CreateShamanImbueMainHandBehavior(Imbue.Flametongue), Spell.BuffSelf("Lightning Shield"), new Decorator(ret => Totems.NeedToRecallTotems, new Action(ret => Totems.RecallTotems())) )); }
public static Composite CreateElementalShamanInstancePullAndCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Totems.CreateSetTotems(), Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Elemental Mastery", ret => StyxWoW.Me.HasAnyAura("Bloodlust", "Heroism", "Time Warp", "Ancient Hysteria")), Spell.BuffSelf("Elemental Mastery", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat && (!SpellManager.HasSpell("Spiritwalker's Grace") || SpellManager.Spells["Spiritwalker's Grace"].Cooldown && !StyxWoW.Me.HasAura("Spiritwalker's Grace"))), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( Spell.CastOnGround("Earthquake", ret => StyxWoW.Me.CurrentTarget.Location), Spell.Cast("Chain Lightning", ret => Clusters.GetBestUnitForCluster(Unit.UnfriendlyUnitsNearTarget(15f), ClusterType.Chained, 12)) )), // Totem stuff // Pop the ele on bosses Spell.BuffSelf("Fire Elemental Totem", ret => StyxWoW.Me.CurrentTarget.IsBoss() && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)), Spell.BuffSelf("Searing Totem", ret => StyxWoW.Me.CurrentTarget.Distance < Totems.GetTotemRange(WoWTotem.Searing) - 2f && !StyxWoW.Me.Totems.Any( t => t.Unit != null && t.WoWTotem == WoWTotem.Searing && t.Unit.Location.Distance(StyxWoW.Me.CurrentTarget.Location) < Totems.GetTotemRange(WoWTotem.Searing)) && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Burst"), Spell.Cast("Earth Shock", ret => (StyxWoW.Me.HasAura("Lightning Shield", 7) || TalentManager.GetCount(1, 13) == 0) && StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 6), Spell.Cast("Unleash Elements", ret => Item.HasWeaponImbue(WoWInventorySlot.MainHand, "Flametongue") && StyxWoW.Me.IsMoving && !StyxWoW.Me.HasAura("Spiritwalker's Grace")), Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )); }
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 CreateElementalShamanPreCombatBuffs() { return(new PrioritySelector( new Decorator( ret => !Item.HasWeaponImbue(WoWInventorySlot.MainHand, "Flametongue") && SpellManager.HasSpell("Flametongue Weapon") && SpellManager.CanCast("Flametongue Weapon", null, false, false), new Sequence( new Action(ret => Lua.DoString("CancelItemTempEnchantment(1)")), new Action(ret => Logger.Write("Imbuing main hand weapon with Flametongue")), new Action(ret => SpellManager.Cast("Flametongue Weapon", null)) )), Spell.Cast("Lightning Shield", ret => StyxWoW.Me, ret => !StyxWoW.Me.HasAura("Lightning Shield", 2)), new Decorator(ret => Totems.NeedToRecallTotems, new Action(ret => Totems.RecallTotems())) )); }
public static Composite CreateShamanEnhancementPvPPullAndCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), new Decorator( ret => !SpellManager.GlobalCooldown, new PrioritySelector( Helpers.Common.CreateAutoAttack(true), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Common.CreateShamanImbueMainHandBehavior(Imbue.Windfury, Imbue.Flametongue), Common.CreateShamanImbueOffHandBehavior(Imbue.Frostbrand, Imbue.Flametongue), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Feral Spirit"), Totems.CreateTotemsPvPBehavior(), Spell.Cast("Stormstrike"), Spell.Cast("Primal Strike", ret => !SpellManager.HasSpell("Stormstrike")), Spell.Cast("Lava Lash", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), new Decorator(ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5) && (StyxWoW.Me.GetAuraTimeLeft("Maelstom Weapon", true).TotalSeconds < 3000 || StyxWoW.Me.GetPredictedHealthPercent() > 90), new PrioritySelector( Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt") ) ), Spell.Cast("Unleash Elements"), Spell.Buff("Flame Shock", true, ret => StyxWoW.Me.HasAura("Unleash Wind") || !SpellManager.HasSpell("Unleash Elements")), Spell.Cast("Earth Shock", ret => StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 6) ) ), Movement.CreateMoveToMeleeBehavior(true) )); }
private static bool IsMagmaTotemNeeded() { if (Spell.UseAOE && Me.GotTarget() && TotemIsKnown(WoWTotem.Magma) && AllowDpsTotems) { WoWTotemInfo ti = GetTotem(WoWTotemType.Fire); if (ti.WoWTotem == WoWTotem.FireElemental) { return(false); } // for existing magma return no cast needed if it has enough mobs float rangeCheck = rangeCheck = Totems.GetTotemRange(WoWTotem.Magma); if (ti.WoWTotem == WoWTotem.Magma) { int existcount = Unit.NearbyUnitsInCombatWithUsOrOurStuff.Count(u => ti.Unit.SpellDistance(u) < rangeCheck); if (existcount >= 3) { return(false); } } // so no good magma in range, so now check if we want one to be int nearcount = Unit.NearbyUnitsInCombatWithUsOrOurStuff.Count(u => u.SpellDistance() < rangeCheck); if (nearcount < 3) { return(false); } if (ti.WoWTotem == WoWTotem.Magma) { Logger.WriteDebug("IsMagmaTotemNeeded: existing Magma out of range, resetting since {0} mobs near me", nearcount); } else { Logger.WriteDebug("IsMagmaTotemNeeded: found {0} mobs near me, setting Magma", nearcount); } return(true); } return(false); }
public static Composite CreateShamanElementalNormalPull() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Spell.BuffSelf("Lightning Shield"), new Decorator( ret => StyxWoW.Me.CurrentTarget.DistanceSqr < 40 * 40, Totems.CreateTotemsNormalBehavior()), // 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 => StyxWoW.Me.CurrentTarget.Distance < 12 || ObjectManager.GetObjectsOfType <WoWPlayer>(true, false).Any(p => p.Location.DistanceSqr(StyxWoW.Me.CurrentTarget.Location) <= 40 * 40), new PrioritySelector( Spell.Buff("Flame Shock", true), Spell.Cast("Unleash Weapon", ret => Common.IsImbuedForDPS(StyxWoW.Me.Inventory.Equipped.MainHand)), 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", ret => !StyxWoW.Me.IsMoving || StyxWoW.Me.HasAura("Spiritwalker's Grace") || TalentManager.HasGlyph("Unleashed Lightning")), // we are moving so throw an instant of some type Spell.Cast("Flame Shock"), Spell.Cast("Unleash Weapon", ret => Common.IsImbuedForDPS(StyxWoW.Me.Inventory.Equipped.MainHand)), Movement.CreateMoveToTargetBehavior(true, 35f) )); }
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 CreateShamanElementalInstancePullAndCombat() { return(new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Common.CreateShamanImbueMainHandBehavior(Imbue.Flametongue), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Elemental Mastery", ret => StyxWoW.Me.Combat), Totems.CreateTotemsInstanceBehavior(), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( new Action(act => { Logger.WriteDebug("performing aoe behavior"); return RunStatus.Failure; }), Spell.CastOnGround("Earthquake", ret => StyxWoW.Me.CurrentTarget.Location), Spell.Cast("Chain Lightning", ret => Clusters.GetBestUnitForCluster(Unit.UnfriendlyUnitsNearTarget(15f), ClusterType.Chained, 12)) )), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Burst"), Spell.Cast("Earth Shock", ret => StyxWoW.Me.HasAura("Lightning Shield", 5) && StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 3), Spell.Cast("Unleash Elements", ret => StyxWoW.Me.IsMoving && !StyxWoW.Me.HasAura("Spiritwalker's Grace") && Common.IsImbuedForDPS(StyxWoW.Me.Inventory.Equipped.MainHand)), Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )); }
public static Composite CreateShamanEnhancementInstancePullAndCombat() { return(new PrioritySelector( Spell.WaitForCast(true), Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving && StyxWoW.Me.Combat), Spell.BuffSelf("Feral Spirit", ret => Unit.IsBoss(Me.CurrentTarget)), Totems.CreateTotemsNormalBehavior(), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( Spell.Cast("Shamanistic Rage", ret => Me.CurrentMana <= 70), Spell.Cast("Unleash Elements"), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Lash", ret => StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") && StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), Spell.Cast("Fire Nova"), Spell.Cast("Chain Lightning", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Stormstrike"), Movement.CreateMoveToMeleeBehavior(true) )), Spell.Cast("Stormstrike"), Spell.Cast("Primal Strike", ret => !SpellManager.HasSpell("Stormstrike")), Spell.Cast("Lava Lash", ret => StyxWoW.Me.Inventory.Equipped.OffHand != null && StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon), Spell.Cast("Lightning Bolt", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)), Spell.Cast("Unleash Elements"), Spell.Buff("Flame Shock", true, ret => StyxWoW.Me.HasAura("Unleash Flame") || !SpellManager.HasSpell("Unleash Elements")), Spell.Cast("Earth Shock", ret => StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 6) )); }
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 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 CreateShamanElementalNormalCombat() { return(new PrioritySelector( new ThrottlePasses(1, CreateElementalDiagnosticOutputBehavior()), Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Spell.WaitForCast(true), new Decorator( ret => !Common.InGCD, new PrioritySelector( Helpers.Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), new Decorator( ret => Common.GetImbue(StyxWoW.Me.Inventory.Equipped.MainHand) == Imbue.None, Common.CreateShamanImbueMainHandBehavior(Imbue.Flametongue)), Spell.BuffSelf("Lightning Shield"), Spell.BuffSelf("Elemental Mastery", ret => Unit.NearbyUnitsInCombatWithMe.Any(u => u.Elite || u.IsPlayer) && !StyxWoW.Me.HasAnyAura(Common.BloodlustName, "Time Warp", "Ancient Hysteria")), Common.CreateShamanInCombatBuffs(true), Spell.BuffSelf("Spiritwalker's Grace", ret => StyxWoW.Me.IsMoving), Spell.BuffSelf("Thunderstorm", ret => Unit.NearbyUnfriendlyUnits.Count(u => u.Distance < 10f) >= 3), Totems.CreateTotemsNormalBehavior(), new Decorator( ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 3, new PrioritySelector( new Action(act => { Logger.WriteDebug("performing aoe behavior"); return RunStatus.Failure; }), Spell.BuffSelf("Astral Shift", ret => StyxWoW.Me.HealthPercent < 40 || Unit.NearbyUnitsInCombatWithMe.Count() >= 5), Spell.BuffSelf(Common.BloodlustName, ret => Unit.NearbyUnitsInCombatWithMe.Count() >= 5 || Unit.NearbyUnitsInCombatWithMe.Any(u => u.Elite || u.IsPlayer)), Spell.BuffSelf("Elemental Mastery", ret => !StyxWoW.Me.HasAnyAura(Common.BloodlustName, "Time Warp", "Ancient Hysteria")), Spell.CastOnGround("Earthquake", ret => StyxWoW.Me.CurrentTarget.Location, req => (StyxWoW.Me.ManaPercent > 60 || StyxWoW.Me.HasAura("Clearcasting")) && Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 6), Spell.Cast("Chain Lightning", ret => Clusters.GetBestUnitForCluster(Unit.UnfriendlyUnitsNearTarget(15f), ClusterType.Chained, 12)) )), Spell.Buff("Flame Shock", true), Spell.Cast("Lava Burst"), Spell.Cast("Earth Shock", ret => StyxWoW.Me.HasAura("Lightning Shield", 5) && StyxWoW.Me.CurrentTarget.GetAuraTimeLeft("Flame Shock", true).TotalSeconds > 3), Spell.Cast("Unleash Elements", ret => StyxWoW.Me.IsMoving && !StyxWoW.Me.HasAura("Spiritwalker's Grace") && Common.IsImbuedForDPS(StyxWoW.Me.Inventory.Equipped.MainHand)), Spell.Cast("Chain Lightning", ret => Unit.UnfriendlyUnitsNearTarget(10f).Count() >= 2), Spell.Cast("Lightning Bolt") ) ), Movement.CreateMoveToTargetBehavior(true, 35f) )); }
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 CreateTotemsNormalBehavior() { // create Fire Totems behavior first, then wrap if needed PrioritySelector fireTotemBehavior = new PrioritySelector(); fireTotemBehavior.AddChild( Spell.Buff(WoWTotem.FireElemental.ToSpellId(), req => Common.StressfulSituation && Totems.AllowElementalTotems && !Exist(WoWTotem.EarthElemental) && !Spell.CanCastHack("Earth Elemental Totem") ) ); if (TalentManager.CurrentSpec == WoWSpec.ShamanEnhancement) { fireTotemBehavior.AddChild( Spell.Cast("Magma Totem", on => Me.CurrentTarget ?? Me, ret => IsMagmaTotemNeeded()) ); } fireTotemBehavior.AddChild( Spell.BuffSelf("Searing Totem", ret => IsSearingTotemNeeded()) ); if (TalentManager.CurrentSpec == WoWSpec.ShamanRestoration) { fireTotemBehavior = new PrioritySelector( new Decorator( ret => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget() && !Unit.NearbyGroupMembers.Any(), fireTotemBehavior ) ); } // now return(new PrioritySelector( new Throttle(1, new Action(r => { bool ccMechanic = Me.HasAuraWithMechanic(WoWSpellMechanic.Fleeing | WoWSpellMechanic.Polymorphed | WoWSpellMechanic.Asleep); bool ccEffect = Me.HasAuraWithEffect(WoWApplyAuraType.ModFear | WoWApplyAuraType.ModPacify | WoWApplyAuraType.ModPacifySilence); bool ccAttrib = Me.Fleeing; if (ccMechanic || ccEffect || ccAttrib) { Logger.WriteDebug(Color.Pink, "... FEAR CHECKED OUT -- Mechanic={0} Effect={1} Attrib={2}", ccMechanic, ccEffect, ccAttrib); } return RunStatus.Failure; }) ), Spell.BuffSelf(WoWTotem.Tremor.ToSpellId(), ret => Unit.GroupMembers.Any(f => f.Fleeing && f.Distance < Totems.GetTotemRange(WoWTotem.Tremor)) && !Exist(WoWTotem.StoneBulwark, WoWTotem.EarthElemental)), new Decorator( req => PetManager.NeedsPetSupport && Totems.ExistInRange(Me.Location, WoWTotem.EarthElemental) && !Me.HasAura("Reinforce") && !Spell.DoubleCastContains(Me, "Reinforce"), new Sequence( PetManager.CastAction("Reinforce", on => Me), new Action(r => Spell.UpdateDoubleCast("Reinforce", Me)) ) ), new Decorator( req => PetManager.NeedsPetSupport && Totems.ExistInRange(Me.Location, WoWTotem.FireElemental) && !Me.HasAura("Empower") && !Spell.DoubleCastContains(Me, "Empower"), new Sequence( PetManager.CastAction("Empower", on => Me), new Action(r => Spell.UpdateDoubleCast("Empower", Me)) ) ), new Decorator( ret => ShouldWeDropTotemsYet, new PrioritySelector( // check for stress - enemy player or elite within 8 levels nearby // .. dont use NearbyUnitsInCombatWithMe since it checks .Tagged and we only care if we are being attacked ctx => Common.StressfulSituation, // earth totems Spell.BuffSelf(WoWTotem.EarthElemental.ToSpellId(), ret => ((bool)ret || Group.Tanks.Any(t => t.IsDead && t.Distance < 40)) && Totems.AllowElementalTotems && !Exist(WoWTotem.StoneBulwark) ), Spell.BuffSelf(WoWTotem.StoneBulwark.ToSpellId(), ret => Me.Combat && Me.HealthPercent < ShamanSettings.StoneBulwarkTotemPercent && !Exist(WoWTotem.EarthElemental)), new PrioritySelector( ctx => Unit.NearbyUnfriendlyUnits.Any(u => u.IsTargetingMeOrPet && u.IsPlayer && u.Combat), Spell.BuffSelf(WoWTotem.Earthgrab.ToSpellId(), ret => (bool)ret && !Exist(WoWTotemType.Earth)), Spell.BuffSelf(WoWTotem.Earthbind.ToSpellId(), ret => (bool)ret && !Exist(WoWTotemType.Earth)) ), // fire totems fireTotemBehavior, // water totems Spell.BuffSelf("Mana Tide Totem", ret => { if (TalentManager.CurrentSpec != WoWSpec.ShamanRestoration) { return false; } // Logger.WriteDebug("Mana Tide Totem Check: current mana {0:F1}%", Me.ManaPercent); if (Me.ManaPercent > ShamanSettings.ManaTideTotemPercent) { return false; } if (Exist(WoWTotem.HealingTide, WoWTotem.HealingStream)) { return false; } return true; }), /* Healing...: handle within Helaing logic * Spell.Cast("Healing Tide Totem", ret => ((bool)ret) && StyxWoW.Me.HealthPercent < 50 * && !Exist(WoWTotem.ManaTide)), * * Spell.Cast("Healing Stream Totem", ret => ((bool)ret) && StyxWoW.Me.HealthPercent < 80 * && !Exist( WoWTotemType.Water)), */ // air totems Spell.Cast("Stormlash Totem", ret => PartyBuff.WeHaveBloodlust && !Me.HasAura("Stormlash Totem")), new Decorator( ret => !Exist(WoWTotemType.Air), new PrioritySelector( Spell.Cast("Grounding Totem", ret => Unit.NearbyUnfriendlyUnits.Any(u => u.SpellDistance() < 40 && u.IsTargetingMeOrPet && u.IsCasting)), Spell.Cast("Capacitor Totem", ret => ((bool)ret) && Unit.NearbyUnfriendlyUnits.Any(u => u.SpellDistance() < GetTotemRange(WoWTotem.Capacitor))), Spell.BuffSelf("Windwalk Totem", ret => Unit.HasAuraWithMechanic(StyxWoW.Me, WoWSpellMechanic.Rooted, WoWSpellMechanic.Snared)) ) ) ) ) )); }
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; return(new PrioritySelector( ctx => selfOnly ? StyxWoW.Me : HealerManager.Instance.FirstUnit, new Decorator( ret => ret != null && (moveInRange || ((WoWUnit)ret).InLineOfSpellSight && ((WoWUnit)ret).DistanceSqr < 40 * 40), new PrioritySelector( Spell.WaitForCast(), new Decorator( ret => moveInRange, Movement.CreateMoveToLosBehavior(ret => (WoWUnit)ret)), Totems.CreateSetTotems(), // Mana tide... Spell.Cast("Mana Tide Totem", ret => StyxWoW.Me.ManaPercent < 80), // Grounding... Spell.Cast("Grounding Totem", ret => Unit.NearbyUnfriendlyUnits.Any(u => u.Distance < 40 && u.IsTargetingMeOrPet && u.IsCasting)), // 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)), // And deal with some edge PVP cases. Spell.Heal("Earth Shield", ret => (WoWUnit)ret, ret => ret is WoWPlayer && Group.Tanks.Contains((WoWPlayer)ret) && Group.Tanks.All(t => !t.HasMyAura("Earth Shield"))), // Pop NS if someone is in some trouble. Spell.BuffSelf("Nature's Swiftness", ret => ((WoWUnit)ret).HealthPercent < 15), Spell.Heal("Unleash Elements", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < 40), // GHW is highest priority. It should be fairly low health %. (High-end healers will have this set to 70ish Spell.Heal("Greater Healing Wave", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < 50), // Most (if not all) will leave this at 90. Its lower prio, high HPM, low HPS Spell.Heal("Healing Wave", ret => (WoWUnit)ret, ret => ((WoWUnit)ret).HealthPercent < 60), // CH/HR only in parties/raids new Decorator( ret => StyxWoW.Me.IsInParty || StyxWoW.Me.IsInRaid, new PrioritySelector( // This seems a bit tricky, but its really not. This is just how we cache a somewhat expensive lookup. // Set the context to the "best unit" for the cluster, so we don't have to do that check twice. // Then just use the context when passing the unit to throw the heal on, and the target of the heal from the cluster count. // Also ensure it will jump at least 3 times. (CH is pointless to cast if it won't jump 3 times!) new PrioritySelector( context => Clusters.GetBestUnitForCluster(ChainHealPlayers, ClusterType.Chained, 12f), Spell.Heal( "Chain Heal", ret => (WoWPlayer)ret, ret => Clusters.GetClusterCount((WoWPlayer)ret, ChainHealPlayers, ClusterType.Chained, 12f) > 2)), // Now we're going to do the same thing as above, but this time we're going to do it with healing rain. new PrioritySelector( context => Clusters.GetBestUnitForCluster(Unit.NearbyFriendlyPlayers.Cast <WoWUnit>(), ClusterType.Radius, 10f), Spell.CastOnGround( "Healing Rain", ret => ((WoWPlayer)ret).Location, ret => Clusters.GetClusterCount((WoWPlayer)ret, Unit.NearbyFriendlyPlayers.Cast <WoWUnit>(), ClusterType.Radius, 10f) > // If we're in a raid, check for 4 players. If we're just in a party, check for 3. (StyxWoW.Me.IsInRaid ? 3 : 2))))), new Decorator( ret => moveInRange, Movement.CreateMoveToTargetBehavior(true, 38f, ret => (WoWUnit)ret)) )))); }
public static Composite CreateShamanDpsHealBehavior() { Composite offheal; if (!SingularSettings.Instance.DpsOffHealAllowed) { offheal = new ActionAlwaysFail(); } else { offheal = new Decorator( ret => HealerManager.ActingAsOffHealer, CreateDpsShamanOffHealBehavior() ); } return(new Decorator( ret => !Spell.IsGlobalCooldown() && !Spell.IsCastingOrChannelling(), new PrioritySelector( new Decorator( ret => !Me.Combat && (!Me.IsMoving || Me.HasAura("Maelstrom Weapon", 5)) && Me.HealthPercent <= 85 && // not redundant... this eliminates unnecessary GetPredicted... checks SpellManager.HasSpell("Healing Surge") && Me.PredictedHealthPercent(includeMyHeals: true) < 85, new PrioritySelector( new Sequence( ctx => (float)Me.HealthPercent, new Action(r => Logger.WriteDebug("Healing Surge: {0:F1}% Predict:{1:F1}% and moving:{2}, cancast:{3}", (float)r, Me.PredictedHealthPercent(includeMyHeals: true), Me.IsMoving, Spell.CanCastHack("Healing Surge", Me, skipWowCheck: false))), Spell.Cast( "Healing Surge", mov => true, on => Me, req => true, cancel => Me.HealthPercent > 85 ), new WaitContinue(TimeSpan.FromMilliseconds(500), until => !Me.IsCasting && Me.HealthPercent > (1.1 * ((float)until)), new ActionAlwaysSucceed()), new Action(r => Logger.WriteDebug("Healing Surge: After Heal Attempted: {0:F1}% Predicted: {1:F1}%", Me.HealthPercent, Me.PredictedHealthPercent(includeMyHeals: true))) ), new Action(r => Logger.WriteDebug("Healing Surge: After Heal Skipped: {0:F1}% Predicted: {1:F1}%", Me.HealthPercent, Me.PredictedHealthPercent(includeMyHeals: true))) ) ), new Decorator( ret => Me.Combat, new PrioritySelector( 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 < ShamanSettings.ShamanisticRagePercent || Common.StressfulSituation), Spell.HandleOffGCD( Spell.BuffSelf("Ancestral Guidance", ret => Me.HealthPercent < ShamanSettings.SelfAncestralGuidance && Me.GotTarget() && Me.CurrentTarget.TimeToDeath() > 8 ) ), new Decorator( req => !Me.IsMoving && ShamanSettings.SelfHealingStreamTotem > 0 && !Totems.Exist(WoWTotemType.Water), Spell.BuffSelf( WoWTotem.HealingStream.ToSpellId(), req => { int count = Unit.NearbyUnitsInCombatWithMeOrMyStuff.Count(u => !u.IsTrivial()); if (count > 1) { return true; } if (count > 0 && Me.HealthPercent < ShamanSettings.SelfHealingStreamTotem) { if (!Me.GotTarget() || Me.CurrentTarget.IsPlayer || Me.CurrentTarget.TimeToDeath() > 5) { return true; } if (Me.HealthPercent < (ShamanSettings.SelfHealingStreamTotem / 2)) { return true; } } return false; } ) ), // save myself if possible new Decorator( ret => (!Me.IsInGroup() || Battlegrounds.IsInsideBattleground) && (!Me.IsMoving || Me.HasAura("Maelstrom Weapon", 5) || !Spell.IsSpellOnCooldown("Ancestral Swiftness")) && Me.HealthPercent < ShamanSettings.SelfAncestralSwiftnessHeal && Me.PredictedHealthPercent(includeMyHeals: true) < ShamanSettings.SelfAncestralSwiftnessHeal, new PrioritySelector( Spell.HandleOffGCD(Spell.BuffSelf("Ancestral Swiftness")), new PrioritySelector( new Sequence( ctx => (float)Me.HealthPercent, new Action(r => Logger.WriteDebug("Healing Surge: {0:F1}% Predict:{1:F1}% and moving:{2}, cancast:{3}", (float)r, Me.PredictedHealthPercent(includeMyHeals: true), Me.IsMoving, Spell.CanCastHack("Healing Surge", Me, skipWowCheck: false))), Spell.Cast( "Healing Surge", mov => true, on => Me, req => true, cancel => Me.HealthPercent > 85 ), new WaitContinue(TimeSpan.FromMilliseconds(500), until => !Me.IsCasting && Me.HealthPercent > (1.1 * ((float)until)), new ActionAlwaysSucceed()), new Action(r => Logger.WriteDebug("Healing Surge: After Heal Attempted: {0:F1}% Predicted: {1:F1}%", Me.HealthPercent, Me.PredictedHealthPercent(includeMyHeals: true))) ), new Action(r => Logger.WriteDebug("Healing Surge: After Heal Skipped: {0:F1}% Predicted: {1:F1}%", Me.HealthPercent, Me.PredictedHealthPercent(includeMyHeals: true))) ) ) ) ) ), offheal ) )); }
public static Composite CreateTotemsInstanceBehavior() { // create Fire Totems behavior first, then wrap if needed PrioritySelector fireTotemBehavior = new PrioritySelector(); fireTotemBehavior.AddChild( Spell.Buff( "Fire Elemental Totem", req => Me.CurrentTarget.IsBoss() && AllowElementalTotems ) ); if (TalentManager.CurrentSpec == WoWSpec.ShamanEnhancement) { fireTotemBehavior.AddChild( Spell.Cast("Magma Totem", on => Me.CurrentTarget ?? Me, ret => IsMagmaTotemNeeded()) ); } if (TalentManager.CurrentSpec == WoWSpec.ShamanRestoration) { fireTotemBehavior = new PrioritySelector( new Decorator( ret => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget() && !HealerManager.Instance.TargetList.Any(m => m.IsAlive), fireTotemBehavior ) ); } else { fireTotemBehavior.AddChild( Spell.Cast("Searing Totem", ret => IsSearingTotemNeeded()) ); } // now return(new PrioritySelector( Spell.BuffSelf(WoWTotem.Tremor.ToSpellId(), ret => Unit.GroupMembers.Any(f => f.Fleeing && f.Distance < Totems.GetTotemRange(WoWTotem.Tremor)) && !Exist(WoWTotem.StoneBulwark, WoWTotem.EarthElemental)), new Decorator( req => Totems.ExistInRange(Me.Location, WoWTotem.EarthElemental) && !Me.HasAura("Reinforce") && !Spell.DoubleCastContains(Me, "Reinforce"), new Sequence( PetManager.CastAction("Reinforce", on => Me), new Action(r => Spell.UpdateDoubleCast("Reinforce", Me)) ) ), new Decorator( req => Totems.ExistInRange(Me.Location, WoWTotem.FireElemental) && !Me.HasAura("Empower") && !Spell.DoubleCastContains(Me, "Empower"), new Sequence( PetManager.CastAction("Empower", on => Me), new Action(r => Spell.UpdateDoubleCast("Empower", Me)) ) ), new Decorator( ret => ShouldWeDropTotemsYet, new PrioritySelector( // earth totems Spell.Cast(WoWTotem.EarthElemental.ToSpellId(), on => Me.CurrentTarget ?? Me, req => { if (!Totems.AllowElementalTotems) { return false; } if (Exist(WoWTotem.StoneBulwark)) { return false; } if (Spell.IsSpellOnCooldown("Earth Elemental Totem")) { return false; } // no living tanks in range IEnumerable <WoWUnit> tanks = Group.Tanks.Where(u => u.DistanceSqr < 65 * 65); if (!tanks.Any(t => t.IsAlive) || tanks.Any(t => t.IsDead)) { // we are okay if another Earth Elemental active if (ObjectManager.GetObjectsOfType <WoWUnit>(false, false).Any(o => o.Entry == 15352)) { return false; } // we are okay if nothing in combat with our group if (!Unit.NearbyUnitsInCombatWithUsOrOurStuff.Any()) { return false; } } // check we can cast it before messaging if (!Spell.CanCastHack("Earth Elemental Totem")) { return false; } Logger.Write(LogColor.Hilite, "^Earth Elemental Totem: tank is dead or not nearby"); return true; }), // Stone Bulwark handled in CombatBuffs with Astral Shift // fire totems fireTotemBehavior, // water totems Spell.BuffSelf("Mana Tide Totem", ret => { if (TalentManager.CurrentSpec != WoWSpec.ShamanRestoration) { return false; } // Logger.WriteDebug("Mana Tide Totem Check: current mana {0:F1}%", Me.ManaPercent); if (Me.ManaPercent > ShamanSettings.ManaTideTotemPercent) { return false; } if (Exist(WoWTotem.HealingTide, WoWTotem.HealingStream)) { return false; } return true; }), /* Healing...: handle within Helaing logic * Spell.Cast("Healing Tide Totem", ret => ((bool)ret) && StyxWoW.Me.HealthPercent < 50 * && !Exist(WoWTotem.ManaTide)), * * Spell.Cast("Healing Stream Totem", ret => ((bool)ret) && StyxWoW.Me.HealthPercent < 80 * && !Exist( WoWTotemType.Water)), */ // air totems Spell.Cast("Stormlash Totem", ret => PartyBuff.WeHaveBloodlust && !Me.HasAura("Stormlash Totem")), new Decorator( ret => !Exist(WoWTotemType.Air), new PrioritySelector( Spell.Cast("Grounding Totem", on => Unit.NearbyUnfriendlyUnits.FirstOrDefault(u => u.SpellDistance() < 40 && u.IsTargetingMeOrPet && u.IsCasting)), Spell.Cast("Capacitor Totem", on => Unit.NearbyUnfriendlyUnits.FirstOrDefault(u => u.SpellDistance() < GetTotemRange(WoWTotem.Capacitor) && u.IsTargetingMeOrPet)), Spell.BuffSelf("Windwalk Totem", ret => Unit.HasAuraWithMechanic(StyxWoW.Me, WoWSpellMechanic.Rooted, WoWSpellMechanic.Snared)) ) ) ) ) )); }