Example #1
0
        /// <summary>
        /// Our main menu screen method. Draws the recipe selection screen and handles related functions.
        /// </summary>
        /// <remarks>
        /// This (and several supporting methods) are static just for simplicity's sake, because it
        /// is easier to call from a Harmony patch when it's static. If we were implementing this
        /// directly, we wouldn't make this static.
        /// </remarks>
        public static ScreenReturn Show(List <Tuple <string, CookingRecipe> > recipeList, out int screenResult)
        {
            screenResult = -1;
            if (recipeList == null || recipeList.Count <= 0 || recipeList.Any(r => r.Item2 == null))
            {
                return(ScreenReturn.Exit);
            }

            recipeList.Sort(RecipeComparator);

            GameManager.Instance.PushGameView("QudUX:CookRecipes");
            ScreenBuffer cachedScrapBuffer = ScreenBuffer.GetScrapBuffer2(true);
            Keys         keys                = Keys.None;
            bool         shouldExitMenu      = false;
            int          scrollOffset        = 0;
            int          scrollAreaHeight    = 11;
            int          selectedRecipeIndex = 0;

            while (!shouldExitMenu)
            {
                ScrapBuffer.Clear();
                //Event.ResetPool();  // Can't call this here because there are active event pool lists in use by the enclosing Campfire code
                CookingRecipe selectedRecipe = recipeList[selectedRecipeIndex].Item2;

                //TODO: HANDLE 0 RECIPES (because user deleted them all)

                //Draw main box
                ScrapBuffer.TitledBox("Recipes");
                ScrapBuffer.SingleBoxHorizontalDivider(14);
                ScrapBuffer.EscOr5ToExit();
                //Help text
                ScrapBuffer.Write(2, 0, " {{W|2}} or {{W|8}} to scroll ");
                ScrapBuffer.Write(2, 24, " {{W|Space}}/{{W|Enter}} - Cook ");
                ScrapBuffer.Write(45, 24, " {{W|F}} - Favorite ");
                ScrapBuffer.Write(62, 24, " {{W|D}}/{{W|Del}} - Forget ");

                //Draw scrollable recipe list
                for (int drawIndex = scrollOffset; drawIndex < recipeList.Count && drawIndex - scrollOffset < scrollAreaHeight; drawIndex++)
                {
                    CookingRecipe recipe = recipeList[drawIndex].Item2;
                    string        name   = ColorUtility.StripFormatting(recipe.GetDisplayName());
                    if (name.Length > 74)
                    {
                        name = name.Substring(0, 71) + "...";
                    }
                    name = (recipe.CheckIngredients() ? "{{W|" + name + "}}" : "{{K|" + name + "}}");
                    name = (recipe.Favorite ? "{{R|\u0003" + name + "}}" : name);
                    int xPos = recipe.Favorite ? 4 : 5;
                    int yPos = 2 + (drawIndex - scrollOffset);

                    ScrapBuffer.Write(xPos, yPos, name);

                    if (drawIndex == selectedRecipeIndex)
                    {
                        ScrapBuffer.Write(2, yPos, "{{Y|>}}");
                    }
                }

                //Draw ingredients
                int bottomPaneTextStartPos = 2;
                int maxBottomPaneWidth     = 76;
                int ingredientPaneStartRow = 15;
                int ingredientPaneHeight   = 2;
                ScrapBuffer.Goto(bottomPaneTextStartPos, ingredientPaneStartRow);
                List <string> ingredients = StringFormat.ClipTextToArray(selectedRecipe.GetBriefIngredientList(), maxBottomPaneWidth);
                for (int i = 0; i < ingredients.Count && i < ingredientPaneHeight; i++)
                {
                    ScrapBuffer.WriteLine(ingredients[i]);
                }

                //Draw recipe effect description
                int           recipeDescriptionPaneStartRow = 18;
                int           recipeDescriptionPaneHeight   = 6;
                List <string> description = StringFormat.ClipTextToArray(selectedRecipe.GetDescription(), maxBottomPaneWidth, KeepNewlines: true);
                if (description.Count > 6)
                {
                    //This should be extremely rare - but if some single effects are longer than 2 lines for instance, this removes
                    //line breaks to condense the effect description and ensure it can fit on 6 lines total.
                    description = StringFormat.ClipTextToArray(selectedRecipe.GetDescription(), maxBottomPaneWidth, KeepNewlines: false);
                }
                ScrapBuffer.Goto(bottomPaneTextStartPos, recipeDescriptionPaneStartRow);
                for (int i = 0; i < description.Count && i < recipeDescriptionPaneHeight; i++)
                {
                    ScrapBuffer.WriteLine(description[i]);
                }

                //Draw the screen
                Console.DrawBuffer(ScrapBuffer);

                //Respond to keyboard input
                keys = Keyboard.getvk(Options.MapDirectionsToKeypad);

                if (keys == Keys.Escape || keys == Keys.NumPad5)
                {
                    screenResult   = -1;                   //canceled
                    shouldExitMenu = true;
                }
                if (keys == Keys.NumPad8)
                {
                    if (selectedRecipeIndex == scrollOffset)
                    {
                        if (scrollOffset > 0)
                        {
                            scrollOffset--;
                            selectedRecipeIndex--;
                        }
                    }
                    else if (selectedRecipeIndex > 0)
                    {
                        selectedRecipeIndex--;
                    }
                }
                if (keys == Keys.NumPad2)
                {
                    int maxIndex = recipeList.Count - 1;
                    if (selectedRecipeIndex < maxIndex)
                    {
                        selectedRecipeIndex++;
                    }
                    if (selectedRecipeIndex - scrollOffset >= scrollAreaHeight)
                    {
                        scrollOffset++;
                    }
                }
                if (keys == Keys.Prior)                 //PgUp
                {
                    selectedRecipeIndex = ((selectedRecipeIndex != scrollOffset) ? scrollOffset : (scrollOffset = Math.Max(scrollOffset - (scrollAreaHeight - 1), 0)));
                }
                if (keys == Keys.Next)                 //PgDn
                {
                    if (selectedRecipeIndex != scrollOffset + (scrollAreaHeight - 1))
                    {
                        selectedRecipeIndex = scrollOffset + (scrollAreaHeight - 1);
                    }
                    else
                    {
                        int advancementDistance = scrollAreaHeight - 1;
                        selectedRecipeIndex += advancementDistance;
                        scrollOffset        += advancementDistance;
                    }
                    selectedRecipeIndex = Math.Min(selectedRecipeIndex, recipeList.Count - 1);
                    scrollOffset        = Math.Min(scrollOffset, recipeList.Count - 1);
                }
                if (keys == Keys.F)
                {
                    selectedRecipe.Favorite = !selectedRecipe.Favorite;
                    recipeList.Sort(RecipeComparator);
                    if (selectedRecipe.Favorite)
                    {
                        //if this was just marked as a favorite, update selection index to continue to point to it where it was moved
                        for (int i = 0; i < recipeList.Count; i++)
                        {
                            if (recipeList[i].Item2 == selectedRecipe)
                            {
                                selectedRecipeIndex = i;
                                //scroll the selection back into view if needed
                                if (selectedRecipeIndex < scrollOffset || selectedRecipeIndex >= (scrollOffset + scrollAreaHeight))
                                {
                                    scrollOffset = Math.Max(0, selectedRecipeIndex - (scrollAreaHeight / 2));
                                }
                            }
                        }
                    }
                }
                if (keys == Keys.D || keys == Keys.Delete)
                {
                    if (Popup.ShowYesNo("{{y|Are you sure you want to forget your recipe for }}" + selectedRecipe.GetDisplayName() + "{{y|?}}") == DialogResult.Yes)
                    {
                        selectedRecipe.Hidden = true;
                        for (int i = 0; i < recipeList.Count; i++)
                        {
                            if (recipeList[i].Item2 == selectedRecipe)
                            {
                                recipeList.RemoveAt(i);
                                break;
                            }
                        }
                        selectedRecipeIndex = Math.Min(selectedRecipeIndex, recipeList.Count - 1);
                        scrollOffset        = Math.Min(scrollOffset, recipeList.Count - 1);
                    }
                }
                if (keys == Keys.Space || keys == Keys.Enter)
                {
                    if (!selectedRecipe.CheckIngredients())
                    {
                        List <ICookingRecipeComponent> missingComponents = selectedRecipe.Components.Where(c => !c.doesPlayerHaveEnough()).ToList();
                        string message = "{{y|You don't have enough servings of }}";
                        int    idx     = 0;
                        foreach (ICookingRecipeComponent component in missingComponents)
                        {
                            message += component.GetComponentSimpleName().PrependListElementJoinString(idx++, missingComponents.Count, "or");
                        }
                        message += "{{y| to cook }}" + selectedRecipe.GetDisplayName() + "{{y|.}}";
                        Popup.Show(message, LogMessage: false);
                        continue;
                    }
                    else if (Popup.ShowYesNo("Cook " + selectedRecipe.GetDisplayName() + "&y?") == DialogResult.Yes)
                    {
                        screenResult   = selectedRecipeIndex;
                        shouldExitMenu = true;
                    }
                }
            }

            //Screen exit
            Console.DrawBuffer(cachedScrapBuffer);
            GameManager.Instance.PopGameView(true);
            return(ScreenReturn.Exit);
        }
