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} - Targets:{npcNameFinder.TargetCount} - Adds:{npcNameFinder.AddCount}");
                    return(false);
                }
                else
                {
                    item.LogInformation($"Only cast if adds exist = {item.CastIfAddsVisible} and it is {npcNameFinder.PotentialAddsExist} - Targets:{npcNameFinder.TargetCount} - Adds:{npcNameFinder.AddCount}");
                }
            }

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

            return(item.CanRun());
        }
        private async Task <bool> WaitForGCD(KeyAction item, bool beforeHasTarget)
        {
            if (item.WaitForGCD)
            {
                (bool gcd, double gcdElapsedMs) = await wait.InterruptTask(GCD,
                                                                           () => addonReader.UsableAction.Is(item) || beforeHasTarget != playerReader.HasTarget);

                if (!gcd)
                {
                    item.LogInformation($" ... gcd interrupted {gcdElapsedMs}ms");

                    if (beforeHasTarget != playerReader.HasTarget)
                    {
                        item.LogInformation($" ... lost target!");
                        return(false);
                    }
                }
                else
                {
                    item.LogInformation($" ... gcd fully waited {gcdElapsedMs}ms");
                }
            }

            return(true);
        }
        private async Task <bool> CastInstant(KeyAction item)
        {
            if (item.StopBeforeCast)
            {
                await stopMoving.Stop();

                await wait.Update(1);
            }

            playerReader.CastEvent.ForceUpdate(0);
            int  beforeCastEventValue = playerReader.CastEvent.Value;
            int  beforeSpellId        = playerReader.CastSpellId.Value;
            bool beforeUsable         = addonReader.UsableAction.Is(item);

            await PressKeyAction(item);

            bool   inputNotHappened;
            double inputElapsedMs;

            if (item.AfterCastWaitNextSwing)
            {
                (inputNotHappened, inputElapsedMs) = await wait.InterruptTask(MaxSwingTimeMs,
                                                                              interrupt : () => !addonReader.CurrentAction.Is(item),
                                                                              repeat : async() =>
                {
                    if (classConfig.Approach.GetCooldownRemaining() == 0)
                    {
                        await input.TapApproachKey("");
                    }
                });
            }
            else
            {
                (inputNotHappened, inputElapsedMs) = await wait.InterruptTask(MaxWaitCastTimeMs,
                                                                              interrupt : () =>
                                                                              (beforeSpellId != playerReader.CastSpellId.Value && beforeCastEventValue != playerReader.CastEvent.Value) ||
                                                                              beforeUsable != addonReader.UsableAction.Is(item)
                                                                              );
            }

            if (!inputNotHappened)
            {
                item.LogInformation($" ... instant input {inputElapsedMs}ms");
            }
            else
            {
                item.LogInformation($" ... instant input not registered! {inputElapsedMs}ms");
                return(false);
            }

            item.LogInformation($" ... usable: {beforeUsable}->{addonReader.UsableAction.Is(item)} -- ({(UI_ERROR)beforeCastEventValue}->{(UI_ERROR)playerReader.CastEvent.Value})");

            if (!CastSuccessfull((UI_ERROR)playerReader.CastEvent.Value))
            {
                await ReactToLastCastingEvent(item, $"{item.Name}-{GetType().Name}: CastInstant");

                return(false);
            }
            return(true);
        }
