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 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) )); }
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 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 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 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)) ) ) ) ) )); }
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 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 CreateTotemsNormalBehavior() { // create Fire Totems behavior first, then wrap if needed Composite fireTotemBehavior = new PrioritySelector( Spell.BuffSelf("Fire Elemental", ret => ((bool)ret) || (Unit.NearbyUnitsInCombatWithMe.Count() >= StressMobCount && !SpellManager.CanBuff(WoWTotem.EarthElemental.ToSpellId(), false))), // Magma - handle within AoE DPS logic only Spell.BuffSelf("Magma Totem", ret => Unit.NearbyUnitsInCombatWithMe.Count(u => u.Distance <= GetTotemRange(WoWTotem.Magma)) >= StressMobCount && !Exist(WoWTotem.FireElemental)), Spell.BuffSelf("Searing Totem", ret => Me.GotTarget && Me.CurrentTarget.Distance < GetTotemRange(WoWTotem.Searing) - 2f && !Exist(WoWTotemType.Fire)) ); if (Me.Specialization == WoWSpec.ShamanRestoration) { fireTotemBehavior = new Decorator(ret => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget && Unit.NearbyFriendlyPlayers.Count(u => u.IsInMyPartyOrRaid) == 0, fireTotemBehavior); } // now return(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 => Unit.NearbyUnitsInCombatWithMe.Count() >= StressMobCount || Unit.NearbyUnfriendlyUnits.Any(u => u.IsTargetingMeOrPet && (u.IsPlayer || (u.Elite && u.Level + 8 > Me.Level))), // earth totems Spell.BuffSelf(WoWTotem.EarthElemental.ToSpellId(), ret => (bool)ret && !Exist(WoWTotem.StoneBulwark)), Spell.BuffSelf(WoWTotem.StoneBulwark.ToSpellId(), ret => Me.HealthPercent < SingularSettings.Instance.Shaman.StoneBulwarkTotemPercent && !Exist(WoWTotem.EarthElemental)), Spell.BuffSelf(WoWTotem.Tremor.ToSpellId(), ret => Unit.GroupMembers.Any(f => f.Fleeing && f.Distance < Totems.GetTotemRange(WoWTotem.Tremor) && !Exist(WoWTotem.StoneBulwark, 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.Cast("Mana Tide Totem", ret => ((bool)ret) && StyxWoW.Me.ManaPercent < 80 && !Exist(WoWTotem.HealingTide)), /* 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("Grounding Totem", ret => ((bool)ret) && Unit.NearbyUnfriendlyUnits.Any(u => u.Distance < 40 && u.IsTargetingMeOrPet && u.IsCasting) && !Exist(WoWTotemType.Air)), Spell.Cast("Capacitor Totem", ret => ((bool)ret) && Unit.NearbyUnfriendlyUnits.Any(u => u.Distance < GetTotemRange(WoWTotem.Capacitor)) && !Exist(WoWTotemType.Air)), Spell.Cast("Stormlash Totem", ret => ((bool)ret) && Me.HasAnyAura(Common.BloodlustName, "Timewarp", "Ancient Hysteria") && !Exist(WoWTotemType.Air)) )); }
public static Composite CreateRestoShamanCombatBehavior() { return (new PrioritySelector( new Decorator( ret => Unit.NearbyFriendlyPlayers.Count(u => u.IsInMyPartyOrRaid) == 0, new PrioritySelector( Safers.EnsureTarget(), Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.BuffSelf("Fire Elemental Totem", ret => (StyxWoW.Me.CurrentTarget.Elite || Unit.NearbyUnfriendlyUnits.Count(u => u.IsTargetingMeOrPet) >= 3) && !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("Earth Shock"), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )) )); }
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 => StyxWoW.Me.Combat && StyxWoW.Me.GotTarget && Unit.NearbyFriendlyPlayers.Count(u => u.IsInMyPartyOrRaid) == 0, new PrioritySelector( Movement.CreateMoveToLosBehavior(), Movement.CreateFaceTargetBehavior(), Common.CreateInterruptSpellCast(ret => StyxWoW.Me.CurrentTarget), Spell.BuffSelf("Fire Elemental Totem", ret => (StyxWoW.Me.CurrentTarget.Elite || Unit.NearbyUnfriendlyUnits.Count(u => u.IsTargetingMeOrPet) >= 3) && !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("Earth Shock"), Spell.Cast("Lightning Bolt"), Movement.CreateMoveToTargetBehavior(true, 35f) )), new Decorator( ret => moveInRange, Movement.CreateMoveToTargetBehavior(true, 38f, ret => (WoWUnit)ret)) )))); }