protected bool CanRun(KeyAction item)
        {
            if (!string.IsNullOrEmpty(item.CastIfAddsVisible))
            {
                var needAdds = bool.Parse(item.CastIfAddsVisible);
                if (needAdds != npcNameFinder.PotentialAddsExist)
                {
                    item.LogInformation($"Only cast if adds exist = {item.CastIfAddsVisible} and it is {npcNameFinder.PotentialAddsExist}");
                    return(false);
                }
            }

            if (item.School != SchoolMask.None)
            {
                if (classConfig.ImmunityBlacklist.TryGetValue(playerReader.TargetId, out var list))
                {
                    if (list.Contains(item.School))
                    {
                        return(false);
                    }
                }
            }

            return(item.CanRun());
        }
Example #2
0
        protected bool CanRun(KeyAction item)
        {
            if (!string.IsNullOrEmpty(item.CastIfAddsVisible))
            {
                var needAdds = bool.Parse(item.CastIfAddsVisible);
                if (needAdds != npcNameFinder.PotentialAddsExist)
                {
                    item.LogInformation($"Only cast if adds exist = {item.CastIfAddsVisible} and it is {npcNameFinder.PotentialAddsExist}");
                    return(false);
                }
            }

            return(item.CanRun());
        }
        public async Task <bool> CastIfReady(KeyAction item, int sleepBeforeCast = 0)
        {
            if (!CanRun(item))
            {
                return(false);
            }

            if (item.ConsoleKey == 0)
            {
                return(false);
            }

            if (item.Name == classConfig.Approach.Name ||
                item.Name == classConfig.AutoAttack.Name ||
                item.Name == classConfig.Interact.Name)
            {
                await PressKeyAction(item);

                return(true);
            }

            bool beforeUsable = addonReader.UsableAction.Is(item);
            var  beforeForm   = playerReader.Form;

            if (!await SwitchToCorrectStanceForm(beforeForm, item))
            {
                return(false);
            }

            if (beforeForm != playerReader.Form && !beforeUsable && !addonReader.UsableAction.Is(item))
            {
                item.LogInformation(" ... after Form switch still not usable!");
                return(false);
            }

            if (playerReader.Bits.IsAutoRepeatSpellOn_Shoot)
            {
                await input.TapStopAttack("Stop AutoRepeat Shoot");

                await input.TapStopAttack("Stop AutoRepeat Shoot");

                await wait.Update(1);

                (bool interrupted, double elapsedMs) = await wait.InterruptTask(GCD,
                                                                                () => addonReader.UsableAction.Is(item));

                if (!interrupted)
                {
                    item.LogInformation($" ... waited to end Shoot {elapsedMs}ms");
                }
            }

            if (sleepBeforeCast > 0)
            {
                if (item.StopBeforeCast || item.HasCastBar)
                {
                    await stopMoving.Stop();

                    await wait.Update(1);

                    await stopMoving.Stop();

                    await wait.Update(1);
                }

                item.LogInformation($" Wait {sleepBeforeCast}ms before press.");
                await Task.Delay(sleepBeforeCast);
            }

            bool beforeHasTarget = playerReader.HasTarget;
            int  auraHash        = playerReader.AuraCount.Hash;


            if (!await WaitForGCD(item, beforeHasTarget))
            {
                return(false);
            }

            if (!item.HasCastBar)
            {
                if (!await CastInstant(item))
                {
                    // try again after reacted to UI_ERROR
                    if (!await CastInstant(item))
                    {
                        return(false);
                    }
                }
            }
            else
            {
                if (!await CastCastbar(item))
                {
                    // try again after reacted to UI_ERROR
                    if (!await CastCastbar(item))
                    {
                        return(false);
                    }
                }
            }

            if (item.AfterCastWaitBuff)
            {
                (bool notappeared, double elapsedMs) = await wait.InterruptTask(MaxWaitBuffTimeMs, () => auraHash != playerReader.AuraCount.Hash);

                item.LogInformation($" ... AfterCastWaitBuff: Buff: {!notappeared} | pb: {playerReader.AuraCount.PlayerBuff} | pd: {playerReader.AuraCount.PlayerDebuff} | tb: {playerReader.AuraCount.TargetBuff} | td: {playerReader.AuraCount.TargetDebuff} | Delay: {elapsedMs}ms");
            }

            if (item.DelayAfterCast != defaultKeyAction.DelayAfterCast)
            {
                if (item.DelayUntilCombat) // stop waiting if the mob is targetting me
                {
                    item.LogInformation($" ... DelayUntilCombat ... delay after cast {item.DelayAfterCast}ms");

                    var sw = new Stopwatch();
                    sw.Start();
                    while (sw.ElapsedMilliseconds < item.DelayAfterCast)
                    {
                        await wait.Update(1);

                        if (playerReader.Bits.TargetOfTargetIsPlayer)
                        {
                            break;
                        }
                    }
                }
                else if (item.DelayAfterCast > 0)
                {
                    item.LogInformation($" ... delay after cast {item.DelayAfterCast}ms");
                    var result = await wait.InterruptTask(item.DelayAfterCast, () => beforeHasTarget != playerReader.HasTarget);

                    if (!result.Item1)
                    {
                        item.LogInformation($" .... delay after cast interrupted, target changed {result.Item2}ms");
                    }
                    else
                    {
                        item.LogInformation($" .... delay after cast not interrupted {result.Item2}ms");
                    }
                }
            }
            else
            {
                if (item.RequirementObjects.Any())
                {
                    (bool firstReq, double firstReqElapsedMs) = await wait.InterruptTask(SpellQueueTimeMs,
                                                                                         () => !item.CanRun()
                                                                                         );

                    item.LogInformation($" ... instant interrupt: {!firstReq} | CanRun:{item.CanRun()} | Delay: {firstReqElapsedMs}ms");
                }
            }

            if (item.StepBackAfterCast > 0)
            {
                input.SetKeyState(ConsoleKey.DownArrow, true, false, $"Step back for {item.StepBackAfterCast}ms");
                (bool notStepback, double stepbackElapsedMs) =
                    await wait.InterruptTask(item.StepBackAfterCast, () => beforeHasTarget != playerReader.HasTarget);

                if (!notStepback)
                {
                    item.LogInformation($" .... interrupted stepback | lost target? {beforeHasTarget != playerReader.HasTarget} | {stepbackElapsedMs}ms");
                }
                input.SetKeyState(ConsoleKey.DownArrow, false, false);
            }

            if (item.AfterCastWaitNextSwing)
            {
                await wait.Update(1);
            }

            item.ConsumeCharge();
            return(true);
        }