Пример #4
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());
        }
        protected async Task <bool> SwitchToCorrectStanceForm(Form beforeForm, KeyAction item)
        {
            if (string.IsNullOrEmpty(item.Form))
            {
                return(true);
            }

            if (playerReader.Form == item.FormEnum)
            {
                return(true);
            }

            var formKeyAction = classConfig.Form
                                .Where(s => s.FormEnum == item.FormEnum)
                                .FirstOrDefault();

            if (formKeyAction == null)
            {
                logger.LogWarning($"Unable to find key in Form to transform into {item.FormEnum}");
                return(false);
            }

            await input.KeyPress(formKeyAction.ConsoleKey, formKeyAction.PressDuration);

            (bool notChanged, double elapsedMs) = await wait.InterruptTask(SpellQueueTimeMs, () => beforeForm != playerReader.Form);

            item.LogInformation($" ... form changed: {!notChanged} | Delay: {elapsedMs}ms");

            if (playerReader.Form == Form.None)
            {
                item.LogInformation($" ... wait for GCD after form change {beforeForm}->{playerReader.Form}!");
                await WaitForGCD(item, playerReader.HasTarget);
            }

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

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

            if (!await SwitchToCorrectShapeShiftForm(item))
            {
                return(false);
            }

            if (this.playerReader.IsShooting)
            {
                await input.TapInteractKey("Stop casting shoot");

                await Task.Delay(1500); // wait for shooting to end
            }

            if (sleepBeforeCast > 0)
            {
                item.LogInformation($" Wait before {sleepBeforeCast}.");
                await Task.Delay(sleepBeforeCast);
            }

            await PressKey(item.ConsoleKey, item.Name, item.PressDuration);

            item.SetClicked();

            if (!item.HasCastBar)
            {
                var result = await WaitInterrupt(item.DelayAfterCast,
                                                 () => playerReader.PlayerBitValues.TargetIsDead || playerReader.TargetHealthPercentage < 5);

                item.LogInformation($" ... no castbar delay after cast {result.Item2}ms");
                await InteractOnUIError();
            }
            else
            {
                await playerReader.WaitForNUpdate(1);

                if (!this.playerReader.IsCasting && this.playerReader.HasTarget)
                {
                    await this.InteractOnUIError();

                    item.LogInformation($"Not casting, pressing it again");
                    await PressKey(item.ConsoleKey, item.Name, item.PressDuration);

                    await playerReader.WaitForNUpdate(1);

                    if (!this.playerReader.IsCasting && this.playerReader.HasTarget)
                    {
                        item.LogInformation($"Still not casting !");
                        await this.InteractOnUIError();

                        return(false);
                    }
                }

                item.LogInformation(" waiting for cast bar to end.");
                for (int i = 0; i < 15000; i += 100)
                {
                    if (!this.playerReader.IsCasting)
                    {
                        await playerReader.WaitForNUpdate(1);

                        break;
                    }

                    // wait after cast if the delay is different to the default value
                    if (item.DelayAfterCast != new KeyAction().DelayAfterCast)
                    {
                        item.LogInformation($" ... delay after cast {item.DelayAfterCast}");

                        if (item.DelayUntilCombat) // stop waiting if the mob is targetting me
                        {
                            var sw = new Stopwatch();
                            sw.Start();
                            while (sw.ElapsedMilliseconds < item.DelayAfterCast)
                            {
                                await Task.Delay(10);

                                if (this.playerReader.PlayerBitValues.TargetOfTargetIsPlayer)
                                {
                                    break;
                                }
                            }
                        }
                        else
                        {
                            var result = await WaitInterrupt(item.DelayAfterCast,
                                                             () => playerReader.PlayerBitValues.TargetIsDead || playerReader.TargetHealthPercentage < 5);

                            item.LogInformation($" ... castbar delay after cast {result.Item2}ms");
                        }
                    }

                    await playerReader.WaitForNUpdate(1);
                }
            }
            if (item.StepBackAfterCast > 0)
            {
                await this.input.KeyPress(ConsoleKey.DownArrow, item.StepBackAfterCast, $"Step back for {item.StepBackAfterCast}ms");
            }

            item.ConsumeCharge();
            return(true);
        }
