What's new
  • Visit Rebornbuddy
  • Visit Panda Profiles
  • Visit LLamamMagic
  • Visit Resources
  • Visit Downloads
  • Visit Portal

How do I stop my char from double-casting heals?

Inrego

New Member
Joined
Feb 7, 2010
Messages
2,765
Reaction score
71
I'm making a CC, but I have a problem that most of the times when it heals, it casts a heal again right after even when the hp is full.
It's like it doesn't recognize the health gained from the first heal before casting the next one.

Here's my code:
PHP:
using System.Linq;
using System.Collections.Generic;
using System.Drawing;
using Styx.Combat.CombatRoutine;
using Styx.Helpers;
using Styx.Logic.Combat;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace Retrego
{
    class Classname : CombatRoutine
    {
        public override sealed string Name { get { return "Retrego v0.1"; } }
        public override WoWClass Class { get { return WoWClass.Paladin; } }
        private static LocalPlayer Me { get { return ObjectManager.Me; } }
        private static bool verboseLogging = false;
        private WoWUnit[] Targets
        {
            get
            {
                var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(p => p.Distance <= 40 && (p.IsHostile || p.IsNeutral) && (IsTargetingFriend(p) || IsCCed(p)));
                return targetsList.ToArray();
            }
        }
        private static WoWUnit[] TargetsInRange(int range)
        {
            var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(p => p.Distance <= range && p.IsHostile && p.IsAlive);
            return targetsList.ToArray();
        }
        private WoWPlayer[] friends
        {
            get
            {
                var friendsList = new List<WoWPlayer>();
                friendsList.Add(Me);
                if (Me.IsInRaid)
                    friendsList.AddRange(Me.RaidMembers);
                else if (Me.IsInParty)
                    friendsList.AddRange(Me.PartyMembers);
                return friendsList.ToArray();
            }
        }

        private void slog(string format, params object[] args) //use for slogging
        {
            Logging.Write(Color.Crimson, "[Retrego]: " + format, args);
        }
        public override bool WantButton
        {
            get
            {

                return true;
            }
        }
        public override void OnButtonPress()
        {
            //ConfigForm.ShowDialog();
        }
        #region overrides
        public override bool NeedRest
        {
            get
            {
                if (Me.HealthPercent <= 70 && Me.HasAura("Crusader")) return true;
                if (Me.HealthPercent <= 50) return true;
                return false;
            }
        }

        public override void Rest()
        {
            if (Me.HealthPercent <= 70 && Me.HasAura("Crusader")) CastSpell("Holy Light", Me);
            if (Me.HealthPercent <= 50) CastSpell("Flash of Light");
        }
        public override void Pull()
        {
            float maxRange = WoWSpell.FromId(20271).MaxRange;
            WoWMovement.ClickToMove(Me.CurrentTarget.Location, maxRange);
            slog("Moving to {0}", Me.CurrentTarget.Name);
            slog("Pulling with Judgement!");
            CastSpell("Judgement");
        }

        public override bool NeedPreCombatBuffs
        {
            get
            {
                if (friends.Any(f => f.Distance < 50 && f.IsAlive && !f.HasAura(ChooseBlessing())))
                    return true;
                if (!Me.HasAura(ChooseAura())) 
                    return true;
                return false;
            }
        }

        public override void PreCombatBuff()
        {
            if (friends.Any(f => f.Distance < 50 && f.IsAlive && !f.HasAura(ChooseBlessing())))
                CastSpell(ChooseBlessing());
            if (!Me.HasAura(ChooseAura()))
                CastSpell(ChooseAura());
        }

        public override bool NeedPullBuffs
        {
            get
            {
                if (!Me.HasAura("Seal of Truth") && !Me.HasAura("Seal of Righteousness"))
                    return true;
                return false;
            }
        }

        public override void PullBuff()
        {
            if (!Me.HasAura("Seal of Truth")) CastSpell("Seal of Truth");
            if (!Me.HasAura("Seal of Righteousness")) CastSpell("Seal of Righteousness");
        }

        public override bool NeedCombatBuffs { get { return false; } }

        public override void CombatBuff()
        {

        }

        public override bool NeedHeal
        {
            get
            {
                return Me.HealthPercent <= 30;
            }
        }

        public override void Heal()
        {
            CastSpell("Flash of Light");
        }

        public void HandleFalling() { }

        public override void Combat()
        {
            var bestAttackTarget = BestAttackTarget();
            MoveToUnit(Me.CurrentTarget);
            if (Me.CurrentTarget.IsWithinMeleeRange)
                WoWMovement.MoveStop();
            AutoAttack();
            if(verboseLogging)
            {
                slog("Best attack target is '{0}'", bestAttackTarget.Name);
                slog("Valid mobs: {0}", Targets.Length);
                slog("Mobs within melee: {0}", TargetsInRange(10).Length);
            }
            foreach (WoWUnit mob in TargetsInRange(10))
            {
                if (mob.IsCasting && mob.CanInterruptCurrentSpellCast && mob.CurrentCastTimeLeft.Milliseconds < 700)
                {
                    mob.Target();
                    Me.Face();
                    CastSpell("Rebuke", mob);
                }
            }
            foreach (WoWUnit mob in TargetsInRange(12))
            {
                if (mob.IsCasting && (!mob.CanInterruptCurrentSpellCast || !mob.IsWithinMeleeRange || !SpellManager.CanCast("Rebuke")))
                {
                    CastSpell("Hammer of Justice", mob);
                }
            }
            if(bestAttackTarget.HealthPercent <= 20) CastSpell("Hammer of Wrath");
            if (Me.HealthPercent <= 60 && Me.HasAura("Crusader")) CastSpell("Holy Light", Me);
            if (Me.HasAura(59578)) // The Art of War
            {
                CastSpell("Exorcism", BestExorcismTarget());
            }
            if(Me.CurrentHolyPower == 3 || Me.HasAura(90174)) // Divine Purpose
            {
                if(BestHealingTarget().HealthPercent < 60)
                {
                    CastSpell("Word of Glory", BestHealingTarget());
                }
                else
                {
                    CastSpell(85256, bestAttackTarget); // Templar's Verdict
                }
                
            }
            else
            {
                if(Targets.Length >= 2 && BestCCTarget() != null)
                {
                    CastSpell(20066, BestCCTarget()); // Repentance
                }
                if (TargetsInRange(10).Length >= 4)
                {
                    CastSpell("Divine Storm");
                }
                CastSpell(35395, bestAttackTarget); // Crusader Strike
                CastSpell(20271, bestAttackTarget); // Judgement
                if (TargetsInRange(12).Length >= 4)
                {
                    CastSpell("Holy Wrath");
                }
            }
        }

        private void AutoAttack()
        {
            if (!Me.IsAutoAttacking)
            {
                Me.ToggleAttack();
            }

        }
        #endregion overrides
        
        private static void CastSpell(string spellName)
        {
            if (SpellManager.CanCast(spellName))
            {
                SpellManager.Cast(spellName);
            }
        }
        private static void CastSpell(string spellName, WoWUnit target)
        {
            if (SpellManager.CanCast(spellName, target))
            {
                SpellManager.Cast(spellName, target);
            }
        }
        private void CastSpell(int spellId)
        {
            WoWSpell spell = WoWSpell.FromId(spellId);
            float maxRange = spell.MaxRange;
            bool shouldMoveMelee = spell.IsMeleeSpell && !Me.CurrentTarget.IsWithinMeleeRange;
            bool shouldMoveRanged = !spell.IsMeleeSpell && Me.Location.Distance(Me.CurrentTarget.Location) >= maxRange;
            bool shouldMove = shouldMoveMelee || shouldMoveRanged;
            if (verboseLogging)
            {
                slog("ShouldMove: {0}", shouldMove);
            }
            if (shouldMove)
            {
                slog("Moving to {0}", Me.CurrentTarget.Name);
                WoWMovement.ClickToMove(Me.CurrentTarget.Location, maxRange - 5);
            }
            if (SpellManager.CanCast(spellId))
            {
                SpellManager.Cast(spellId);
            }
        }
        private void CastSpell(int spellId, WoWUnit target)
        {
            WoWSpell spell = WoWSpell.FromId(spellId);
            float maxRange = spell.MaxRange;
            bool shouldMoveMelee = spell.IsMeleeSpell && !target.IsWithinMeleeRange;
            bool shouldMoveRanged = !spell.IsMeleeSpell && Me.Location.Distance(target.Location) >= maxRange;
            bool shouldMove = shouldMoveMelee || shouldMoveRanged;
            if (verboseLogging)
            {
                slog("ShouldMove: {0}", shouldMove);
            } 
            if (shouldMove)
            {
                slog("Moving to {0}", target.Name);
                WoWMovement.ClickToMove(target.Location, maxRange - 3);
            }
            if (SpellManager.CanCast(spellId, target))
            {
                SpellManager.Cast(spellId, target);
            }
        }
        private bool IsTargetingFriend(WoWUnit p)
        {
            return p.IsTargetingMeOrPet || p.IsTargetingMyPartyMember || p.IsTargetingMyRaidMember;
        }
        private bool IsTargetedByFriend(WoWUnit m)
        {
            foreach (WoWPlayer friend in friends)
            {
                if(friend.CurrentTarget == m)
                {
                    return true;
                }
            }
            return false;
        }
        private WoWPlayer BestHealingTarget()
        {
            WoWPlayer lowest = Me;
            foreach(WoWPlayer player in friends)
            {
                if(Me.Location.Distance(player.Location) < 30 && player.HealthPercent < lowest.HealthPercent)
                {
                    lowest = player;
                }
            }
            return lowest;
        }
        private WoWUnit BestAttackTarget()
        {
            WoWUnit lowest = Targets[0];
            foreach(WoWUnit mob in Targets)
            {
                if (IsAllTargetsCCed())
                {
                    if (mob.HealthPercent < lowest.HealthPercent)
                    {
                        lowest = mob;
                    }
                }
                else
                {
                    if (mob.HealthPercent < lowest.HealthPercent && !IsCCed(mob))
                    {
                        lowest = mob;
                    }
                }
            }
            lowest.Target();
            lowest.Face();
            return lowest;
        }
        private WoWUnit BestCCTarget()
        {
            WoWUnit bestTarget = null;
            foreach(WoWUnit mob in Targets)
            {
                if (bestTarget == null && !IsTargetedByFriend(mob) && ValidRepTarget(mob) && !IsCCed(mob))
                {
                    bestTarget = mob;
                }
                if (bestTarget != null && mob.HealthPercent > bestTarget.HealthPercent && !IsTargetedByFriend(mob) && ValidRepTarget(mob))
                {
                    bestTarget = mob;
                }
            }
            return bestTarget;
        }
        private WoWUnit BestExorcismTarget()
        {
            WoWUnit bestTarget = Me.CurrentTarget;
            foreach (WoWUnit mob in Targets)
            {
                if (!GoodExorcismTarget(bestTarget) && GoodExorcismTarget(mob) && !IsCCed(mob))
                {
                    bestTarget = mob;
                }
                if (GoodExorcismTarget(bestTarget) && GoodExorcismTarget(mob) && !IsCCed(mob))
                {
                    if (mob.HealthPercent < bestTarget.HealthPercent) bestTarget = mob;
                }
            }
            return bestTarget;
        }
        private bool ValidRepTarget(WoWUnit mob)
        {
            return  !IsCCed(mob) && (mob.IsDemon || mob.IsDragon || mob.IsHumanoid || mob.IsGiant || mob.IsUndead);
        }
        private bool GoodExorcismTarget(WoWUnit mob)
        {
            return mob.IsDemon || mob.IsUndead;
            
        }
        private bool HasMyAura(WoWUnit friend, string aura)
        {
            return friend.GetAllAuras().Any(a => a.Name == aura && (a.CreatorGuid == Me.Guid));
        }
        private bool HasMyAura(WoWUnit friend, int aura)
        {
            return friend.GetAllAuras().Any(a => a.SpellId == aura && (a.CreatorGuid == Me.Guid));
        }
        private bool HasKingsLikeBuff(WoWUnit friend)
        {
            return friend.HasAura("Blessing of Kings") || friend.HasAura("Mark of the Wild") ||
                   friend.HasAura("Embrace of the Shale Spider");
        }
        private bool HasMightLikeBuff(WoWUnit friend)
        {
            return friend.HasAura("Blessing of Might") || friend.HasAura("Abomination's Might") ||
                   friend.HasAura("Trueshot Aura") || friend.HasAura("Unleashed Rage");
        }
        private string ChooseBlessing()
        {
            string kings = "Blessing of Kings";
            string might = "Blessing of Might";
            if (friends.Any(f => HasMyAura(f, kings)))
                return kings;
            if (friends.Any(f => HasMyAura(f, might)))
                return might;
            if (!friends.Any(f => HasKingsLikeBuff(f)))
                return kings;
            if (!friends.Any(f => HasMightLikeBuff(f)))
                return might;
            return kings;
        }
        private string ChooseAura()
        {
            string retribution = "Retribution Aura";
            string devotion = "Devotion Aura";
            string resistance = "Resistance Aura";
            string concentration = "Concentration Aura";
            if (!Me.HasAura(retribution))
                return retribution;
            if (!Me.HasAura(devotion) && !HasMyAura(Me, retribution))
                return devotion;
            if (!Me.HasAura(resistance) && !HasMyAura(Me, devotion))
                return resistance;
            if (!Me.HasAura(concentration) && !HasMyAura(Me, resistance))
                return concentration;
            return retribution;
        }
        private bool IsCCed(WoWUnit unit)
        {
            return HasAuraWithMechanic(unit, WoWSpellMechanic.Banished, WoWSpellMechanic.Shackled,
                                       WoWSpellMechanic.Incapacitated, WoWSpellMechanic.Polymorphed,
                                       WoWSpellMechanic.Shackled, WoWSpellMechanic.Disoriented, WoWSpellMechanic.Sapped,
                                       WoWSpellMechanic.Asleep);
        }
        private bool HasAuraWithMechanic(WoWUnit unit, params WoWSpellMechanic[] mechanics)
        {
            return unit.GetAllAuras().Any(a => mechanics.Contains(a.Spell.Mechanic));
        }
        private bool IsAllTargetsCCed()
        {
            return Targets.All(t => IsCCed(t));
        }
        private void MoveToUnit(WoWUnit unit)
        {
            if (!unit.IsWithinMeleeRange)
            {
                slog("Moving to {0}", unit.Name);
                WoWMovement.ClickToMove(unit.Location, 3);
            }
        }
    }   
}

