/// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (_species is null)
            {
                throw new InvalidOperationException
                      (
                          "The shifter must be constructed with a target species when shifting parts."
                      );
            }

            var getTFResult = await _transformations.GetTransformationsByPartAndSpeciesAsync(bodypart, _species);

            if (!getTFResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getTFResult));
            }

            var transformation = getTFResult.Entity.First();

            if (this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var existingComponent))
            {
                if (existingComponent.Transformation.Species.Name.Equals(transformation.Species.Name))
                {
                    var message = await GetNoChangeMessageAsync(bodypart);

                    return(ShiftBodypartResult.FromError
                           (
                               message
                           ));
                }
            }

            string shiftMessage;

            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                currentComponent = AppearanceComponent.CreateFrom(transformation, chirality);

                this.Appearance.Components.Add(currentComponent);

                shiftMessage = await GetAddMessageAsync(bodypart, chirality);

                return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Add));
            }

            if (currentComponent.Transformation.Species.Name == "template")
            {
                // Apply default settings
                currentComponent.BaseColour = transformation.DefaultBaseColour.Clone();

                currentComponent.Pattern       = transformation.DefaultPattern;
                currentComponent.PatternColour = transformation.DefaultPatternColour?.Clone();
            }

            currentComponent.Transformation = transformation;

            shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Shift));
        }
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            var character = this.Appearance.Character;

            var getAppearanceResult = await _transformations.GetOrCreateCurrentAppearanceAsync(character);

            if (!getAppearanceResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getAppearanceResult));
            }

            var appearance = getAppearanceResult.Entity;

            if (!appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.BaseColour.IsSameColourAs(_colour))
            {
                return(ShiftBodypartResult.FromError("The bodypart is already that colour."));
            }

            currentComponent.BaseColour = _colour.Clone();

            var shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Shift));
        }
Esempio n. 3
0
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.Pattern == _pattern)
            {
                return(ShiftBodypartResult.FromError("The character already has that pattern."));
            }

            var shiftAction = ShiftBodypartAction.Shift;

            if (currentComponent.Pattern is null)
            {
                shiftAction = ShiftBodypartAction.Add;
            }

            currentComponent.Pattern       = _pattern;
            currentComponent.PatternColour = _patternColour.Clone();

            var shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, shiftAction));
        }
Esempio n. 4
0
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> RemoveBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            var character = this.Appearance.Character;

            var getAppearanceResult = await _transformations.GetOrCreateCurrentAppearanceAsync(character);

            if (!getAppearanceResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getAppearanceResult));
            }

            var appearance = getAppearanceResult.Entity;

            if (!appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.Pattern is null)
            {
                return(ShiftBodypartResult.FromError("The character doesn't have a pattern on that part."));
            }

            currentComponent.Pattern       = null;
            currentComponent.PatternColour = null;

            var shiftMessage = await GetRemoveMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Remove));
        }
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.Pattern is null)
            {
                return(ShiftBodypartResult.FromError("That bodypart doesn't have a pattern."));
            }

            // ReSharper disable once PossibleNullReferenceException
            // Having a pattern implies having a pattern colour
            if (currentComponent.PatternColour.IsSameColourAs(_colour))
            {
                return(ShiftBodypartResult.FromError("The pattern is already that colour."));
            }

            currentComponent.PatternColour = _colour.Clone();

            var shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Shift));
        }
Esempio n. 6
0
        private Task <string> BuildMessageFromResultAsync
        (
            ShiftBodypartResult result,
            Bodypart bodypart,
            Chirality chirality
        )
        {
            switch (result.Action)
            {
            case ShiftBodypartAction.Remove:
            {
                return(GetRemoveMessageAsync(bodypart, chirality));
            }

            case ShiftBodypartAction.Nothing:
            {
                throw new InvalidOperationException("Can't build a message for something that didn't happen.");
            }

            default:
            {
                throw new ArgumentOutOfRangeException();
            }
            }
        }
Esempio n. 7
0
        /// <inheritdoc />
        protected override Task <ShiftBodypartResult> RemoveBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var component))
            {
                return(Task.FromResult(ShiftBodypartResult.FromError("The character doesn't have that bodypart.")));
            }

            this.Appearance.Components.Remove(component);

            var removeMessage = _descriptionBuilder.BuildRemoveMessage(this.Appearance, bodypart);

            return(Task.FromResult(ShiftBodypartResult.FromSuccess(removeMessage, ShiftBodypartAction.Remove)));
        }
