using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Revitalize.Framework.Menus.MenuComponents; using Revitalize.Framework.Objects.Machines; using StardewValley; using StardewValley.Menus; using StardustCore.UIUtilities; using StardustCore.UIUtilities.MenuComponents.ComponentsV2.Buttons; namespace Revitalize.Framework.Menus { /// /// A simple menu for displaying craftable objects. /// public class CraftingMenuV1 : IClickableMenuExtended { /// /// All the different pages for crafting. /// public Dictionary CraftingTabs; /// /// All of the actual buttons to display for crafting. /// public Dictionary> craftingItemsToDisplay; /// /// The inventory to tke items from. /// public IList fromInventory; /// /// The inventory to put items into. /// public IList toInventory; /// /// The current page index for the current tab. /// public int currentPageIndex; /// /// The name of the current tab. /// public string currentTab; /// /// The background color for the menu. /// public Color backgroundColor; /// /// The x offset for the menu so that tabs can be interacted with properly. /// public int xOffset = 72; /// /// Teh hover text to display. /// public string hoverText; /// /// How many crafting recipes to display at a time. /// public int amountOfRecipesToShow = 9; /// /// Is this menu the player's? /// public bool playerInventory; /// /// The crafting info menu that displays when a recipe is clicked. /// public CraftingInformationPage craftingInfo; /// /// The previous page button. /// public AnimatedButton leftButton; /// /// The next page button. /// public AnimatedButton rightButton; /// /// The search box used for looking for specific items. /// public StardewValley.Menus.TextBox searchBox; private Machine machine; /// /// The maximum amount of pages to display. /// private int maxPages { get { if (string.IsNullOrEmpty(this.currentTab)) return 0; List searchSelection; if (string.IsNullOrEmpty(this.searchBox.Text) == false) { searchSelection = this.craftingItemsToDisplay[this.currentTab].FindAll(i => i.displayItem.item.DisplayName.ToLowerInvariant().Contains(this.searchBox.Text.ToLowerInvariant())); } else { searchSelection = this.craftingItemsToDisplay[this.currentTab]; } return (int)(Math.Ceiling((double)(searchSelection.Count / this.amountOfRecipesToShow))); } } public CraftingMenuV1() : base() { } /// /// Constructor to be used when the inventory is the player's /// /// /// /// /// /// /// public CraftingMenuV1(int X, int Y, int Width, int Height, Color BackgroundColor, IList Inventory) : base(X, Y, Width, Height, false) { this.backgroundColor = BackgroundColor; this.CraftingTabs = new Dictionary(); this.craftingItemsToDisplay = new Dictionary>(); this.currentPageIndex = 0; this.fromInventory = Inventory; this.toInventory = Inventory; this.playerInventory = true; this.initializeButtons(); } /// /// Constructor to be used when inventory destination is the same and not the player. /// /// /// /// /// /// /// public CraftingMenuV1(int X, int Y, int Width, int Height, Color BackgroundColor, ref IList Inventory) : base(X, Y, Width, Height, false) { this.backgroundColor = BackgroundColor; this.CraftingTabs = new Dictionary(); this.craftingItemsToDisplay = new Dictionary>(); this.currentPageIndex = 0; this.fromInventory = Inventory; this.toInventory = Inventory; this.initializeButtons(); } /// /// Inventory constructor to be used when the input and output inventories are different. /// /// /// /// /// /// /// /// public CraftingMenuV1(int X, int Y, int Width, int Height, Color BackgroundColor, ref IList FromInventory, ref IList ToInventory,Machine Machine) : base(X, Y, Width, Height, false) { this.backgroundColor = BackgroundColor; this.CraftingTabs = new Dictionary(); this.craftingItemsToDisplay = new Dictionary>(); this.currentPageIndex = 0; this.fromInventory = FromInventory; this.toInventory = ToInventory; this.initializeButtons(); this.machine = Machine; this.playerInventory = false; } /// /// Fix the display of menu elements when the menu is resized. /// /// /// public override void gameWindowSizeChanged(Rectangle oldBounds, Rectangle newBounds) { base.gameWindowSizeChanged(oldBounds, newBounds); if (this.craftingInfo != null) { this.craftingInfo.gameWindowSizeChanged(oldBounds, newBounds); } } /// /// Initialize the buttons for the menu. /// private void initializeButtons() { this.leftButton = new AnimatedButton(new StardustCore.Animations.AnimatedSprite("Left Button", new Vector2(this.xPositionOnScreen, this.yPositionOnScreen), new StardustCore.Animations.AnimationManager(TextureManager.GetExtendedTexture(ModCore.Manifest, "InventoryMenu", "PreviousPageButton"), new StardustCore.Animations.Animation(0, 0, 32, 32)), Color.White), new Rectangle(0, 0, 32, 32), 2f); this.rightButton = new AnimatedButton(new StardustCore.Animations.AnimatedSprite("Right Button", new Vector2(this.xPositionOnScreen + this.width, this.yPositionOnScreen), new StardustCore.Animations.AnimationManager(TextureManager.GetExtendedTexture(ModCore.Manifest, "InventoryMenu", "NextPageButton"), new StardustCore.Animations.Animation(0, 0, 32, 32)), Color.White), new Rectangle(0, 0, 32, 32), 2f); this.searchBox = new TextBox((Texture2D)null, (Texture2D)null, Game1.dialogueFont, Game1.textColor); this.searchBox.X = this.xPositionOnScreen + this.width + 96; this.searchBox.Y = this.yPositionOnScreen; this.searchBox.Width = 256; this.searchBox.Height = 192; Game1.keyboardDispatcher.Subscriber = (IKeyboardSubscriber)this.searchBox; this.searchBox.Selected = false; } /// /// What happens when the menu receives a key press. /// /// public override void receiveKeyPress(Keys key) { if (this.searchBox.Selected && key != Keys.Escape) { return; } else { base.receiveKeyPress(key); } } /// /// Sorts all of the recipes for the menu. /// public void sortRecipes() { foreach (KeyValuePair> pair in this.craftingItemsToDisplay) { List copy = pair.Value.ToList(); pair.Value.Clear(); copy = copy.OrderBy(x => x.displayItem.item.DisplayName).ToList(); foreach (CraftingRecipeButton b in copy) { this.addInCraftingRecipe(b, pair.Key); } } } /// /// Adds in a new tab for the crafting recipe menu. /// /// /// public void addInCraftingPageTab(string name, AnimatedButton Button) { int count = this.CraftingTabs.Count; if (this.CraftingTabs.ContainsKey(name)) { return; } else { Vector2 newPos = new Vector2(100 + (48), this.yPositionOnScreen + (24 * 4) * (count + 1)); Button.Position = newPos; this.CraftingTabs.Add(name, Button); this.craftingItemsToDisplay.Add(name, new List()); } } /// /// Adds in a crafting recipe to the crafting menu. /// /// /// public void addInCraftingRecipe(CraftingRecipeButton Button, string WhichTab) { if (this.craftingItemsToDisplay.ContainsKey(WhichTab)) { int count = this.craftingItemsToDisplay[WhichTab].Count % this.amountOfRecipesToShow; Vector2 newPos = new Vector2(this.xPositionOnScreen + (128), (this.yPositionOnScreen + 64) + (64 * (count + 1))); Button.displayItem.Position = newPos; this.craftingItemsToDisplay[WhichTab].Add(Button); } else { throw new Exception("Tab: " + WhichTab + " doesn't exist!"); } } /// /// What happens when you hover over a menu element. /// /// /// public override void performHoverAction(int x, int y) { bool hovered = false; foreach (KeyValuePair pair in this.CraftingTabs) { if (pair.Value.containsPoint(x, y)) { this.hoverText = pair.Key; hovered = true; } } //get range of buttons to show if (string.IsNullOrEmpty(this.currentTab) == false) { List buttonsToDraw = this.getRecipeButtonsToDisplay(); foreach (CraftingRecipeButton button in buttonsToDraw) { if (button.containsPoint(x, y)) { this.hoverText = button.recipe.outputName; hovered = true; } } } if (hovered == false) { this.hoverText = ""; } } /// /// What happens when the meu receives a left click. /// /// /// /// public override void receiveLeftClick(int x, int y, bool playSound = true) { if (this.leftButton.containsPoint(x, y)) { if (this.currentPageIndex <= 0) this.currentPageIndex = 0; else { this.currentPageIndex--; Game1.playSound("shwip"); } } if (this.rightButton.containsPoint(x, y)) { if (this.currentPageIndex < this.maxPages) { this.currentPageIndex++; Game1.playSound("shwip"); } } Rectangle r = new Rectangle(this.searchBox.X, this.searchBox.Y, this.searchBox.Width, this.searchBox.Height / 2); if (r.Contains(x, y)) { this.searchBox.Update(); this.searchBox.SelectMe(); } else { this.searchBox.Selected = false; } foreach (KeyValuePair pair in this.CraftingTabs) { if (pair.Value.containsPoint(x, y)) { this.currentTab = pair.Key; this.currentPageIndex = 0; return; } } //get range of buttons to show if (string.IsNullOrEmpty(this.currentTab) == false) { List buttonsToDraw = this.getRecipeButtonsToDisplay(); foreach (CraftingRecipeButton button in buttonsToDraw) { if (button.containsPoint(x, y)) { //button.craftItem(this.fromInventory, this.toInventory); if (this.playerInventory) { this.fromInventory = Game1.player.Items; } this.craftingInfo = new CraftingInformationPage(this.xPositionOnScreen + this.width + this.xOffset, this.yPositionOnScreen, 400, this.height, this.backgroundColor, button, ref this.fromInventory,ref this.toInventory,this.playerInventory,this.machine); Game1.soundBank.PlayCue("coin"); if (this.playerInventory) { Game1.player.Items = this.toInventory; return; } //ModCore.log("Button has been clicked!"); return; } } } //ModCore.log("Menu has been clicked"); if (this.craftingInfo != null) { this.craftingInfo.receiveLeftClick(x, y); if (this.craftingInfo.doesMenuContainPoint(x, y)) return; } this.craftingInfo = null; } /// /// Draws the menu to the screen. /// /// public override void draw(SpriteBatch b) { this.drawDialogueBoxBackground(this.xPositionOnScreen + this.xOffset, this.yPositionOnScreen, this.width, this.height, this.backgroundColor); if (this.currentPageIndex > this.maxPages) this.currentPageIndex = 0; this.leftButton.draw(b); //Draw page numbers here. //b.DrawString(Game1.smallFont,"Page: "+this.currentPageIndex.ToString()/) b.DrawString(Game1.dialogueFont, ("Page: " + (this.currentPageIndex + 1) + " / " + (this.maxPages + 1)).ToString(), new Vector2(this.xPositionOnScreen + 128, this.yPositionOnScreen+32), Color.White); this.rightButton.draw(b); this.searchBox.Draw(b, true); //this.drawDialogueBoxBackground(); foreach (KeyValuePair pair in this.CraftingTabs) { pair.Value.draw(b); } if (string.IsNullOrEmpty(this.currentTab)) { if (string.IsNullOrEmpty(this.hoverText) == false) { IClickableMenuExtended.drawHoverText(b, this.hoverText, Game1.dialogueFont); } this.drawMouse(b); return; } List buttonsToDraw = this.getRecipeButtonsToDisplay(); foreach (CraftingRecipeButton button in buttonsToDraw) { if (button.recipe.CanCraft(this.fromInventory)) { button.draw(b); } else { button.draw(b, .25f); } b.DrawString(Game1.smallFont, button.displayItem.item.DisplayName, button.displayItem.Position + new Vector2(64, 0), Color.Brown); } if (this.craftingInfo != null) { this.craftingInfo.draw(b); } if (string.IsNullOrEmpty(this.hoverText) == false) { IClickableMenuExtended.drawHoverText(b, this.hoverText, Game1.dialogueFont); } this.drawMouse(b); } /// /// Gets all of the crafting buttons to display. /// /// private List getRecipeButtonsToDisplay() { List searchSelection; if (string.IsNullOrEmpty(this.searchBox.Text) == false) { searchSelection = this.craftingItemsToDisplay[this.currentTab].FindAll(i => i.displayItem.item.DisplayName.ToLowerInvariant().Contains(this.searchBox.Text.ToLowerInvariant())); } else { searchSelection = this.craftingItemsToDisplay[this.currentTab]; } searchSelection = this.searchSort(searchSelection); int amount = searchSelection.Count / this.amountOfRecipesToShow; int min = this.currentPageIndex == amount ? searchSelection.Count % this.amountOfRecipesToShow : this.amountOfRecipesToShow; List buttonsToDraw = searchSelection.GetRange(this.currentPageIndex * this.amountOfRecipesToShow, min); return buttonsToDraw; } /// /// Repositions crafting buttons based on the current sort context. /// /// /// private List searchSort(List Unsorted) { List copy = Unsorted.ToList(); //copy = copy.OrderBy(x => x.displayItem.item.DisplayName).ToList(); //Sort the recipes again. Probably unnecessary. //Do sorting; for (int i = 0; i < Unsorted.Count; i++) { int count = i % this.amountOfRecipesToShow; copy[i].displayItem.Position = new Vector2(this.xPositionOnScreen + (128), (this.yPositionOnScreen + 64) + (64 * (count + 1))); } return copy; } } }