PS: It happens both with in-combat heals and out of combat heals (rest)
 
Which botbase are you using? One thing I would suggest is putting a return statement at the begining of your combat method for global cd and casting.

so...
PHP:
if (StyxWoW.GlobalCooldown || Me.IsCasting)
                return;

This may not solve your problem, but it will help you control your flow a little better. In that black space of time when you are on global cd or are casting, the CC is running through your rotation millions of times. This should ensure that it starts at the beginning when you are done casting. If you are using RaidBot, this isn't a problem. With lazyraider, it sometimes is. If you had a class with lots of instant casts without cooldowns, you might notice you rotation seem almost random.

I noticed with warlocks, double casting is a huge pain in the ass. What I did was blacklist the spells for a couple seconds. If you want to do that, use this...

ExpiringItem.cs

You can call it this way...

PHP:
List<ExpiringItem> list = new List<ExpiringItem>()
ExpiringItem e = new ExpiringItem(spellName, Miliseconds);

list.Add(e);

then...

public bool SpellBlackListed(string spell)
        {
            foreach (ExpiringItem s in list)
            {
                if (s.item.Equals(spell))
                {
                    return true;
                }
            }
            return false;
        }

list.Add(e);

If you blacklist the spell when you cast it, the timer starts when you start casting. So make the length just a little longer than the cast time. Just long enough to know you have been healed. When the timer is up, the name of the ExpiringItem turns to an empty string. Make sure you prune your list every once in a while or you will have a list full of empty strings.
 
Last edited:
Thanks for the tip. I've experienced it with Combat Bot/Grind Bot/Partybot.

That is a very hack'n'slash solution - I've thought that I'd try something like this:
PHP:
if (Me.IsCasting && Me.CastingSpell.Mechanic == WoWSpellMechanic.Healing && BestHealingTarget().HealthPercent >= 75)
                SpellManager.StopCasting();

Or another way could be targeting the person that I'm healing - and if Me.CurrentTarget.HealthPercent >= 75 -> stop casting
 
Last edited:
Back
Top