Esempio n. 8
0
        /// <inheritdoc />
        public async Task <ShiftBodypartResult> RemoveAsync(Bodypart bodypart, Chirality chirality)
        {
            if (bodypart.IsChiral() && chirality == Chirality.Center)
            {
                return(ShiftBodypartResult.FromError("Please specify left or right when removing one-sided bodyparts."));
            }

            if (bodypart.IsComposite())
            {
                return(await RemoveCompositeBodypartAsync(bodypart));
            }

            return(await RemoveBodypartAsync(bodypart, chirality));
        }
 private Task <string> BuildMessageFromResultAsync
 (
     ShiftBodypartResult result,
     Bodypart bodypart,
     Chirality chirality
 )
 {
     return(result.Action switch
     {
         ShiftBodypartAction.Remove => GetRemoveMessageAsync(bodypart, chirality),
         ShiftBodypartAction.Nothing => throw new InvalidOperationException
         (
             "Can't build a message for something that didn't happen."
         ),
         _ => throw new ArgumentOutOfRangeException(nameof(result.Action))
     });
Esempio n. 10
0
        /// <summary>
        /// Shifts the given character's bodypart to the given species.
        /// </summary>
        /// <param name="context">The context of the command.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to shift.</param>
        /// <param name="speciesName">The species to shift the bodypart into.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> ShiftBodypartAsync
        (
            ICommandContext context,
            Character character,
            Bodypart bodyPart,
            string speciesName,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            var getSpeciesResult = await GetSpeciesByNameAsync(speciesName);

            if (!getSpeciesResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getSpeciesResult));
            }

            var species = getSpeciesResult.Entity;

            var getCurrentAppearance = await GetOrCreateCurrentAppearanceAsync(character);

            if (!getCurrentAppearance.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getCurrentAppearance));
            }

            var appearance = getCurrentAppearance.Entity;

            var speciesShifter = new SpeciesShifter(appearance, species, this, _descriptionBuilder);
            var shiftResult    = await speciesShifter.ShiftAsync(bodyPart, chirality);

            if (shiftResult.IsSuccess)
            {
                await _database.SaveChangesAsync();
            }

            return(shiftResult);
        }
Esempio n. 11
0
        /// <summary>
        /// Shifts the colour of the given bodypart on the given character to the given colour.
        /// </summary>
        /// <param name="context">The command context.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to shift.</param>
        /// <param name="colour">The colour to shift it into.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> ShiftBodypartColourAsync
        (
            ICommandContext context,
            Character character,
            Bodypart bodyPart,
            Colour colour,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            if (bodyPart.IsChiral() && chirality == Chirality.Center)
            {
                return(ShiftBodypartResult.FromError
                       (
                           $"Please specify if it's the left or right {bodyPart.Humanize().ToLower()}."
                       ));
            }

            var getCurrentAppearance = await GetOrCreateCurrentAppearanceAsync(character);

            if (!getCurrentAppearance.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getCurrentAppearance));
            }

            var appearance = getCurrentAppearance.Entity;

            var colourShifter = new ColourShifter(appearance, colour, _descriptionBuilder);
            var shiftResult   = await colourShifter.ShiftAsync(bodyPart, chirality);

            if (shiftResult.IsSuccess)
            {
                await _database.SaveChangesAsync();
            }

            return(shiftResult);
        }
Esempio n. 12
0
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.BaseColour.IsSameColourAs(_colour))
            {
                return(ShiftBodypartResult.FromError("The bodypart is already that colour."));
            }

            currentComponent.BaseColour = _colour.Clone();

            var shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Shift));
        }
Esempio n. 13
0
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> RemoveBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            if (!this.Appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.Pattern is null)
            {
                return(ShiftBodypartResult.FromError("The character doesn't have a pattern on that part."));
            }

            currentComponent.Pattern       = null;
            currentComponent.PatternColour = null;

            var shiftMessage = await GetRemoveMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, ShiftBodypartAction.Remove));
        }
Esempio n. 14
0
        /// <summary>
        /// Shifts the pattern of the given bodypart on the given character to the given pattern with the given colour.
        /// </summary>
        /// <param name="context">The command context.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to shift.</param>
        /// <param name="pattern">The pattern to shift the bodypart into.</param>
        /// <param name="patternColour">The colour to shift it into.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> ShiftBodypartPatternAsync
        (
            ICommandContext context,
            Character character,
            Bodypart bodyPart,
            Pattern pattern,
            Colour patternColour,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            var getAppearanceResult = await GetOrCreateCurrentAppearanceAsync(character);

            if (!getAppearanceResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getAppearanceResult));
            }

            var appearance = getAppearanceResult.Entity;

            var patternShifter = new PatternShifter(appearance, pattern, patternColour, _descriptionBuilder);
            var shiftResult    = await patternShifter.ShiftAsync(bodyPart, chirality);

            if (shiftResult.IsSuccess)
            {
                await _database.SaveChangesAsync();
            }

            return(shiftResult);
        }
