/// <summary> /// Creates a move behind target behavior. If it cannot fully navigate will move to target location /// </summary> /// <remarks> /// Created 2/12/2011. /// </remarks> /// <param name="requirements">Aditional requirments.</param> /// <returns>.</returns> public static Composite CreateMoveBehindTargetBehavior(SimpleBooleanDelegate requirements) { return(new Decorator( ret => { if (StyxWoW.Me.CurrentMap.IsBattleground || !requirements(ret) || Spell.IsCastingOrChannelling() || Group.MeIsTank) { return false; } var currentTarget = StyxWoW.Me.CurrentTarget; if (currentTarget == null || currentTarget.MeIsSafelyBehind || !currentTarget.IsAlive || BossList.AvoidRearBosses.Contains(currentTarget.Entry)) { return false; } return currentTarget.Stunned || currentTarget.CurrentTarget != StyxWoW.Me; }, new PrioritySelector( ctx => CalculatePointBehindTarget(), new Decorator( req => Navigator.CanNavigateFully(StyxWoW.Me.Location, (WoWPoint)req, 4), new Sequence( new Action(ret => Logging.WriteDiagnostic("MoveBehind: behind {0} @ {1:F1} yds", StyxWoW.Me.CurrentTarget.SafeName(), StyxWoW.Me.CurrentTarget.Distance)), //Logger.WriteDebug(Color.White, "MoveBehind: behind {0} @ {1:F1} yds", StyxWoW.Me.CurrentTarget.SafeName(), StyxWoW.Me.CurrentTarget.Distance)), new Action(behindPoint => Navigator.MoveTo((WoWPoint)behindPoint)), new Action(behindPoint => StopMoving.AtLocation((WoWPoint)behindPoint)) ) ) ) )); }
/// <summary> /// private function to buff individual units. makes assumptions /// that certain states have been checked previously. only the /// group interface to PartyBuffs is exposed since it handles the /// case of LocalPlayer not in a group as well /// </summary> /// <param name="name">spell name</param> /// <param name="onUnit">unit selection delegate</param> /// <param name="requirements">requirements delegate that must be true to cast buff</param> /// <param name="myMutexBuffs">list of buffs your mechanics make mutually exclusive for you to cast. For example, BuffGroup("Blessing of Kings", ret => true, "Blessing of Might") </param> /// <returns></returns> private static Composite BuffUnit(string name, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, params string[] myMutexBuffs) { return (new Decorator( ret => onUnit(ret) != null && (PartyBuffType.None != (onUnit(ret).GetMissingPartyBuffs() & GetPartyBuffForSpell(name))) && (myMutexBuffs == null || myMutexBuffs.Count() == 0 || !onUnit(ret).GetAllAuras().Any(a => a.CreatorGuid == StyxWoW.Me.Guid && myMutexBuffs.Contains(a.Name))), new Sequence( Spell.Buff(name, onUnit, requirements), new Wait(1, until => StyxWoW.Me.HasPartyBuff(name), new ActionAlwaysSucceed()), new Action(ret => { System.Diagnostics.Debug.Assert(PartyBuffType.None != GetPartyBuffForSpell(name)); if (PartyBuffType.None != GetPartyBuffForSpell(name)) { ResetReadyToPartyBuffTimer(); } else { Logging.WriteDiagnostic("Programmer Error: should use Spell.Buff(\"{0}\") instead", name); } }) ) )); }
private Composite CastLikeMonk(string spell, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, bool face = false) { return(new Decorator( ret => requirements != null && onUnit != null && requirements(ret) && onUnit(ret) != null && spell != null && CanCastLikeMonk(spell, onUnit(ret)), new Sequence( new Styx.TreeSharp.Action(ctx => { Logging.Write(LogLevel.Normal, MONK_COLOR, "{0} on {1} at {2:F1} yds at {3:F1}%", spell, onUnit(ctx).Name, onUnit(ctx).Distance, onUnit(ctx).HealthPercent); if (face) { onUnit(ctx).Face(); } SpellManager.Cast(spell, onUnit(ctx)); } ), new WaitContinue(TimeSpan.FromMilliseconds((int)StyxWoW.WoWClient.Latency << 1), ctx => !(SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null), new ActionAlwaysSucceed() ), new WaitContinue(TimeSpan.FromMilliseconds((int)StyxWoW.WoWClient.Latency << 1), ctx => SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null, new ActionAlwaysSucceed() ) ) )); }
public static Composite CastElementalBlast(UnitSelectionDelegate onUnit = null, SimpleBooleanDelegate requirements = null, SimpleBooleanDelegate cancel = null) { const string ELEMENTAL_BLAST = "Elemental Blast"; UnitSelectionDelegate ondel = onUnit ?? (o => Me.CurrentTarget); SimpleBooleanDelegate reqdel = requirements ?? (r => true); SimpleBooleanDelegate candel = cancel ?? (c => false); // we do a doublecast check with Me as the target // .. since the buff appears on us -- a different model requiring custom handling below return(new Decorator( req => { if (Spell.DoubleCastContains(Me, ELEMENTAL_BLAST)) { return false; } if (!Me.HasAuraExpired(ELEMENTAL_BLAST, 0, myAura: true)) { return false; } return true; }, new Sequence( Spell.Cast(ELEMENTAL_BLAST, ondel, reqdel, candel), new Action(r => Spell.UpdateDoubleCast(ELEMENTAL_BLAST, Me, 750)) ) )); }
/// <summary> /// Cast "Freeze" pet ability on a target. Uses a local store for location to /// avoid target position changing during cast preparation and being out of /// range after range check /// </summary> /// <param name="onUnit">target to cast on</param> /// <returns></returns> public static Composite CastFreeze( UnitSelectionDelegate onUnit, SimpleBooleanDelegate require = null) { if (onUnit == null) return new ActionAlwaysFail(); if (require == null) require = req => true; return new Sequence( ctx => onUnit(ctx), new Decorator( req => req != null && (req as WoWUnit).SpellDistance() < 40 && require(req), new Action( r => { _locFreeze = (r as WoWUnit).Location; if (StyxWoW.Me.Location.Distance(_locFreeze) > 45) _locFreeze = WoWMathHelper.CalculatePointFrom(StyxWoW.Me.Location, _locFreeze, 7f + (r as WoWUnit).CombatReach); if (StyxWoW.Me.Location.Distance(_locFreeze) > 45) return RunStatus.Failure; return RunStatus.Success; }) ), new Throttle( TimeSpan.FromMilliseconds(250), Pet.CastPetActionOnLocation( "Freeze", on => _locFreeze, ret => !Me.CurrentTarget.TreatAsFrozen() ) ) ); }
/// <summary> /// Creates a behavior to cast a buff by name, with special requirements, on a specific unit. Returns /// RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spellId">The ID of the buff</param> /// <param name = "onUnit">The on unit</param> /// <param name = "requirements">The requirements.</param> /// <returns></returns> public static Composite Buff(int spellId, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return (new Decorator( ret => onUnit(ret) != null && !onUnit(ret).Auras.Values.Any(a => a.SpellId == spellId), Cast(spellId, onUnit, requirements))); }
/// <summary> /// Creates a behavior to start shooting current target with the wand if extra conditions are met. /// </summary> /// <param name="extra"> Extra conditions to check to start shooting. </param> /// <returns></returns> public static Composite CreateUseWand(SimpleBooleanDelegate extra) { return new PrioritySelector( new Decorator( ret => Item.HasWand && !StyxWoW.Me.IsWanding() && extra(ret), new Action(ret => SpellManager.Cast("Shoot"))) ); }
private static Composite CastSoulburn(SimpleBooleanDelegate requirements) { return(new Throttle(2, new Sequence( Spell.Cast("Soulburn", on => Me, ret => Me.CurrentSoulShards > 0 && requirements(ret) && (Me.CurrentTarget.Elite || Me.CurrentTarget.IsBoss()) && !Me.HasAura("Soulburn")), new Wait(TimeSpan.FromMilliseconds(500), ret => Me.HasAura("Soulburn"), new Action(ret => RunStatus.Success)) ))); }
/// <summary> /// Creates a behavior to start shooting current target with the wand if extra conditions are met. /// </summary> /// <param name="extra"> Extra conditions to check to start shooting. </param> /// <returns></returns> public static Composite CreateUseWand(SimpleBooleanDelegate extra) { return(new PrioritySelector( new Decorator( ret => Item.HasWand && !StyxWoW.Me.IsWanding() && extra(ret), new Action(ret => SpellManager.Cast("Shoot"))) )); }
/// <summary> /// Creates a behavior to cast a heal spell by name, with special requirements, on a specific unit. Heal behaviors will make sure /// we don't double cast. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name.</param> /// <param name="checkMovement"></param> /// <param name = "onUnit">The on unit.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Heal(string name, SimpleBooleanDelegate checkMovement, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return (new Sequence( Cast(name, checkMovement, onUnit, requirements), // Little bit wait here to catch casting new WaitContinue( 1, ret => { WoWSpell spell; if (SpellManager.Spells.TryGetValue(name, out spell)) { if (spell.CastTime == 0) { return true; } return StyxWoW.Me.IsCasting; } return true; }, new ActionAlwaysSucceed()), new WaitContinue( 10, ret => { // Let channeled heals been cast till end. if (StyxWoW.Me.ChanneledCastingSpellId != 0) { return false; } // Interrupted or finished casting. Continue if (!StyxWoW.Me.IsCasting) { return true; } // 500ms left till cast ends. Shall continue for next spell //if (StyxWoW.Me.CurrentCastTimeLeft.TotalMilliseconds < 500) //{ // return true; //} // If requirements don't meet anymore, stop casting and let it continue if (!requirements(ret)) { SpellManager.StopCasting(); return true; } return false; }, new ActionAlwaysSucceed()))); }
public static Composite UseHealthStoneBehavior(SimpleBooleanDelegate requirements) { return(new PrioritySelector( ctx => StyxWoW.Me.BagItems.FirstOrDefault(i => i.Entry == 5512), new Decorator( ret => ret != null && StyxWoW.Me.HealthPercent < 100 && ((WoWItem)ret).Cooldown == 0 && requirements(ret), new Sequence( new Action(ret => Logger.Write("Using {0}", ((WoWItem)ret).Name)), new Action(ret => ((WoWItem)ret).Use()))) )); }
public static Composite CreateUseManaGemBehavior(SimpleBooleanDelegate requirements) { return(new PrioritySelector( ctx => StyxWoW.Me.BagItems.FirstOrDefault(i => i.Entry == 36799), new Decorator( ret => ret != null && StyxWoW.Me.ManaPercent < 100 && ((WoWItem)ret).Cooldown == 0 && requirements(ret), new Sequence( new Action(ret => Logger.Write("Using mana gem")), new Action(ret => ((WoWItem)ret).Use()))) )); }
private Composite Cast(string spell, SimpleBooleanDelegate requirements, UnitSelectionDelegate unit) { return(new Decorator(ret => requirements != null && requirements(ret) && SpellManager.HasSpell(spell) && SpellManager.CanCast(spell, unit(ret), true, true), new Styx.TreeSharp.Action(ctx => { SpellManager.Cast(spell, unit(ctx)); Logging.Write(LogLevel.Normal, MONK_COLOR, "Casting Spell [{0}].", spell); return RunStatus.Success; }) )); }
public static Composite PetBuffGroup(string name, SimpleBooleanDelegate requirements, params string[] myMutexBuffs) { return(new Decorator( ret => IsItTimeToBuff() && PetManager.CanCastPetAction("Qiraji Fortitude") && (!StyxWoW.Me.Mounted || !PVP.IsPrepPhase), new PrioritySelector( ctx => Unit.GroupMembers.FirstOrDefault(m => m.IsAlive && m.DistanceSqr < 30 * 30 && (PartyBuffType.None != (m.GetMissingPartyBuffs() & GetPartyBuffForSpell(name)))), PetManager.Buff(name, on => (WoWUnit)on, requirements, myMutexBuffs) ) )); }
/// <summary> /// checks group members in range if they have a buff providing the benefits /// that this spell does, and if not casts the buff upon them. understands /// similar buffs such as Blessing of Kings being same as Mark of the Wild. /// if not in a group, will treat Me as a group of one. /// Will not buff if Mounted unless during prep phase of a battleground /// </summary> /// <param name="name">spell name of buff</param> /// <param name="requirements">requirements delegate that must be true for cast to occur</param> /// <param name="myMutexBuffs">list of your buffs which are mutually exclusive to 'name'. For example, BuffGroup("Blessing of Kings", ret => true, "Blessing of Might") </param> /// <returns></returns> public static Composite BuffGroup(string name, SimpleBooleanDelegate requirements, params string[] myMutexBuffs) { return (new Decorator(ret => IsItTimeToBuff() && SpellManager.HasSpell(name) && (!StyxWoW.Me.Mounted || (Battlegrounds.IsInsideBattleground && DateTime.Now < Battlegrounds.BattlefieldStartTime)), new PrioritySelector( ctx => Unit.GroupMembers.FirstOrDefault(m => m.IsAlive && m.DistanceSqr < 30 * 30 && (PartyBuffType.None != (m.GetMissingPartyBuffs() & GetPartyBuffForSpell(name)))), BuffUnit(name, ctx => (WoWUnit)ctx, requirements, myMutexBuffs) ) )); }
/// <summary> /// Creates a behavior to cast a spell by ID, with special requirements, on a specific unit. /// Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spellId">Identifier for the spell.</param> /// <param name = "onUnit">The on unit.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Cast(int spellId, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return(new Decorator( ret => requirements != null && requirements(ret) && onUnit != null && onUnit(ret) != null && SpellManager.CanCast(spellId, onUnit(ret), true), new Action( ret => { Logger.Write("Casting " + spellId + " on " + onUnit(ret).SafeName()); SpellManager.Cast(spellId); }) )); }
private static Composite CastRegrowth(UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, SimpleBooleanDelegate cancel) { SimpleBooleanDelegate require = r => (glyphRegrowth || !Spell.DoubleCastContains((WoWUnit)r, "Regrowth")) && requirements(r); return(new Sequence( ctx => onUnit(ctx), Spell.Cast("Regrowth", on => (WoWUnit)on, req => require(req), cancel), new DecoratorContinue( req => !glyphRegrowth, new Action(ret => Spell.UpdateDoubleCast("Regrowth", (WoWUnit)ret)) ) )); }
public static Composite Buff(string spell, UnitSelectionDelegate onUnit, SimpleBooleanDelegate require, params string[] buffNames) { return(new Decorator( ret => { if (onUnit == null || require == null) { return false; } _buffUnit = onUnit(ret); if (_buffUnit == null) { return false; } if (spell == null) { return false; } if (Spell.DoubleCastContains(_buffUnit, spell)) { return false; } if (!buffNames.Any()) { return !_buffUnit.HasAura(spell); } bool buffFound; try { buffFound = buffNames.Any(b => _buffUnit.HasAura(b)); } catch { // mark as found buff, so we return false buffFound = true; } return !buffFound; }, new Sequence( // new Action(ctx => _lastBuffCast = name), new Action(r => PetManager.CastPetAction(spell)), new Action(ret => Spell.UpdateDoubleCast(spell, _buffUnit)) ) )); }
/// <summary> /// Creates a move behind target behavior. If it cannot fully navigate will move to target location /// </summary> /// <remarks> /// Created 2/12/2011. /// </remarks> /// <param name="requirements">Aditional requirments.</param> /// <returns>.</returns> public static Composite CreateMoveBehindTargetBehavior(SimpleBooleanDelegate requirements) { return (new Decorator( ret => !SingularSettings.Instance.DisableAllMovement && SingularRoutine.CurrentWoWContext != WoWContext.Battlegrounds && requirements(ret) && !StyxWoW.Me.IsCasting && !Group.MeIsTank && !StyxWoW.Me.CurrentTarget.MeIsBehind && StyxWoW.Me.CurrentTarget.IsAlive && (StyxWoW.Me.CurrentTarget.CurrentTarget == null || StyxWoW.Me.CurrentTarget.CurrentTarget != StyxWoW.Me || StyxWoW.Me.CurrentTarget.Stunned), new Action(ret => Navigator.MoveTo(CalculatePointBehindTarget())))); }
static Composite CastMindFlay(UnitSelectionDelegate onUnit = null, SimpleBooleanDelegate requirements = null) { UnitSelectionDelegate o = onUnit ?? (on => Me.CurrentTarget); SimpleBooleanDelegate r; if (requirements == null) { r = req => Me.ManaPercent > PriestSettings.MindFlayManaPct; } else { r = req => Me.ManaPercent > PriestSettings.MindFlayManaPct && requirements(req); } return(Spell.Cast("Mind Flay", mov => true, o, r, cancel => { if (Spell.IsGlobalCooldown()) { return false; } if (!Spell.IsSpellOnCooldown("Mind Blast") && Spell.GetSpellCastTime("Mind Blast") == TimeSpan.Zero) { Logger.Write(LogColor.Cancel, "/cancel Mind Flay for instant Mind Blast proc"); } else if (Me.HasAura(SURGE_OF_DARKNESS)) { Logger.Write(LogColor.Cancel, "/cancel Mind Flay for instant Mind Spike proc"); } else if (SpellManager.HasSpell("Shadow Word: Insanity") && Unit.NearbyUnfriendlyUnits.Any(u => u.GetAuraTimeLeft("Shadow Word: Pain", true).TotalMilliseconds.Between(1000, 5000) && u.InLineOfSpellSight)) { Logger.Write(LogColor.Cancel, "/cancel Mind Flay for Shadow Word: Insanity proc"); } else if (!Spell.IsSpellOnCooldown("Shadow Word: Death") && Unit.NearbyUnfriendlyUnits.Any(u => u.HealthPercent < 20 && u.InLineOfSpellSight)) { Logger.Write(LogColor.Cancel, "/cancel Mind Flay for Shadow Word: Death proc"); } else { return false; } return true; })); }
/// <summary> /// retrieve best estimation of number of hops a chained spell will make for a given target /// </summary> /// <param name="target">spell target all hops originate from</param> /// <param name="otherUnits">units to consider as possible targets</param> /// <param name="chainRange">chain hop distance</param> /// <param name="avoid">delegate to determine if an unwanted target would be hit</param> /// <returns>0 avoid target would be hit, otherwise count of targets hit (including initial target)</returns> public static int GetChainedClusterCount(WoWUnit target, IEnumerable<WoWUnit> otherUnits, float chainRange, SimpleBooleanDelegate avoid = null) { if (avoid == null) return GetChainedCluster(target, otherUnits, chainRange).Count(); int cnt = 0; foreach (var u in GetChainedCluster(target, otherUnits, chainRange)) { cnt++; if (avoid(u)) { cnt = 0; break; } } return cnt; }
private static void Set(StopType type, WoWUnit unit, WoWPoint pt, double range, SimpleBooleanDelegate stop, SimpleBooleanDelegate and) { //if (MovementManager.IsMovementDisabled) // return; Type = type; Unit = unit; Point = pt; Range = range; if (and == null) { and = ret => true; } StopNow = ret => stop(ret) && and(ret); }
/// <summary> /// cast Ice Lance without requiring FoF, but if FoF active wait until buff stack count updated /// to ensure we don't break other Ice Lance logic that depends on FoF being accurate /// </summary> /// <param name="on"></param> /// <returns></returns> private static Sequence CreateIceLanceBehavior(UnitSelectionDelegate on = null, SimpleBooleanDelegate requirements = null) { UnitSelectionDelegate ondel = on ?? (o => Me.CurrentTarget); SimpleBooleanDelegate reqdel = requirements ?? (req => true); return(new Sequence( ctx => new ILInfo(ondel(ctx), Me.GetAuraStacks(FINGERS_OF_FROST), ctx), new Decorator( req => ILInfo.Ref(req).Unit != null && (ILInfo.Ref(req).StacksOfFOF > 0 || ILInfo.Ref(req).Unit.IsTrivial()) && Spell.CanCastHack("Ice Lance", ILInfo.Ref(req).Unit) && !ILInfo.Ref(req).Unit.IsImmune(WoWSpellSchool.Frost), new Sequence( Spell.Cast("Ice Lance", o => ((ILInfo)o).Unit, r => reqdel(ILInfo.Ref(r).SaveContext)), Helpers.Common.CreateWaitForLagDuration( until => ILInfo.Ref(until).StacksOfFOF != Me.GetAuraStacks(FINGERS_OF_FROST) || Me.GetAuraStacks(FINGERS_OF_FROST) == 0 ) ) ) )); }
/// <summary> /// cast Ice Lance only if FoF active. waits after cast until FoF stack count changes /// to ensure we don't double cast Ice Lance (since we queue spells) /// </summary> /// <param name="on"></param> /// <returns></returns> private static Sequence CreateIceLanceFoFBehavior(UnitSelectionDelegate onUnit = null, SimpleBooleanDelegate requirements = null) { UnitSelectionDelegate ondel = onUnit ?? (o => Me.CurrentTarget); SimpleBooleanDelegate reqdel = requirements ?? (req => true); return(new Sequence( ctx => new ILInfo(ondel(ctx), Me.GetAuraStacks(FINGERS_OF_FROST), ctx), new Decorator( // req => Spell.CanCastHack("Ice Lance", (req as ILInfo).Unit) && ((req as ILInfo).Unit != null && ((req as ILInfo).StacksOfFOF > 0 || (req as ILInfo).Unit.IsTrivial())), req => ILInfo.Ref(req).Unit != null && ILInfo.Ref(req).StacksOfFOF > 0 && Spell.CanCastHack("Ice Lance", ILInfo.Ref(req).Unit) && !ILInfo.Ref(req).Unit.IsImmune(WoWSpellSchool.Frost), new Sequence( new Action(r => Logger.Write(LogColor.Hilite, "^Fingers of Frost[{0}]: casting buffed Ice Lance", ILInfo.Ref(r).StacksOfFOF)), Spell.Cast("Ice Lance", mov => false, o => ILInfo.Ref(o).Unit, r => reqdel(ILInfo.Ref(r).SaveContext)), // ret => Unit.NearbyUnfriendlyUnits.Count(t => t.Distance <= 10) < 4), Helpers.Common.CreateWaitForLagDuration( until => ILInfo.Ref(until).StacksOfFOF != Me.GetAuraStacks(FINGERS_OF_FROST) ) ) ) )); }
/// <summary> /// Cast "Freeze" pet ability on a target. Uses a local store for location to /// avoid target position changing during cast preparation and being out of /// range after range check /// </summary> /// <param name="onUnit">target to cast on</param> /// <returns></returns> public static Composite CastFreeze(UnitSelectionDelegate onUnit, SimpleBooleanDelegate require = null) { if (onUnit == null) { return(new ActionAlwaysFail()); } if (require == null) { require = req => true; } return(new Sequence( ctx => onUnit(ctx), new Decorator( req => req != null && (req as WoWUnit).SpellDistance() < 40 && require(req), new Action(r => { _locFreeze = (r as WoWUnit).Location; if (StyxWoW.Me.Location.Distance(_locFreeze) > 45) { _locFreeze = WoWMathHelper.CalculatePointFrom(StyxWoW.Me.Location, _locFreeze, 7f + (r as WoWUnit).CombatReach); } if (StyxWoW.Me.Location.Distance(_locFreeze) > 45) { return RunStatus.Failure; } return RunStatus.Success; }) ), new Throttle(TimeSpan.FromMilliseconds(250), Pet.CastPetActionOnLocation( "Freeze", on => _locFreeze, ret => !Me.CurrentTarget.TreatAsFrozen() ) ) )); }
private Composite SelfCast(string spell, SimpleBooleanDelegate requirements) { return Cast(spell, requirements, unit => StyxWoW.Me); }
/// <summary> /// Creates a behavior to cast a spell by name, on the ground at the specified location. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spell">The spell.</param> /// <param name = "onLocation">The on location.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite CastOnGround(string spell, LocationRetriever onLocation, SimpleBooleanDelegate requirements) { return(new Decorator( ret => requirements(ret) && onLocation != null && SpellManager.CanCast(spell) && (StyxWoW.Me.Location.Distance(onLocation(ret)) <= SpellManager.Spells[spell].MaxRange || SpellManager.Spells[spell].MaxRange == 0), new Sequence( new Action(ret => Logger.Write("Casting {0} at location {1}", spell, onLocation(ret))), new Action(ret => SpellManager.Cast(spell)), new WaitContinue( 1, ret => StyxWoW.Me.CurrentPendingCursorSpell != null && StyxWoW.Me.CurrentPendingCursorSpell.Name == spell, new ActionAlwaysSucceed()), new Action(ret => LegacySpellManager.ClickRemoteLocation(onLocation(ret)))) )); }
/// <summary> /// Creates a behavior to cast a buff by name, with special requirements, on a specific unit. Returns /// RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spellId">The ID of the buff</param> /// <param name = "onUnit">The on unit</param> /// <param name = "requirements">The requirements.</param> /// <returns></returns> public static Composite Buff(int spellId, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return new Decorator(ret => onUnit(ret) != null && onUnit(ret).Auras.Values.All(a => a.SpellId != spellId), Cast(spellId, onUnit, requirements)); }
public static Composite Buff(string name, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, params string[] buffNames) { return Buff(name, false, onUnit, requirements, buffNames); }
public static Composite Buff(string name, bool myBuff, SimpleBooleanDelegate requirements, params string[] buffNames) { return Buff(name, myBuff, ret => StyxWoW.Me.CurrentTarget, requirements, buffNames); }
public static Composite CreateCastSoulburn(SimpleBooleanDelegate requirements) { return new Sequence( Spell.BuffSelf("Soulburn", ret => Me.CurrentSoulShards > 0 && requirements(ret)), new Wait(TimeSpan.FromMilliseconds(500), ret => Me.HasAura("Soulburn"), new Action(ret => { return RunStatus.Success; })) ); }
/// <summary> /// checks group members in range if they have a buff providing the benefits /// that this spell does, and if not casts the buff upon them. understands /// similar buffs such as Blessing of Kings being same as Mark of the Wild. /// if not in a group, will treat Me as a group of one. /// Will not buff if Mounted unless during prep phase of a battleground /// </summary> /// <param name="name">spell name of buff</param> /// <param name="requirements">requirements delegate that must be true for cast to occur</param> /// <param name="myMutexBuffs">list of your buffs which are mutually exclusive to 'name'. For example, BuffGroup("Blessing of Kings", ret => true, "Blessing of Might") </param> /// <returns></returns> public static Composite BuffGroup(string name, SimpleBooleanDelegate requirements, params string[] myMutexBuffs) { return new Decorator(ret => IsItTimeToBuff() && SpellManager.HasSpell(name) && (!StyxWoW.Me.Mounted || !PVP.IsPrepPhase), new PrioritySelector( ctx => Unit.GroupMembers.FirstOrDefault(m => m.IsAlive && m.DistanceSqr < 30 * 30 && (PartyBuffType.None != (m.GetMissingPartyBuffs() & GetPartyBuffForSpell(name)))), BuffUnit(name, ctx => (WoWUnit)ctx, requirements, myMutexBuffs) ) ); }
public static Composite Heal(string name, SimpleBooleanDelegate checkMovement, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, bool allowLagTollerance = false) { return Heal(name, checkMovement, onUnit, requirements, ret => onUnit(ret).HealthPercent > SingularSettings.Instance.IgnoreHealTargetsAboveHealth, false); }
/// <summary> /// Creates a behavior to cast a heal spell by name, with special requirements. Heal behaviors will make sure /// we don't double cast. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Heal(string name, SimpleBooleanDelegate requirements) { return Heal(name, ret => true, ret => StyxWoW.Me, requirements); }
/// <summary> /// Creates a behavior to cast a spell by name, on the ground at the specified location. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spell">The spell.</param> /// <param name = "onLocation">The on location.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite CastOnGround(string spell, LocationRetriever onLocation, SimpleBooleanDelegate requirements) { return CastOnGround(spell, onLocation, requirements, true); }
/// <summary> /// Creates a behavior to cast a spell by ID, with special requirements. Returns /// RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spellId">Identifier for the spell.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Cast(int spellId, SimpleBooleanDelegate requirements) { return Cast(spellId, ret => StyxWoW.Me.CurrentTarget, requirements); }
/// <summary> /// Creates a behavior to cast a buff by ID on yourself with special requirements. Returns RunStatus.Success if /// successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/6/2011. /// </remarks> /// <param name = "spellId">The buff ID.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite BuffSelf(int spellId, SimpleBooleanDelegate requirements) { return Buff(spellId, ret => StyxWoW.Me, requirements); }
private static Composite CreateShieldCharge(UnitSelectionDelegate onUnit = null, SimpleBooleanDelegate requirements = null) { if (onUnit == null) onUnit = on => Me.CurrentTarget; if (requirements == null) requirements = req => true; return new Sequence( new Decorator( req => Spell.DoubleCastContains(Me, "Shield Charge") || !HasShieldInOffHand, new ActionAlwaysFail() ), Spell.Cast("Shield Charge", onUnit, req => requirements(req), gcd: HasGcd.No), new Action(ret => Spell.UpdateDoubleCast("Shield Charge", Me)) ); }
public static Composite CreateUseManaGemBehavior(SimpleBooleanDelegate requirements) { return new Throttle( 2, new PrioritySelector( ctx => StyxWoW.Me.BagItems.FirstOrDefault(i => i.Entry == 36799 || i.Entry == 81901), new Decorator( ret => ret != null && StyxWoW.Me.ManaPercent < 100 && ((WoWItem)ret).Cooldown == 0 && requirements(ret), new Sequence( new Action(ret => Logger.Write("Using {0}", ((WoWItem)ret).Name)), new Action(ret => ((WoWItem)ret).Use()) ) ) ) ); }
public static Composite CastThrash( UnitSelectionDelegate on, SimpleBooleanDelegate required, int seconds = 2) { return Spell.Cast( "Thrash", on, req => required(req) && on(req).HasAuraExpired("Thrash",seconds, true)); // return Spell.Buff("Thrash", true, on, required, 2); // return Spell.Buff(106832, on => Me.CurrentTarget, req => Me.HasAura("Omen of Clarity") && Me.CurrentTarget.HasAuraExpired("Thrash", 3)), }
/// <summary> /// Creates a behavior to cast a buff by name, with special requirements, on current target. Returns /// RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name of the buff</param> /// <param name = "requirements">The requirements.</param> /// <returns></returns> public static Composite Buff(string name, SimpleBooleanDelegate requirements) { return Buff(name, false, ret => StyxWoW.Me.CurrentTarget, requirements, name); }
private Composite Cast(string spell, SimpleBooleanDelegate requirements) { return Cast(spell, requirements, unit => StyxWoW.Me.CurrentTarget); }
public static Composite Buff(string name, bool myBuff, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return Buff(name, myBuff, onUnit, requirements, name); }
private Composite Cast(string spell, SimpleBooleanDelegate requirements, UnitSelectionDelegate unit) { return new Decorator(ret => requirements != null && requirements(ret) && SpellManager.HasSpell(spell) && SpellManager.CanCast(spell, unit(ret), true, true), new Styx.TreeSharp.Action(ctx => { SpellManager.Cast(spell, unit(ctx)); Logging.Write(LogLevel.Normal, MONK_COLOR, "Casting Spell [{0}].", spell); return RunStatus.Success; }) ); }
//private static string _lastBuffCast = string.Empty; //private static System.Diagnostics.Stopwatch _castTimer = new System.Diagnostics.Stopwatch(); /// <summary> /// Creates a behavior to cast a buff by name, with special requirements, on a specific unit. Returns /// RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name of the buff</param> /// <param name = "myBuff">Check for self debuffs or not</param> /// <param name = "onUnit">The on unit</param> /// <param name = "requirements">The requirements.</param> /// <returns></returns> public static Composite Buff(string name, bool myBuff, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, params string[] buffNames) { //if (name == _lastBuffCast && _castTimer.IsRunning && _castTimer.ElapsedMilliseconds < 250) //{ // return new Action(ret => RunStatus.Success); //} //if (name == _lastBuffCast && StyxWoW.Me.IsCasting) //{ // _castTimer.Reset(); // _castTimer.Start(); // return new Action(ret => RunStatus.Success); //} return new Decorator( ret => onUnit(ret) != null && !DoubleCastPreventionDict.ContainsKey(name) && buffNames.All(b => myBuff ? !onUnit(ret).HasMyAura(b) : !onUnit(ret).HasAura(b)), new Sequence( // new Action(ctx => _lastBuffCast = name), Cast(name, onUnit, requirements), new DecoratorContinue(ret => SpellManager.Spells[name].CastTime > 0, new Sequence(new WaitContinue(1, ret => StyxWoW.Me.IsCasting, new Action(ret => UpdateDoubleCastDict(name))))))); }
private Composite CastLikeMonk(string spell, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, bool face = false) { return new Decorator( ret => requirements != null && onUnit != null && requirements(ret) && onUnit(ret) != null && spell != null && CanCastLikeMonk(spell, onUnit(ret)), new Sequence( new Styx.TreeSharp.Action(ctx => { Logging.Write(LogLevel.Normal, MONK_COLOR, "{0} on {1} at {2:F1} yds at {3:F1}%", spell, onUnit(ctx).Name, onUnit(ctx).Distance, onUnit(ctx).HealthPercent); if (face) onUnit(ctx).Face(); SpellManager.Cast(spell, onUnit(ctx)); } ), new WaitContinue(TimeSpan.FromMilliseconds((int)StyxWoW.WoWClient.Latency << 1), ctx => !(SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null), new ActionAlwaysSucceed() ), new WaitContinue(TimeSpan.FromMilliseconds((int)StyxWoW.WoWClient.Latency << 1), ctx => SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null, new ActionAlwaysSucceed() ) ) ); }
/// <summary> /// Creates a behavior to cast a buff by name on yourself with special requirements. Returns RunStatus.Success if /// successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/6/2011. /// </remarks> /// <param name = "name">The buff name.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite BuffSelf(string name, SimpleBooleanDelegate requirements) { return Buff(name, ret => StyxWoW.Me, requirements); }
public static Composite StopAndCast(string name, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return(new Decorator( ret => { return requirements(ret) && onUnit(ret) != null && SpellManager.CanCast(name, onUnit(ret), true, false); }, new Action( ret => { WoWSpell spell = GetSpellByName(name); if (spell.CastTime > 0 && StyxWoW.Me.IsMoving) { WoWMovement.MoveStop(); } Logger.Write("Casting " + name + " on " + onUnit(ret).SafeName()); SpellManager.Cast(name, onUnit(ret)); }) )); }
/// <summary> /// Creates a behavior to cast a spell by name, with special requirements. Returns RunStatus.Success if successful, /// RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Cast(string name, SimpleBooleanDelegate requirements) { return Cast(name, ret => true, ret => StyxWoW.Me.CurrentTarget, requirements); }
public static void AtLocation(WoWPoint pt, SimpleBooleanDelegate and = null) { Set(StopType.Location, null, pt, 0, at => StyxWoW.Me.Location.Distance(pt) <= 1, and); }
/// <summary> /// Creates a behavior to cast a spell by ID, with special requirements, on a specific unit. /// Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spellId">Identifier for the spell.</param> /// <param name = "onUnit">The on unit.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Cast(int spellId, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return new Decorator(ret => requirements != null && requirements(ret) && onUnit != null && onUnit(ret) != null && SpellManager.CanCast(spellId, onUnit(ret),true), new Action(ret => { Logger.Write(string.Format("Casting {0} on {1}", spellId, onUnit(ret).SafeName())); SpellManager.Cast(spellId); })); }
public static void InRangeOfLocation(WoWPoint pt, double range, SimpleBooleanDelegate and = null) { Set(StopType.RangeOfLocation, null, pt, range, at => StyxWoW.Me.Location.Distance(pt) <= range, and); }
/// <summary> /// Creates a behavior to cast a spell by name, on the ground at the specified location. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "spell">The spell.</param> /// <param name = "onLocation">The on location.</param> /// <param name = "requirements">The requirements.</param> /// <param name="waitForSpell">Waits for spell to become active on cursor if true. </param> /// <returns>.</returns> public static Composite CastOnGround(string spell, LocationRetriever onLocation, SimpleBooleanDelegate requirements, bool waitForSpell) { return new Decorator( ret => requirements(ret) && onLocation != null && SpellManager.CanCast(spell) && (StyxWoW.Me.Location.Distance(onLocation(ret)) <= SpellManager.Spells[spell].MaxRange || SpellManager.Spells[spell].MaxRange == 0) && GameWorld.IsInLineOfSpellSight(StyxWoW.Me.Location, onLocation(ret)), new Sequence( new Action(ret => Logger.Write("Casting {0} at location {1}", spell, onLocation(ret))), new Action(ret => SpellManager.Cast(spell)), new DecoratorContinue(ctx => waitForSpell, new WaitContinue(1, ret => StyxWoW.Me.CurrentPendingCursorSpell != null && StyxWoW.Me.CurrentPendingCursorSpell.Name == spell, new ActionAlwaysSucceed())), new Action(ret => SpellManager.ClickRemoteLocation(onLocation(ret))))); }
public static void InRangeOfUnit(WoWUnit unit, double range, SimpleBooleanDelegate and = null) { Set(StopType.RangeOfUnit, unit, WoWPoint.Empty, range, at => Unit == null || !Unit.IsValid || Unit.Distance <= range, and); }
/// <summary> /// Creates a behavior to cast a heal spell by name, on a specific unit. Heal behaviors will make sure /// we don't double cast. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name.</param> /// <param name = "onUnit">The on unit.</param> /// <param name = "requirements">The requirements.</param> /// <returns>.</returns> public static Composite Heal(string name, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements) { return Heal(name, ret => true, onUnit, requirements); }
public static void InMeleeRangeOfUnit(WoWUnit unit, SimpleBooleanDelegate and = null) { Set(StopType.RangeOfUnit, unit, WoWPoint.Empty, 0, at => Unit == null || !Unit.IsValid || Movement.InMoveToMeleeStopRange(Unit), and); }
/// <summary> /// Creates a behavior to cast a heal spell by name, with special requirements, on a specific unit. Heal behaviors will make sure /// we don't double cast. Returns RunStatus.Success if successful, RunStatus.Failure otherwise. /// </summary> /// <remarks> /// Created 5/2/2011. /// </remarks> /// <param name = "name">The name.</param> /// <param name="checkMovement"></param> /// <param name = "onUnit">The on unit.</param> /// <param name = "requirements">The requirements.</param> /// <param name="cancel">The cancel cast in progress delegate</param> /// <param name="allowLagTollerance">allow next spell to queue before this one completes</param> /// <returns>.</returns> public static Composite Heal(string name, SimpleBooleanDelegate checkMovement, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, SimpleBooleanDelegate cancel, bool allowLagTollerance = false) { return new PrioritySelector( // save context of currently in a GCD or IsCasting before our Cast ctx => (bool)(SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null), new Sequence( Cast(name, checkMovement, onUnit, requirements), // if saved context indicates action was in progress (so we queued this one) then wait briefly for its progress to finish new WaitContinue( new TimeSpan(0, 0, 0, 0, (int) StyxWoW.WoWClient.Latency * 2), ret => !((bool)ret) || !(SpellManager.GlobalCooldown || StyxWoW.Me.IsCasting || StyxWoW.Me.ChanneledSpell != null), new ActionAlwaysSucceed() ), // now for non-instant spell, wait for .IsCasting to be true new WaitContinue(1, ret => { WoWSpell spell; if (SpellManager.Spells.TryGetValue(name, out spell)) { if (spell.CastTime == 0) return true; return StyxWoW.Me.IsCasting; } return true; }, new ActionAlwaysSucceed() ), // finally, wait at this point until heal completes new WaitContinue(10, ret => { // Let channeled heals been cast till end. if (StyxWoW.Me.ChanneledSpell != null) // .ChanneledCastingSpellId != 0) { return false; } // Interrupted or finished casting. Continue (note: following test doesn't deal with latency) if (!StyxWoW.Me.IsCasting) { return true; } // when doing lag tolerance, don't wait for spell to complete before considering finished if (allowLagTollerance) { TimeSpan castTimeLeft = StyxWoW.Me.CurrentCastTimeLeft; if (castTimeLeft != TimeSpan.Zero && castTimeLeft.TotalMilliseconds < (StyxWoW.WoWClient.Latency * 2)) return true; } // 500ms left till cast ends. Shall continue for next spell //if (StyxWoW.Me.CurrentCastTimeLeft.TotalMilliseconds < 500) //{ // return true; //} // temporary hack - checking requirements won't work -- either need global value or cancelDelegate // if ( onUnit(ret).HealthPercent > SingularSettings.Instance.IgnoreHealTargetsAboveHealth) // (!requirements(ret)) if ( cancel(ret) ) { SpellManager.StopCasting(); Logger.Write(System.Drawing.Color.Orange, "/cancel {0} on {1} @ {2:F1}%", name, onUnit(ret).SafeName(), onUnit(ret).HealthPercent); return true; } return false; }, new ActionAlwaysSucceed() ) ) ); }
public static void InLosOfUnit(WoWUnit unit, SimpleBooleanDelegate and = null) { Set(StopType.LosOfUnit, unit, WoWPoint.Empty, 0, at => Unit == null || !Unit.IsValid || Movement.InLineOfSpellSight(Unit), and); }
/// <summary> /// private function to buff individual units. makes assumptions /// that certain states have been checked previously. only the /// group interface to PartyBuffs is exposed since it handles the /// case of LocalPlayer not in a group as well /// </summary> /// <param name="name">spell name</param> /// <param name="onUnit">unit selection delegate</param> /// <param name="requirements">requirements delegate that must be true to cast buff</param> /// <param name="myMutexBuffs">list of buffs your mechanics make mutually exclusive for you to cast. For example, BuffGroup("Blessing of Kings", ret => true, "Blessing of Might") </param> /// <returns></returns> private static Composite BuffUnit(string name, UnitSelectionDelegate onUnit, SimpleBooleanDelegate requirements, params string[] myMutexBuffs) { return new Decorator( ret => onUnit(ret) != null && (PartyBuffType.None != (onUnit(ret).GetMissingPartyBuffs() & GetPartyBuffForSpell(name))) && (myMutexBuffs == null || myMutexBuffs.Count() == 0 || !onUnit(ret).GetAllAuras().Any(a => a.CreatorGuid == StyxWoW.Me.Guid && myMutexBuffs.Contains(a.Name))), new Sequence( Spell.Buff( name, onUnit, requirements), new Wait( 1, until => StyxWoW.Me.HasPartyBuff(name), new ActionAlwaysSucceed()), new Action(ret => { System.Diagnostics.Debug.Assert( PartyBuffType.None != GetPartyBuffForSpell(name)); if (PartyBuffType.None != GetPartyBuffForSpell(name)) ResetReadyToPartyBuffTimer(); else Logger.WriteDebug("Programmer Error: should use Spell.Buff(\"{0}\") instead", name); }) ) ); }
public static void AsSoonAsPossible(SimpleBooleanDelegate and = null) { Set(StopType.AsSoonAsPossible, null, WoWPoint.Empty, 0, at => true, and); }