~ruther/NosSmooth

36b2b063e44dbdb73fbda1f2eeccc6ae797d203f — Rutherther 3 years ago c1dde0d
feat(combat): use attack command in combat manager
1 files changed, 79 insertions(+), 50 deletions(-)

M Extensions/NosSmooth.Extensions.Combat/CombatManager.cs
M Extensions/NosSmooth.Extensions.Combat/CombatManager.cs => Extensions/NosSmooth.Extensions.Combat/CombatManager.cs +79 -50
@@ 5,6 5,7 @@
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using NosSmooth.Core.Client;
using NosSmooth.Core.Commands.Attack;
using NosSmooth.Core.Stateful;
using NosSmooth.Extensions.Combat.Errors;
using NosSmooth.Extensions.Combat.Operations;


@@ 40,66 41,94 @@ public class CombatManager : IStatefulEntity
    /// Enter into a combat state using the given technique.
    /// </summary>
    /// <param name="technique">The technique to use.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not succeed.</returns>
    public async Task<Result> EnterCombat(ICombatTechnique technique)
    public async Task<Result> EnterCombatAsync(ICombatTechnique technique, CancellationToken ct = default)
    {
        var combatState = new CombatState(_client, _game, this);
        long? currentTarget = null;
        long? previousTarget = null;

        while (!combatState.ShouldQuit)
        {
            if (!technique.ShouldContinue(combatState))
            var commandResult = await _client.SendCommandAsync
            (
                new AttackCommand
                (
                    currentTarget,
                    async (c) =>
                    {
                        while (!combatState.ShouldQuit && currentTarget == previousTarget)
                        {
                            if (!technique.ShouldContinue(combatState))
                            {
                                combatState.QuitCombat();
                                continue;
                            }

                            var operation = combatState.NextOperation();

                            if (operation is null)
                            { // The operation is null and the step has to be obtained from the technique.
                                var stepResult = technique.HandleCombatStep(combatState);
                                if (!stepResult.IsSuccess)
                                {
                                    return Result.FromError(stepResult);
                                }

                                previousTarget = currentTarget;
                                currentTarget = stepResult.Entity;

                                operation = combatState.NextOperation();
                            }

                            if (operation is null)
                            { // The operation could be null just because there is currently not a skill to be used etc.
                                await Task.Delay(5, ct);
                                continue;
                            }

                            Result<CanBeUsedResponse> responseResult;
                            while ((responseResult = operation.CanBeUsed(combatState)).IsSuccess
                                && responseResult.Entity == CanBeUsedResponse.MustWait)
                            { // TODO: wait for just some amount of time
                                await Task.Delay(5, ct);
                            }

                            if (!responseResult.IsSuccess)
                            {
                                return Result.FromError(responseResult);
                            }

                            if (responseResult.Entity == CanBeUsedResponse.WontBeUsable)
                            {
                                return new UnusableOperationError(operation);
                            }

                            var usageResult = await operation.UseAsync(combatState, ct);
                            if (!usageResult.IsSuccess)
                            {
                                var errorHandleResult = technique.HandleError(combatState, operation, usageResult);
                                if (!errorHandleResult.IsSuccess)
                                {
                                    return errorHandleResult;
                                }
                            }
                        }

                        return Result.FromSuccess();
                    }
                ),
                ct
            );

            if (!commandResult.IsSuccess)
            {
                combatState.QuitCombat();
                continue;
                return commandResult;
            }

            var operation = combatState.NextOperation();

            if (operation is null)
            { // The operation is null and the step has to be obtained from the technique.
                var stepResult = technique.HandleCombatStep(combatState);
                if (!stepResult.IsSuccess)
                {
                    return stepResult;
                }

                operation = combatState.NextOperation();
            }

            if (operation is null)
            { // The operation could be null just because there is currently not a skill to be used etc.
                await Task.Delay(5);
                continue;
            }

            Result<CanBeUsedResponse> responseResult;
            while ((responseResult = operation.CanBeUsed(combatState)).IsSuccess
                && responseResult.Entity == CanBeUsedResponse.MustWait)
            { // TODO: wait for just some amount of time
                await Task.Delay(5);
            }

            if (!responseResult.IsSuccess)
            {
                return Result.FromError(responseResult);
            }

            if (responseResult.Entity == CanBeUsedResponse.WontBeUsable)
            {
                return new UnusableOperationError(operation);
            }

            var usageResult = await operation.UseAsync(combatState);
            if (!usageResult.IsSuccess)
            {
                var errorHandleResult = technique.HandleError(combatState, operation, usageResult);
                if (!errorHandleResult.IsSuccess)
                {
                    return errorHandleResult;
                }
            }
            previousTarget = currentTarget;
        }

        return Result.FromSuccess();
    }


Do not follow this link