Esempio n. 15
0
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> ShiftBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            var character = this.Appearance.Character;

            var getAppearanceResult = await _transformations.GetOrCreateCurrentAppearanceAsync(character);

            if (!getAppearanceResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getAppearanceResult));
            }

            var appearance = getAppearanceResult.Entity;

            if (!appearance.TryGetAppearanceComponent(bodypart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            if (currentComponent.Pattern == _pattern)
            {
                return(ShiftBodypartResult.FromError("The character already has that pattern."));
            }

            var shiftAction = ShiftBodypartAction.Shift;

            if (currentComponent.Pattern is null)
            {
                shiftAction = ShiftBodypartAction.Add;
            }

            currentComponent.Pattern       = _pattern;
            currentComponent.PatternColour = _patternColour.Clone();

            var shiftMessage = await GetShiftMessageAsync(bodypart, chirality);

            return(ShiftBodypartResult.FromSuccess(shiftMessage, shiftAction));
        }
        /// <inheritdoc />
        protected override async Task <ShiftBodypartResult> RemoveBodypartAsync(Bodypart bodypart, Chirality chirality)
        {
            var character = this.Appearance.Character;

            var getAppearanceResult = await _transformations.GetOrCreateCurrentAppearanceAsync(character);

            if (!getAppearanceResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getAppearanceResult));
            }

            var appearance = getAppearanceResult.Entity;

            if (!appearance.TryGetAppearanceComponent(bodypart, chirality, out var component))
            {
                return(ShiftBodypartResult.FromError("The character doesn't have that bodypart."));
            }

            appearance.Components.Remove(component);

            var removeMessage = _descriptionBuilder.BuildRemoveMessage(appearance, bodypart);

            return(ShiftBodypartResult.FromSuccess(removeMessage, ShiftBodypartAction.Remove));
        }
Esempio n. 17
0
        /// <summary>
        /// Decomposes and removes the given composite bodypart.
        /// </summary>
        /// <param name="bodypart">The bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        private async Task <ShiftBodypartResult> RemoveCompositeBodypartAsync(Bodypart bodypart)
        {
            var composingParts = bodypart.GetComposingParts();

            var currentParagraphLength = 0;
            var messageBuilder         = new StringBuilder();

            void InsertRemovalMessage(string message)
            {
                messageBuilder !.Append(message);

                if (!message.EndsWith(" "))
                {
                    messageBuilder.Append(" ");
                }

                if (currentParagraphLength > 240)
                {
                    messageBuilder.AppendLine();
                    messageBuilder.AppendLine();

                    currentParagraphLength = 0;
                }

                currentParagraphLength += message.Length;
            }

            foreach (var composingPart in composingParts)
            {
                if (composingPart.IsComposite())
                {
                    var shiftResult = await RemoveCompositeBodypartAsync(composingPart);

                    if (!shiftResult.IsSuccess || shiftResult.Action == ShiftBodypartAction.Nothing)
                    {
                        continue;
                    }

                    InsertRemovalMessage(shiftResult.ShiftMessage !);
                    continue;
                }

                if (composingPart.IsChiral())
                {
                    var leftShift = await RemoveBodypartAsync(composingPart, Chirality.Left);

                    var rightShift = await RemoveBodypartAsync(composingPart, Chirality.Right);

                    // There's a couple of cases here for us to deal with.
                    // 1: both parts were removed
                    // 2: one part was removed
                    // 3: no changes were made
                    if (leftShift.Action == ShiftBodypartAction.Nothing && rightShift.Action == ShiftBodypartAction.Nothing)
                    {
                        // No change, keep moving
                        continue;
                    }

                    if (leftShift.Action == ShiftBodypartAction.Remove && rightShift.Action == ShiftBodypartAction.Remove)
                    {
                        var uniformShiftMessage = await GetUniformRemoveMessageAsync(composingPart);

                        InsertRemovalMessage(uniformShiftMessage);
                        continue;
                    }

                    if (leftShift.Action != ShiftBodypartAction.Nothing)
                    {
                        InsertRemovalMessage
                        (
                            await BuildMessageFromResultAsync(leftShift, composingPart, Chirality.Left)
                        );
                    }

                    if (rightShift.Action != ShiftBodypartAction.Nothing)
                    {
                        InsertRemovalMessage
                        (
                            await BuildMessageFromResultAsync(rightShift, composingPart, Chirality.Right)
                        );
                    }
                }
                else
                {
                    var simpleShiftResult = await RemoveBodypartAsync
                                            (
                        composingPart,
                        Chirality.Center
                                            );

                    if (simpleShiftResult.Action != ShiftBodypartAction.Nothing)
                    {
                        InsertRemovalMessage
                        (
                            await BuildMessageFromResultAsync(simpleShiftResult, composingPart, Chirality.Center)
                        );
                    }
                }
            }

            if (messageBuilder.Length == 0)
            {
                return(ShiftBodypartResult.FromSuccess
                       (
                           await GetNoChangeMessageAsync(bodypart),
                           ShiftBodypartAction.Nothing
                       ));
            }

            return(ShiftBodypartResult.FromSuccess(messageBuilder.ToString(), ShiftBodypartAction.Shift));
        }