Example #2
0
            /// <summary>
            /// Converts a description string into a list of lines that can be written to the Console
            /// UI. Also does a few special things:
            ///  * Adds a vertical line (|) to the beginning of each line, which connects to form a
            ///    visual separator between the ability list and the descriptions written to the screen
            ///  * Deletes lines or phrases that were manually marked in AbilityExtenderData.xml for
            ///    deletion (typically because they either aren't relevant to the activated ability,
            ///    or because the description would otherwise be too long to fit on screen)
            /// </summary>
            public static List <string> SpecialFormatDescription(string description, string lineDeletionClues = null, string phraseDeletionClues = null, ActivatedAbilityEntry SourceAbility = null)
            {
                if (string.IsNullOrEmpty(description))
                {
                    if (SourceAbility != null)
                    {
                        LogUnique($"(FYI) Could not find a description for activated ability '{SimplifiedAbilityName(SourceAbility.DisplayName)}'."
                                  + " A description won't be shown on the Manage Abilities screen.");
                    }
                    return(new List <string>());
                }
                if (!string.IsNullOrEmpty(lineDeletionClues) || !string.IsNullOrEmpty(phraseDeletionClues) || description.Contains(" reputation "))
                {
                    string cleansedDescription = string.Empty;
                    foreach (string _line in description.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
                    {
                        string line             = _line;
                        bool   shouldDeleteLine = false;
                        //remove any custom lines from the description that were configured in AbilityExtenderData.xml
                        if (!string.IsNullOrEmpty(lineDeletionClues))
                        {
                            foreach (string deletionClue in lineDeletionClues.Split('~'))
                            {
                                if (line.StartsWith(deletionClue))
                                {
                                    shouldDeleteLine = true;
                                    break;
                                }
                            }
                        }
                        //remove any custom phrases from the description that were configured in AbilityExtenderData.xml
                        if (!string.IsNullOrEmpty(phraseDeletionClues))
                        {
                            foreach (string deletionClue in phraseDeletionClues.Split('~'))
                            {
                                if (line.Contains(deletionClue))
                                {
                                    line = line.Replace(deletionClue, "");
                                }
                            }
                        }
                        //remove reputation lines, because they aren't relevant to activated ability descriptions
                        if (!shouldDeleteLine && line.Contains(" reputation "))
                        {
                            if (line[0] == '+' || line[0] == '-')
                            {
                                string[] words = line.Split(' ');
                                if (words.Length >= 2 && words[1] == "reputation")
                                {
                                    shouldDeleteLine = true;
                                }
                            }
                        }
                        if (shouldDeleteLine == false)
                        {
                            cleansedDescription += (string.IsNullOrEmpty(cleansedDescription) ? "" : "\n") + line;
                        }
                    }
                    description = cleansedDescription;
                }

                List <string> descriptionLines = StringFormat.ClipTextToArray(description, MaxWidth: 32, KeepNewlines: true);

                if (descriptionLines.Count > 22)
                {
                    LogUnique($"(Warning) Part of the activated ability description for '{SimplifiedAbilityName(SourceAbility?.DisplayName)}'"
                              + " was discarded because it didn't fit on the Manage Abilities screen.");
                    descriptionLines = descriptionLines.GetRange(0, 22);
                }
                bool foundTextEnd = false;

                for (int i = descriptionLines.Count - 1; i >= 0; i--)
                {
                    if (!foundTextEnd) //get rid of any blank lines at the end
                    {
                        if (ColorUtility.StripFormatting(descriptionLines[i]).Trim().Length < 1)
                        {
                            descriptionLines.RemoveAt(i);
                            continue;
                        }
                        else
                        {
                            foundTextEnd = true;
                        }
                    }
                    descriptionLines[i] = "{{K|\u00b3}}" + descriptionLines[i];
                    int length    = ColorUtility.StripFormatting(descriptionLines[i]).Length;
                    int padNeeded = 34 - length;
                    if (padNeeded > 0)
                    {
                        descriptionLines[i] = descriptionLines[i] + "{{y|" + string.Empty.PadRight(padNeeded) + "}}";
                    }
                }
                return(descriptionLines);
            }
Example #3
0
        /// <summary>
        /// Our main menu screen method. Draws the ingredient selection screen and handles related functions.
        /// </summary>
        /// <remarks>
        /// This (and several supporting methods) are static just for simplicity's sake, because it
        /// is easier to call from a Harmony patch when it's static. If we were implementing this
        /// directly, we wouldn't make this static.
        /// </remarks>
        public static ScreenReturn Show(List <GameObject> ingredients, List <bool> isIngredientSelected)
        {
            if (ingredients == null || ingredients.Count <= 0 || isIngredientSelected == null || isIngredientSelected.Count != ingredients.Count)
            {
                return(ScreenReturn.Exit);
            }

            GameManager.Instance.PushGameView("QudUX:CookIngredients");
            ScreenBuffer cachedScrapBuffer = ScreenBuffer.GetScrapBuffer2(true);
            Keys         keys                    = Keys.None;
            bool         shouldExitMenu          = false;
            int          scrollOffset            = 0;
            int          selectedIngredientIndex = 0;
            int          scrollAreaHeight        = 14;
            int          amountColumnPos         = 43;

            //Determine number of ingredients player is allowed to use
            int allowedIngredientCount = 2;

            if (IComponent <GameObject> .ThePlayer.HasSkill("CookingAndGathering_Spicer"))
            {
                allowedIngredientCount++;
            }

            //Gather ingredient display details
            List <IngredientScreenInfo> ingredientOptions = GetIngredientScreenInfo(ingredients, isIngredientSelected);

            while (!shouldExitMenu)
            {
                ScrapBuffer.Clear();
                //Event.ResetPool();  // Can't call this here because there are active event pool lists in use by the enclosing Campfire code
                int selectedIngredientCount = ingredientOptions.Where(io => io.IsSelected == true).Count();

                //Draw main box
                ScrapBuffer.TitledBox("Ingredients");

                //Draw bottom box with selected ingredients
                ScrapBuffer.SingleBoxHorizontalDivider(17);
                int row = 18;
                foreach (IngredientScreenInfo info in ingredientOptions.Where(io => io.IsSelected == true))
                {
                    ScrapBuffer.Write(2, row++, info.OptionName);
                    ScrapBuffer.Write(5, row++, info.CookEffect);
                    if (row > 23)
                    {
                        break;
                    }
                }

                //Draw ingredient list
                if (ingredientOptions.Count == 0)
                {
                    ScrapBuffer.Write(4, 3, "You don't have any ingredients.");
                }
                else
                {
                    for (int drawIndex = scrollOffset; drawIndex < ingredientOptions.Count && drawIndex - scrollOffset < scrollAreaHeight; drawIndex++)
                    {
                        int yPos = 2 + (drawIndex - scrollOffset);
                        ScrapBuffer.Goto(4, yPos);
                        if (string.IsNullOrEmpty(ingredientOptions[drawIndex].OptionName))
                        {
                            ScrapBuffer.Write("&k<Error: unknown ingredient>&y");
                        }
                        else
                        {
                            string option = ingredientOptions[drawIndex].GetCheckboxString();
                            ScrapBuffer.Write(option);
                            if (ConsoleLib.Console.ColorUtility.LengthExceptFormatting(option) > 39)
                            {
                                ScrapBuffer.Write(40, yPos, "{{y|...             }}");
                            }
                        }

                        ScrapBuffer.Goto(amountColumnPos, 2 + (drawIndex - scrollOffset));
                        if (drawIndex == selectedIngredientIndex)
                        {
                            ScrapBuffer.Write("{{^K|" + ingredientOptions[drawIndex].UseCount + "}}");
                        }
                        else
                        {
                            ScrapBuffer.Write(ingredientOptions[drawIndex].UseCount);
                        }

                        //Draw selection caret at current index
                        if (drawIndex == selectedIngredientIndex)
                        {
                            ScrapBuffer.Goto(2, 2 + (drawIndex - scrollOffset));
                            ScrapBuffer.Write("{{Y|>}}");
                        }
                    }
                }

                //Help text on bottom of screen
                ScrapBuffer.Write(2, 24, " {{W|Space{{y|/}}Enter}}{{y| - Select}} ");
                ScrapBuffer.Write(46, 24, " {{W|C{{y|/}}Ctrl+Space{{y|/}}Ctrl+Enter}}{{y| - Cook}} ");

                //Infobox on right-hand side of screen
                ScrapBuffer.SingleBox(56, 0, 79, 17, ConsoleLib.Console.ColorUtility.MakeColor(TextColor.Grey, TextColor.Black));
                ScrapBuffer.Fill(57, 1, 78, 16, ' ', ConsoleLib.Console.ColorUtility.MakeColor(TextColor.Black, TextColor.Black));
                //Fix box intersections
                ScrapBuffer.Goto(56, 17);
                ScrapBuffer.Write(193);
                ScrapBuffer.Goto(56, 0);
                ScrapBuffer.Write(194);
                ScrapBuffer.Goto(79, 17);
                ScrapBuffer.Write(180);

                //Help text at top of screen
                ScrapBuffer.Write(2, 0, "{{y| {{W|2}} or {{W|8}} to scroll }}");
                ScrapBuffer.EscOr5ToExit();

                //Write description to infobox for currently highlighted ingredient
                string   highlightDescription      = ingredientOptions[selectedIngredientIndex].CookEffect;
                string[] linedHighlightDescription = StringFormat.ClipTextToArray(highlightDescription, 20).ToArray();
                ScrapBuffer.Goto(58, 2);
                ScrapBuffer.WriteBlockWithNewlines(linedHighlightDescription, 14);

                //Draw the screen
                Console.DrawBuffer(ScrapBuffer);

                //Respond to keyboard input
                keys = Keyboard.getvk(Options.MapDirectionsToKeypad);

                if (keys == Keys.Escape || keys == Keys.NumPad5)
                {
                    //clear out the boolean list, since our current Harmony setup uses that as a method
                    //to determine whether anything was selected from this menu
                    for (int i = 0; i < isIngredientSelected.Count(); i++)
                    {
                        isIngredientSelected[i] = false;
                    }
                    shouldExitMenu = true;
                }
                if (keys == Keys.NumPad8)
                {
                    if (selectedIngredientIndex == scrollOffset)
                    {
                        if (scrollOffset > 0)
                        {
                            scrollOffset--;
                            selectedIngredientIndex--;
                        }
                    }
                    else if (selectedIngredientIndex > 0)
                    {
                        selectedIngredientIndex--;
                    }
                }
                if (keys == Keys.NumPad2)
                {
                    int maxIndex = ingredientOptions.Count - 1;
                    if (selectedIngredientIndex < maxIndex)
                    {
                        selectedIngredientIndex++;
                    }
                    if (selectedIngredientIndex - scrollOffset >= scrollAreaHeight)
                    {
                        scrollOffset++;
                    }
                }
                if (keys == Keys.Prior)                 //PgUp
                {
                    selectedIngredientIndex = ((selectedIngredientIndex != scrollOffset) ? scrollOffset : (scrollOffset = Math.Max(scrollOffset - (scrollAreaHeight - 1), 0)));
                }
                if (keys == Keys.Next)                 //PgDn
                {
                    if (selectedIngredientIndex != scrollOffset + (scrollAreaHeight - 1))
                    {
                        selectedIngredientIndex = scrollOffset + (scrollAreaHeight - 1);
                    }
                    else
                    {
                        int advancementDistance = scrollAreaHeight - 1;
                        selectedIngredientIndex += advancementDistance;
                        scrollOffset            += advancementDistance;
                    }
                    selectedIngredientIndex = Math.Min(selectedIngredientIndex, ingredientOptions.Count - 1);
                    scrollOffset            = Math.Min(scrollOffset, ingredientOptions.Count - 1);
                }
                if (keys == Keys.C || keys == (Keys.Control | Keys.Enter) || keys == (Keys.Control | Keys.Space))
                {
                    if (selectedIngredientCount > 0)
                    {
                        shouldExitMenu = true;
                    }
                    else
                    {
                        Popup.Show("You haven't selected any ingredients to cook with.", LogMessage: false);
                    }
                }
                if (keys == Keys.Space || keys == Keys.Enter)
                {
                    if (ingredientOptions[selectedIngredientIndex].IsSelected == true)
                    {
                        ingredientOptions[selectedIngredientIndex].IsSelected = false;
                    }
                    else
                    {
                        if (selectedIngredientCount >= allowedIngredientCount)
                        {
                            Popup.Show("You can't select more than " + selectedIngredientCount + " ingredients.", LogMessage: false);
                        }
                        else
                        {
                            ingredientOptions[selectedIngredientIndex].IsSelected = true;
                        }
                    }
                }
                if (keys == Keys.NumPad6)
                {
                    if (ingredientOptions[selectedIngredientIndex].IsSelected == false)
                    {
                        if (selectedIngredientCount >= allowedIngredientCount)
                        {
                            Popup.Show("You can't select more than " + selectedIngredientCount + " ingredients.", LogMessage: false);
                        }
                        else
                        {
                            ingredientOptions[selectedIngredientIndex].IsSelected = true;
                        }
                    }
                }
                if (keys == Keys.NumPad4)
                {
                    if (ingredientOptions[selectedIngredientIndex].IsSelected == true)
                    {
                        ingredientOptions[selectedIngredientIndex].IsSelected = false;
                    }
                }
            }

            //Screen exit
            Console.DrawBuffer(cachedScrapBuffer);
            GameManager.Instance.PopGameView(true);
            return(ScreenReturn.Exit);
        }