Пример #7
0
        public async Task <bool> CastIfReady(KeyAction item, GoapGoal source, int sleepBeforeCast = 0)
        {
            if (!CanRun(item))
            {
                return(false);
            }

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

            if (!await SwitchToCorrectShapeShiftForm(item))
            {
                return(false);
            }

            if (this.playerReader.IsShooting)
            {
                await TapInteractKey("Stop casting shoot");

                await Task.Delay(1500); // wait for shooting to end
            }

            if (sleepBeforeCast > 0)
            {
                item.LogInformation($" Wait before {sleepBeforeCast}.");
                await Task.Delay(sleepBeforeCast);
            }

            await PressKey(item.ConsoleKey, item.Name, item.PressDuration);

            item.SetClicked();

            if (!item.HasCastBar)
            {
                item.LogInformation($" ... delay after cast {item.DelayAfterCast}");
                await Task.Delay(item.DelayAfterCast);
            }
            else
            {
                await Task.Delay(300);

                if (!this.playerReader.IsCasting && this.playerReader.HasTarget)
                {
                    await this.InteractOnUIError();

                    item.LogInformation($"Not casting, pressing it again");
                    await PressKey(item.ConsoleKey, item.Name, item.PressDuration);

                    await Task.Delay(300);

                    if (!this.playerReader.IsCasting && this.playerReader.HasTarget)
                    {
                        item.LogInformation($"Still not casting !");
                        await this.InteractOnUIError();

                        return(false);
                    }
                }

                item.LogInformation(" waiting for cast bar to end.");
                for (int i = 0; i < 15000; i += 100)
                {
                    if (!this.playerReader.IsCasting)
                    {
                        await Task.Delay(100);

                        break;
                    }

                    // wait after cast if the delay is different to the default value
                    if (item.DelayAfterCast != new KeyAction().DelayAfterCast)
                    {
                        item.LogInformation($" ... delay after cast {item.DelayAfterCast}");

                        if (item.DelayUntilCombat) // stop waiting if the mob is targetting me
                        {
                            var sw = new Stopwatch();
                            sw.Start();
                            while (sw.ElapsedMilliseconds < item.DelayAfterCast)
                            {
                                await Task.Delay(10);

                                if (this.playerReader.PlayerBitValues.TargetOfTargetIsPlayer)
                                {
                                    break;
                                }
                            }
                        }
                        else
                        {
                            await Task.Delay(item.DelayAfterCast);
                        }
                    }

                    if (source.GetType() == typeof(PullTargetGoal) &&
                        this.playerReader.PlayerBitValues.PlayerInCombat &&
                        !this.playerReader.PlayerBitValues.TargetOfTargetIsPlayer &&
                        this.playerReader.IsCasting &&
                        this.playerReader.TargetHealthPercentage > 99
                        )
                    {
                        if (!this.playerReader.TargetIsFrostbitten)
                        {
                            await this.wowProcess.KeyPress(ConsoleKey.UpArrow, 200, "Stop cast as picked up an add, my mob is not targetting me.");

                            await wowProcess.KeyPress(ConsoleKey.F3, 400); // clear target

                            break;
                        }
                    }

                    await Task.Delay(100);
                }
            }
            if (item.StepBackAfterCast > 0)
            {
                await this.wowProcess.KeyPress(ConsoleKey.DownArrow, item.StepBackAfterCast * 1000, "Step back hero");
            }
            return(true);
        }
        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);
        }
        private async Task <bool> CastCastbar(KeyAction item)
        {
            if (playerReader.Bits.IsFalling)
            {
                (bool notfalling, double fallingElapsedMs) = await wait.InterruptTask(MaxAirTimeMs, () => !playerReader.Bits.IsFalling);

                if (!notfalling)
                {
                    item.LogInformation($" ... castbar waited for landing {fallingElapsedMs}ms");
                }
            }

            await stopMoving.Stop();

            await wait.Update(1);

            bool beforeHasTarget = playerReader.HasTarget;

            bool beforeUsable         = addonReader.UsableAction.Is(item);
            int  beforeCastEventValue = playerReader.CastEvent.Value;
            int  beforeSpellId        = playerReader.CastSpellId.Value;
            int  beforeCastCount      = playerReader.CastCount;

            await PressKeyAction(item);

            (bool input, double inputElapsedMs) = await wait.InterruptTask(MaxWaitCastTimeMs,
                                                                           interrupt : () =>
                                                                           beforeCastEventValue != playerReader.CastEvent.Value ||
                                                                           beforeSpellId != playerReader.CastSpellId.Value ||
                                                                           beforeCastCount != playerReader.CastCount
                                                                           );

            if (!input)
            {
                item.LogInformation($" ... castbar input {inputElapsedMs}ms");
            }
            else
            {
                item.LogInformation($" ... castbar input not registered! {inputElapsedMs}ms");
                return(false);
            }

            item.LogInformation($" ... casting: {playerReader.IsCasting} -- count:{playerReader.CastCount} -- usable: {beforeUsable}->{addonReader.UsableAction.Is(item)} -- {(UI_ERROR)beforeCastEventValue}->{(UI_ERROR)playerReader.CastEvent.Value}");

            if (!CastSuccessfull((UI_ERROR)playerReader.CastEvent.Value))
            {
                await ReactToLastCastingEvent(item, $"{item.Name}-{GetType().Name}: CastCastbar");

                return(false);
            }

            if (playerReader.IsCasting)
            {
                item.LogInformation(" ... waiting for visible cast bar to end or target loss.");
                await wait.InterruptTask(MaxCastTimeMs, () => !playerReader.IsCasting || beforeHasTarget != playerReader.HasTarget);
            }
            else if ((UI_ERROR)playerReader.CastEvent.Value == UI_ERROR.CAST_START)
            {
                beforeCastEventValue = playerReader.CastEvent.Value;
                item.LogInformation(" ... waiting for hidden cast bar to end or target loss.");
                await wait.InterruptTask(MaxCastTimeMs, () => beforeCastEventValue != playerReader.CastEvent.Value || beforeHasTarget != playerReader.HasTarget);
            }

            return(true);
        }