private Vector3 RandomLocationInAoe(AreaOfEffect area, Target origin)
        {
            Assert.IsNotNull(area);
            switch (area.Area)
            {
            case AreaOfEffect.AreaType.Cone:
                return(AoeUtility.RandomInCone(
                           origin.Position,
                           origin.Forward,
                           area.Angle.GetValue(SpellHandler.Stacks),
                           area.Size.GetValue(SpellHandler.Stacks),
                           area.MinSize.GetValue(SpellHandler.Stacks)));

            case AreaOfEffect.AreaType.Sphere:
                return(AoeUtility.RandomInsideSphere(origin.Position,
                                                     area.Size.GetValue(SpellHandler.Stacks),
                                                     area.MinSize.GetValue(SpellHandler.Stacks)));

            case AreaOfEffect.AreaType.Line:
                return(AoeUtility.RandomInLine(origin.Position, Target.Position));

            default:
                throw new InvalidOperationException($"Invalid area type: {area.Area}");
            }
        }
        private void FillTargetsInAoe(List <Target> targets, AreaOfEffect area, Target origin)
        {
            targets.Clear();
            Assert.IsNotNull(area, "Area must be set to use FillTargetsInAoe");
            IEnumerable <Vector3> positions;

            switch (area.Area)
            {
            case AreaOfEffect.AreaType.Cone:
                positions = AoeUtility.EnumerateLocationsInCone(
                    origin.OffsettedPosition,
                    origin.Forward,
                    area.Angle.GetValue(Stacks),
                    area.Size.GetValue(Stacks),
                    area.MinSize.GetValue(Stacks),
                    1f);
                break;

            case AreaOfEffect.AreaType.Sphere:
                positions = AoeUtility.EnumerateLocationsInCircle(
                    origin.OffsettedPosition,
                    area.Size.GetValue(Stacks),
                    area.MinSize.GetValue(Stacks),
                    1f);
                break;

            case AreaOfEffect.AreaType.Line:
                // Todo: eliminate direct usage of Target
                positions = AoeUtility.EnumerateLocationsInLine(
                    origin.OffsettedPosition,
                    Target.OffsettedPosition);
                break;

            default:
                positions = null;
                break;
            }

            if (positions == null)
            {
                return;
            }

            foreach (var pos in positions)
            {
                targets.Add(new Target(pos));
            }
        }
        private void CharactersInAoe(
            List <CharacterState> characters,
            AreaOfEffect area,
            Target origin)
        {
            // Clear buffer
            characters.Clear();
            Assert.IsNotNull(area);
            switch (area.Area)
            {
            case AreaOfEffect.AreaType.Cone:
                AoeUtility.CharactersInsideConeNonAlloc(
                    characters,
                    origin.OffsettedPosition,
                    origin.Forward,
                    area.Angle.GetValue(Stacks),
                    area.Size.GetValue(Stacks),
                    area.MinSize.GetValue(Stacks));
                return;

            case AreaOfEffect.AreaType.Sphere:
                AoeUtility.CharactersInsideSphereNonAlloc(
                    characters,
                    origin.OffsettedPosition,
                    area.Size.GetValue(Stacks),
                    area.MinSize.GetValue(Stacks));
                return;

            case AreaOfEffect.AreaType.Line:
                // Todo: eliminate direct usage of Target
                AoeUtility.CharactersInLineNonAlloc(characters,
                                                    origin.OffsettedPosition,
                                                    Target.OffsettedPosition);
                return;

            default:
                throw new InvalidOperationException($"Invalid area type: {area.Area}");
            }
        }