Encounter / Assets / Scripts / GUIHandlers / TownUI.cs
TownUI.cs
Raw
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
using System.Linq;

/// <summary>
/// Primary handler for Shop functionality for the shop Encounters
/// </summary>
public class TownUI : MonoBehaviour
{
    #region Variables
    public static TownUI Instance { get; private set; }

    [Header("UI Properties")]
    [SerializeField] private Canvas shopCanvas;
    [SerializeField] private List<GameObject> memberButtons;           // References to all of the party member switch buttons on the left of the screen
    [SerializeField] private GameObject normalButton;                  // The small version of the button for enemy encounters
    [SerializeField] private GameObject itemBoxRef;                   // Prefab reference to an Item that is for sale  
    [SerializeField] private GameObject gridObject;                     // Prefab reference to the grid that the item goes into
    [SerializeField] private TextMeshProUGUI shop_Text;                 // Reference to the field that displays the shop's name
    [SerializeField] private TextMeshProUGUI gold_Text;                 // Reference to the field that displays the character's gold
    [SerializeField] private TextMeshProUGUI memberInvenText;         // Reference to the field that displays what member's inventory is being accessed
    [SerializeField] private TextMeshProUGUI shopOwnerText;           // Reference to the field that displays text the shop owner is saying
    [SerializeField] private Button rightPageButton;                  // Button reference that will be deactivated when needed, logic analyzation
    [SerializeField] private Button leftPageButton;                   // Button reference that will be deactivated when needed, logic analyzation
    [SerializeField] private Button exitButton;                        // Button for exiting the shop and recalling the original shop UI
    [SerializeField] private List<Image> memberGoldActiveImages;                 // References to all of the activated member icons on the left of the member buttons
    [SerializeField] private Transform shopInven;                      // Reference to the container of the shop's inventory
    [SerializeField] private Transform playerInven;                    // Reference to the container of the player_S's inventory
    [SerializeField] private Transform buttonField;                    // Field for the general button selection
    [SerializeField] private TextMeshProUGUI soldOutText;               // Reference to the sold out text that appears when no more stock is available for the shop

    [Header("Sleeper Components")]
    [SerializeField] private GameObject shopObject;                    // Container for the shop game object that holds the merchant's inventory
    [SerializeField] private GameObject invenObject;                   // Container for the player inventory game object that holds its own respective inventory
    [SerializeField] private GameObject buttonFieldObject;            // Container for the button field game object that blocks the inventory object

    [Header("Confirmation Components")]
    [SerializeField] private GameObject confirmObject;                 // Confirmation game object when buying or selling multiple of the same thing
    [SerializeField] private TextMeshProUGUI currentAmountText;       // Text field to indicate item Cur / item Max when confirming
    [SerializeField] private TextMeshProUGUI costField;                // Text field to indicate the cost of the items multiplied by their values or cost
    [SerializeField] private Slider amountSlider;                      // The Slider component the player will manipulate
    [SerializeField] private GameObject restConfirmObject;              // Confirmation game object for resting 
    [SerializeField] private TextMeshProUGUI restCost;                  // Reference to the cost text field in the rest confirm object

    private Shop shop;                                                  // Shop from the Encounter container
    private Dictionary<int, Dictionary<Item, int>> pageDic;            // Dictionary that retains what items are on what page
    private List<Item> discountedItems;                                 // Reference discounted items
    private Dictionary<Item, int> playerItems;                         // Reference list for selling functionality
    private int currentPage = 0;                                       // Represents what page is being shown to the player in the shop
    private List<GameObject> buttons;                                   // Represents the buttons that indicate things to do in the town
    private Inventory currentInven;
    private GameObject playerObject;
    private Player player;
    private GameObject[] allyObjects;
    private Ally[] allies;
    private List<GameObject> shopGrids;
    private List<GameObject> playerGrids;
    private Entity currentPersonInven;
    
    private Task playerConfirmation;
    private bool restIndication;
    private int itemCount;
    private int itemMax;
    private int totalCost;
    private int currentItemVC;
    private bool? confDeter;
    private bool rested;
    private bool isSelling;
    private int RestCost;
    private bool discountsApplied;
    private bool alerted;

    private const byte MaxItemsPerPage = 12;
    private const byte MaxPartyMembers = 4;
    private readonly Color DisabledColor = new Color(.65f, .65f, .65f, 1f);
    #endregion

    /// <summary>
    /// Switches on or off the shop button when the inventory is open or closed to prevent odd interactions
    /// </summary>
    /// <param name="shop">The current TownUI</param>
    public static void CheckInventoryStatus(TownUI shop)
    {
        if (Globals.InventoryOpened)    // Mark shop buttons as inaccessible
        {
            shop.buttons.ForEach(button =>
            {
                button.GetComponent<Button>().interactable = false;
                button.GetComponent<Image>().color = new Color(.65f, .65f, .65f, 1f);
            });
        }
        else                            // Mark shop buttons as accessible
        {
            for (int i = 0; i < shop.buttons.Count; ++i)
            {
                if (i is 0 && shop.rested)
                    continue;
                else
                {
                    shop.buttons[i].GetComponent<Button>().interactable = true;
                    shop.buttons[i].GetComponent<Image>().color = Color.white;
                }
            }
        }
    }
    /// <summary>
    /// Shop information from the Shop object is inserted for indication of what items can be 
    /// sold as well as the merchant information
    /// </summary>
    /// <param name="shop"></param>
    public void InsertShopInfo(Shop shop) 
        => this.shop = shop;
    private void Awake()
        => Instance = this;
    private async void OnEnable()
    {
        await LoadShop();
        // Sets the camera for the canvas as well as the overlay and layer IDs
        SetCanvasComponents();

        playerObject = GameManager.Instance.GetPlayerObject();
        player = playerObject.GetComponent<Player>();
        allyObjects = GameManager.Instance.GetAllyObjects();
        allies = new Ally[allyObjects.Length];
        for (int i = 0; i < allyObjects.Length; i++)
            allies[i] = allyObjects[i].GetComponent<Ally>();

        GeneralUI.Instance.UpdateGUIs(GameManager.Instance.GetAllyObjects());

        currentPersonInven = player;

        // Cost of the rest 
        RestCost = GenerateInnCost();

        FillShopInformation();
        GUIHandler();
        AbilityBrain.ShopChecks(player, allies, this);
        SleepShop();

        // Waits for the shop object to be fully created and within the UI system
        // before grabbing the information within the shop system
        async Task LoadShop()
        {
            while (shop == null)
                await Task.Yield();

            await Task.CompletedTask;
        }
        void SetCanvasComponents()
        {
            Canvas canvasComp = GetComponentInChildren<Canvas>();
            canvasComp.worldCamera = Camera.main;
            canvasComp.sortingLayerName = "UI";
        }
    }
    /// <summary>
    /// Enables the shop layout by creating two buttons to enter the shop or to leaves the encounter
    /// </summary>
    public void EnableShopLayout()
    {
        // Clears the transform to be sure no leftover children are left
        ResetUI();
        buttons = new List<GameObject>();

        const byte ButtonAmount = 3;
        for (int i = 1; i <= ButtonAmount; i++)
        {
            // Two buttons are created for entering the Shop and leaving the Encounter
            GameObject buttonRef = Instantiate(normalButton, buttonField);
            TextMeshProUGUI retainer = buttonRef.GetComponentInChildren<TextMeshProUGUI>();
            buttons.Add(buttonRef);
            switch (i)
            {
                case 1:
                    retainer.text = "Rest at Inn";
                    buttonRef.GetComponent<Button>().onClick.AddListener(() =>
                    {
                        InitializeRestConfirmationObject();
                    });

                    if (rested)
                    {
                        buttonRef.GetComponent<Button>().interactable = false;
                        buttonRef.GetComponent<Image>().color = DisabledColor;
                    }

                    break;
                case 2:
                    retainer.text = "Shop";
                    buttonRef.GetComponent<Button>().onClick.AddListener(() =>
                    {
                        ActivateShop();
                    });
                    break;
                case 3:
                    retainer.text = "Leave";
                    buttonRef.GetComponent<Button>().onClick.AddListener(() =>
                    {
                        GameManager.Instance.EndEncounter(player, allies);
                    });
                    break;
            }
        }
    }
    private void BountyHunterFunction()
    {
        if (GameManager.Instance.GetEncounterValue() is not 1)
        {
            if (player.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[70]))
            {
                Ability abRef = player.GetInventory().Abilities.Find(ability => ability.AbilityID is 70);
                
                if (abRef.ReferenceObject is null)
                {
                    GameObject bountyBoard = Resources.Load<GameObject>("Prefabs/Special Prefabs/Bounty_Board");
                    GameObject instancedBoard = Instantiate(bountyBoard, transform.GetChild(0));
                    instancedBoard.GetComponent<Bounty>().InjectBounties();
                    return;
                }

                TakenBounty bountyLogic = (TakenBounty)abRef.ReferenceObject;

                if (bountyLogic.HasBeenKilled)
                {
                    if (abRef.ReferenceObject is not null)
                    {
                        int goldAmount = bountyLogic.GoldReward;
                        player.GetInventory().AddGold(goldAmount);
                    }

                    GameObject bountyBoard = Resources.Load<GameObject>("Prefabs/Special Prefabs/Bounty_Board");
                    GameObject instancedBoard = Instantiate(bountyBoard, transform.GetChild(0));
                    instancedBoard.GetComponent<Bounty>().InjectBounties();
                }
            }
        }
    }
    /// <summary>
    /// Fills in the shop's merchant information as well as the inventory information from the Shop object
    /// </summary>
    private void FillShopInformation()
    {
        string user = currentPersonInven.GetName();
        shop_Text.text = shop.ShopName;
        gold_Text.text = "GOLD:" + player.GetInventory().GetGold().ToString("000000");
        memberInvenText.text = $"{user}'s Inventory";
        shopOwnerText.text = "Welcome to my Shop! Please look around!";

        // Gathers all items that are available within the shop
        Dictionary<Item, int> listOfStock = StockShop();

        // Seperates all of the available items onto different pages by groups of 12
        pageDic = new Dictionary<int, Dictionary<Item, int>>();
        int counter             = -1;
        int itemCounter         = 0;

        foreach (KeyValuePair<Item, int> item in listOfStock)
        {
            if (itemCounter % MaxItemsPerPage == 0)
                pageDic.Add(++counter, new Dictionary<Item, int>());

            pageDic[counter].Add(item.Key, item.Value);
            itemCounter++;
        }

        if (listOfStock.Count is 0)
            soldOutText.gameObject.SetActive(true);
        else
            soldOutText.gameObject.SetActive(false);
    }
    /// <summary>
    /// Stocks up the shop with the items and such within the Shop component itself
    /// </summary>
    /// <returns>The Complete stock of the shop</returns>
    private Dictionary<Item, int> StockShop()
    {
        Dictionary<Item, int> listOfStock = new Dictionary <Item, int>();
        foreach (KeyValuePair<Item, int> item in shop.ItemsOnSale)
        {
            if (listOfStock.ContainsKey(item.Key))
            {
                listOfStock[item.Key] += item.Value;
                continue;
            }

            listOfStock.Add(item.Key, item.Value);
        }
        foreach (KeyValuePair<Consumable, int> con in shop.ConsumablesOnSale)
        {
            if (listOfStock.ContainsKey(con.Key))
            {
                listOfStock[con.Key] += con.Value;
                continue;
            }

            listOfStock.Add(con.Key, con.Value);
        }
        foreach (KeyValuePair<Relic, int> relic in shop.RelicsOnSale)
        {
            if (listOfStock.ContainsKey(relic.Key))
            {
                listOfStock[relic.Key] += relic.Value;
                continue;
            }

            listOfStock.Add(relic.Key, relic.Value);
        }
        foreach (KeyValuePair<Weapon, int> weapon in shop.WeaponOnSale)
        {
            if (listOfStock.ContainsKey(weapon.Key))
            {
                listOfStock[weapon.Key] += weapon.Value;
                continue;
            }

            listOfStock.Add(weapon.Key, weapon.Value);
        }
        foreach (KeyValuePair<Apparel, int> apparel in shop.ApparelOnSale)
        {
            if (listOfStock.ContainsKey(apparel.Key))
            {
                listOfStock[apparel.Key] += apparel.Value;
                continue;
            }

            listOfStock.Add(apparel.Key, apparel.Value);
        }

        return listOfStock;
    }
    /// <summary>
    /// Handles creation and listeners of the GUI Buttons to determine what allies inventory to access
    /// </summary>
    private void GUIHandler()
    {
        for (int i = 0; i < MaxPartyMembers; i++)
        {
            Button b = memberButtons[i].GetComponent<Button>();
            b.interactable = true;

            if (i is 0)
            {
                memberButtons[i].GetComponentsInChildren<Image>()[1].sprite = Resources.Load<Sprite>("Sprites/PlayerGUI");
                memberGoldActiveImages[i].enabled = true;
                int tempVar = i;
                b.onClick.AddListener(() =>
                {
                    SwitchInventories(tempVar, player.GetInventory(), player);
                });
                continue;
            }

            // 0 is the Image within the primary object 1 is the Image within the child object
            try
            {
                Sprite allySprite = allies[i - 1].GetSprite();

                memberGoldActiveImages[i].enabled = false;
                memberButtons[i].GetComponentsInChildren<Image>()[0].enabled = true;
                memberButtons[i].GetComponentsInChildren<Image>()[1].enabled = true;
                memberButtons[i].GetComponentsInChildren<Image>()[1].sprite = allySprite;

                int tempVar = i;
                b.onClick.AddListener(() =>
                {
                    SwitchInventories(tempVar, allies[tempVar - 1].GetInventory(), allies[tempVar - 1]);
                });
            }
            catch
            {
                memberGoldActiveImages[i].enabled = false;
                memberButtons[i].GetComponent<Button>().interactable = false;
                memberButtons[i].GetComponentsInChildren<Image>()[0].enabled = false;
                memberButtons[i].GetComponentsInChildren<Image>()[1].enabled = false;
            }
        }
    }
    /// <summary>
    /// Fills up the player's inventory bar for selection to sell to the vendor, scrolls properly
    /// </summary>
    private void FillInventoryBar(Entity activeEntity, Dictionary<Item, int> items)
    {
        playerGrids = new List<GameObject>();

        // Retrieves all the player's inventory items
        playerItems = new Dictionary<Item, int>(items);
        currentInven = activeEntity.GetInventory();
        currentPersonInven = activeEntity;

        for (int i = 0; i < currentInven.GetInvenLimit(); i++)
        {
            GameObject grid = Instantiate(gridObject, playerInven);
            grid.GetComponent<DropBox>().DetectItemUISize(DropBox.DropLocations.ShopInventory);
            playerGrids.Add(grid);
        }

        int counter = 0;
        foreach (KeyValuePair<Item, int> item in playerItems)
        {
            // Skips unsellable items
            if (item.Key.CantBeSold)
                continue;

            GameObject itemCon = Instantiate(itemBoxRef, playerGrids[counter++].transform);
            itemCon.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.InventoryInShop;
            ExtractItemInfo(item.Key, item.Value, itemCon, true);
            
            AspectHelperManager ahm = itemCon.GetComponent<AspectHelperManager>();
            ahm.InjectTransform(shopCanvas.transform);
            ahm.InjectAspect(item.Key);
            ahm.InjectOffset(new Vector2(4.25f, -1.55f));
        }
    }
    /// <summary>
    /// Updates the shop information after the player buys from the vendor or sells to the vender
    /// </summary>
    private void UpdateShopInformation()
    {
        // Destroys all of the Shop Items that are currently on the page before resetting the item information
        foreach (Transform child in shopInven)
            Destroy(child.gameObject);

        FillShopInformation();

        ResetPlayerBar(currentPersonInven, currentInven.GetAllItems());
        EnablePage();
    }
    /// <summary>
    /// The page indicated by the current page marker is activated and shows all items represented by the 
    /// dictionary marker correlated to the current page
    /// </summary>
    private void EnablePage()
    {
        if (soldOutText.gameObject.activeSelf)
            return;

        shopGrids = new List<GameObject>();

        foreach (KeyValuePair<Item, int> pair in pageDic[currentPage])
        {
            GameObject grid = Instantiate(gridObject, shopInven);
            grid.GetComponent<DropBox>().DetectItemUISize(DropBox.DropLocations.ShopStock);
            shopGrids.Add(grid);
            GameObject itemCon = Instantiate(itemBoxRef, grid.transform);
            itemCon.GetComponent<DraggableItem>().Type = DraggableItem.DraggableItemType.ShopStock;
            ExtractItemInfo(pair.Key, pair.Value, itemCon);
            
            AspectHelperManager ahm = itemCon.GetComponent<AspectHelperManager>();
            ahm.InjectTransform(shopCanvas.transform);
            ahm.InjectAspect(pair.Key);
            ahm.InjectOffset(new Vector2(-4.25f, -1.55f));
        }
    }
    /// <summary>
    /// Changes the pages of the shop by either incrementing or decrementing the current page
    /// If the current page goes below the restrictive page values than resets to either the lowest
    /// page or highest page respectively
    /// </summary>
    /// <param name="value">Indicator for if the page is being incremented or decremented</param>
    public void ChangePages(int value)
    {
        // Destroys all of the Shop Items that are currently on the page before changing page
        foreach (Transform child in shopInven)
            Destroy(child.gameObject);

        // If the value from the button was 1
        if (value > 0)
        {
            if (currentPage + 1 > pageDic.Count - 1)
                currentPage = 0;
            else
                currentPage += 1;
        }
        // If the value from the button was -1
        else
        {
            if (currentPage - 1 < 0)
                currentPage = pageDic.Count - 1;
            else
                currentPage -= 1;
        }

        EnablePage();
    }
    /// <summary>
    /// Translates the Item object to the ItemGUI UI object
    /// </summary>
    /// <param name="item">Item to translate</param>
    /// <param name="itemCon">The ItemGUI container</param>
    /// <param name="playerBar">If the object is in the player inventory bar transform</param>
    private void ExtractItemInfo(Item item, int amount, GameObject itemCon, bool playerBar = false)
    {
        ItemGUI comp = itemCon.GetComponent<ItemGUI>();
        comp.InjectItemInformation(item, amount);

        if (playerBar)
            comp.IndicateNoNameLargeSpriteWithValue();
        else
            comp.IndicateNoNameLargeSpriteWithCost();
    }
    /// <summary>
    /// Sells the selected item to the vendor for the item's selling value
    /// </summary>
    /// <param name="itemName">Name of the item to be sold</param>
    public async void SellToVendor(string itemName)
    {
        Dictionary<Item, int> items = playerItems;

        // TODO --> Possibility of implementation for vendor to sell back items?
        confDeter = null;
        foreach (KeyValuePair<Item, int> item in items)
        {
            // Once the item is found, adds the item value to the player's gold than removes it
            // Then updates shop information for the player's gold amount
            if (itemName.Equals(item.Key.ItemName))
            {
                if (item.Value > 1)
                {
                    ConfirmationOfAmount(item.Key, item.Value, true);
                    while (playerConfirmation is null)
                        await Task.Yield();
                    if (confDeter is false)
                        return;
                }

                int cost = confDeter is null ? item.Key.ItemValue * item.Value : totalCost;
                player.GetInventory().AddGold(cost);

                int amount = confDeter is null ? 1 : itemCount;
                SwitchPlayerToShop(item, amount);

                if (playerItems[item.Key] - amount == 0)
                    playerItems.Remove(item.Key);

                UpdateShopInformation();
                break;
            }
        }
    }
    /// <summary>
    /// Switches designated item and amount to shop inventory from the player inventory,
    /// also switches off the inventory active nature of items that are active and sold
    /// </summary>
    /// <param name="item">The item to add to the shop and remove from the player</param>
    /// <param name="amount">The amount of the object desired to sell to shop</param>
    private void SwitchPlayerToShop(KeyValuePair<Item, int> item, int amount)
    {
        if (item.Key is Weapon)
        {
            if (item.Key == currentInven.GetPrimaryActiveWeapon())
                currentInven.SetPrimaryActiveWeapon(null);
            else if (item.Key == currentInven.GetSecondaryActiveWeapon())
                currentInven.SetSecondaryActiveWeapon(null);

            currentInven.Remove(item.Key as Weapon, amount);
            shop.Add(item.Key as Weapon, amount);
        }
        else if (item.Key is Consumable)
        {
            currentInven.Remove(item.Key as Consumable, amount);
            shop.Add(item.Key as Consumable, amount);
        }
        else if (item.Key is Apparel app)
        {
            if (currentInven.GetActiveApparelLocations().ContainsValue(app))
                currentInven.SetActiveApparelAtLocation(null, app.ApparelLocation);

            currentInven.Remove(item.Key as Apparel, amount);
            shop.Add(item.Key as Apparel, amount);
        }
        else if (item.Key is Relic)
        {
            if (item.Key == currentInven.GetActiveRelic())
                currentInven.SetActiveRelic(null);

            currentInven.Remove(item.Key as Relic, amount);
            shop.Add(item.Key as Relic, amount);
        }
        else
        {
            currentInven.Remove(item.Key, amount);
            shop.Add(item.Key, amount);
        }
    }
    /// <summary>
    /// Sells the selected item to the player for the item's cost and takes the necessary gold
    /// If the gold is unavailable the item will not be given
    /// </summary>
    /// <param name="itemName">Name of the item to be sold</param>
    public async void SellToPlayer(string itemName)
    {
        if (currentInven.GetInvenCount() + 1 > currentInven.GetInvenLimit())
            return;

        Dictionary<Item, int> items = shop.GetAll();

        confDeter = null;
        foreach (KeyValuePair<Item, int> item in items)
        {
            // Checks for the correct item and also makes sure that the player's gold is able to purchase the item
            if (itemName.Equals(item.Key.ItemName))
            {
                if (item.Key.ItemCost > player.GetInventory().GetGold())
                    return;

                if (item.Value > 1)
                {
                    ConfirmationOfAmount(item.Key, item.Value, false);
                    
                    while (playerConfirmation is null)
                        await Task.Yield();

                    if (confDeter is false)
                        return;
                }

                int cost = confDeter is null ? item.Key.ItemCost : totalCost;
                player.GetInventory().RemoveGold(cost);

                int amount = confDeter is null ? 1 : itemCount;
                SwitchShopToPlayer(item, amount);

                if (!playerItems.ContainsKey(item.Key))
                    playerItems.Add(item.Key, amount);
                else
                    playerItems[item.Key] += amount;

                UpdateShopInformation();
                break;
            }
        }

        // False Idol Relic Flag
        if (Globals.RelicFlags[1])
        {
            if (!alerted)
            {
                foreach (KeyValuePair<Item, int> item in items)
                    item.Key.ImplementPriceSurge(.25f);

                alerted = true;
            }
        }
    }
    /// <summary>
    /// Adds the item to the player's inventory and removes it from the shop's inventyory
    /// </summary>
    /// <param name="item">The item to switch to the player's inventory and remove from the shop</param>
    /// <param name="amount">The amount of the item to remove from the shop and give to the player</param>
    private void SwitchShopToPlayer(KeyValuePair<Item, int> item, int amount)
    {
        if (item.Key is Weapon)
        {
            currentInven.Add(item.Key as Weapon, amount);
            shop.Remove(item.Key as Weapon, amount);
        }
        else if (item.Key is Consumable)
        {
            currentInven.Add(item.Key as Consumable, amount);
            shop.Remove(item.Key as Consumable, amount);
        }
        else if (item.Key is Apparel)
        {
            currentInven.Add(item.Key as Apparel, amount);
            shop.Remove(item.Key as Apparel, amount);
        }
        else if (item.Key is Relic)
        {
            currentInven.Add(item.Key as Relic, 1);
            shop.Remove(item.Key as Relic, amount);
        }
        else
        {
            currentInven.Add(item.Key, amount);
            shop.Remove(item.Key, amount);
        }
    }
    /// <summary>
    /// Calls the confirmation canvas object for the player to take an amount of the object they want to purchase or sell if more than 1
    /// </summary>
    /// <param name="item">The item being purchased or sold</param>
    /// <param name="amount">The max amount of the item available</param>
    /// <param name="merchantState">True, If the item is being sold to the vendor or False, if to the player</param>
    private void ConfirmationOfAmount(Item item, int amount, bool merchantState)
    {
        playerConfirmation = null;
        confirmObject.SetActive(true);

        itemMax = amount;
        itemCount = 1;
        isSelling = merchantState;

        // Sets the cost/value variable to the items cost for buying from the merchant
        if (!merchantState)
        {
            confirmObject.transform.Find("Question_Text").GetComponent<TextMeshProUGUI>().text = "How many would you like to buy?";
            currentItemVC = item.ItemCost;
            totalCost = currentItemVC * itemCount;
            costField.text = $"Cost: {totalCost}";
        }
        // Sets the cost/value variable to the items value for selling to the merchant
        else
        {
            confirmObject.transform.Find("Question_Text").GetComponent<TextMeshProUGUI>().text = "How many would you like to sell?";
            currentItemVC = item.ItemValue;
            totalCost = currentItemVC * itemCount;
            costField.text = $"Value: {totalCost}";
        }

        // Default values
        amountSlider.maxValue = amount;
        amountSlider.value = itemCount;
        currentAmountText.text = $"{itemCount} / {itemMax}";
    }
    /// <summary>
    /// Slider adjustment method that adjusts the GUI objects in the confirmation canvas object
    /// </summary>
    public void AdjustValues()
    {
        itemCount = (int)amountSlider.value;
        totalCost = itemCount * currentItemVC;

        if (isSelling)
            costField.text = $"Value: {totalCost}";
        else
            costField.text = $"Cost: {totalCost}";

        currentAmountText.text = $"{itemCount} / {itemMax}";
    }
    /// <summary>
    /// Cancels the potential transaction, doesn't give the items or take the gold from the designated people
    /// </summary>
    public void Cancel()
    {
        confirmObject.SetActive(false);

        confDeter = false;
        playerConfirmation = Task.CompletedTask;
    }
    /// <summary>
    /// Confirms the transaction based off of the users value on the slider, if the gold cost exceeds player's gold than simply cancels
    /// </summary>
    public void Confirmation()
    {
        confirmObject.SetActive(false);
        bool signal = true;

        // Guard check for if the player does not have the gold for the items
        if (totalCost > player.GetInventory().GetGold() && !isSelling)
            signal = false;

        confDeter = signal;
        playerConfirmation = Task.CompletedTask;
    }
    /// <summary>
    /// Activates the shop by calling the player's inventory sell screen, the shop merchant screen, 
    /// and resets the page calls
    /// </summary>
    public void ActivateShop()
    {
        if (Globals.InventoryOpened)
            return;
        else
        {
            Globals.CloseInventory();
            GeneralUI.Instance.DeactivateInventoryButton();
        }

        AwakeShop();
        ResetUI();

        ActivateAnyDiscounts();

        currentPage = 0;
        EnablePage();
        FillInventoryBar(player, player.GetInventory().GetAllItems());
        buttonFieldObject.SetActive(false);
    }
    /// <summary>
    /// Activates any discounts based on a random value and the player's abilities
    /// </summary>
    private void ActivateAnyDiscounts()
    {
        discountedItems ??= new List<Item>();

        // Makes sure that the 
        if (!discountsApplied)
        {
            Dictionary<int, Ability> abList = AbilityBrain.GetAbilityList();

            // Random discount chance
            int discountTimes = Random.Range(0, 3);

            // Extortion
            if (player.GetInventory().Abilities.Contains(abList[112]) || player.GetInventory().limitedAbilities.Contains(abList[112]))
                discountTimes++;
            
            foreach (Ally ally in allies)
            {
                if (ally.GetInventory().Abilities.Contains(abList[112]) || ally.GetInventory().limitedAbilities.Contains(abList[112]))
                    discountTimes++;
            }

            // Cycles through and gathers random items in the store to discount for each discount point the party has including potential discounts randomly generated
            for (int i = 0; i < discountTimes; ++i)
            {
                int randPage = Random.Range(0, pageDic.Count);
                Dictionary<Item, int> itemPage = pageDic[randPage];

                int itemPos = Random.Range(0, itemPage.Count);
                Item chosenItem = null;
                for (int cycle = 0; cycle <= itemPos; ++cycle)
                {
                    chosenItem = itemPage.ElementAt(cycle).Key;

                    if (cycle == itemPos)    
                        break;
                }

                if (!discountedItems.Contains(chosenItem))
                {
                    chosenItem.ImplementDiscountValue(.75f);
                    discountedItems.Add(chosenItem);
                }
                else
                    --i;
            }

            discountsApplied = true;

            // False Idol Relic Flag
            if (Globals.RelicFlags[1])
            {
                foreach (KeyValuePair<int, Dictionary<Item, int>> shopPage in pageDic)
                {
                    foreach (KeyValuePair<Item, int> shopStock in shopPage.Value)
                        shopStock.Key.ImplementDiscountValue(.99f);
                }
            }
        }
    }
    /// <summary>
    /// Deactivates the shop by clearing the stock to prevent duplication and re-enables the shop layout 
    /// for the player to choose to re-enter the shop or to leave, also sets the images for the shop to sleep
    /// </summary>
    public void DeactivateShop()
    {
        if (!Globals.InventoryOpened)
            GeneralUI.Instance.ReactivateInventoryButton();

        ClearStock();
        EnableShopLayout();
        SleepShop();
        buttonFieldObject.SetActive(true);
    }
    /// <summary>
    /// Resets the player bar when an item is sold or bought to correctly show the state in the transform
    /// </summary>
    private void ResetPlayerBar(Entity activeEntity, Dictionary<Item, int> items)
    {
        // Destroys all the old objects before reapplying the objects 
        foreach (Transform c in playerInven)
            Destroy(c.gameObject);

        FillInventoryBar(activeEntity, items);
    }
    /// <summary>
    /// Clears all of the objects in the shop inventory transform and the player inventory bar transform
    /// </summary>
    private void ClearStock()
    {
        foreach (Transform child in shopInven)
            Destroy(child.gameObject);

        foreach (Transform child in playerInven)
            Destroy(child.gameObject);
    }
    /// <summary>
    /// Sets the objects that hold the shop and inventory asleep
    /// </summary>
    private void SleepShop()
    {
        shopOwnerText.enabled = false;

        for (int i = 0; i < memberGoldActiveImages.Count; i++)
        {
            if (i is 0)
                memberGoldActiveImages[i].enabled = true;
            else
                memberGoldActiveImages[i].enabled = false;
        }

        shopObject.SetActive(false);
        invenObject.SetActive(false);

        BountyHunterFunction();
    }
    /// <summary>
    /// Sets the objects that hold the shop and player inventory awake
    /// </summary>
    private void AwakeShop()
    {
        shopOwnerText.enabled = true;

        shopObject.SetActive(true);
        invenObject.SetActive(true);
    }
    /// <summary>
    /// Clears the parent field for the player's choice buttons of any potential extra children
    /// </summary>
    public void ResetUI()
    {
        foreach (Transform child in buttonField)
            Destroy(child.gameObject);
    }
    /// <summary>
    /// Switches inventories between ally and player member inventories
    /// </summary>
    /// <param name="index">The position reference in the list to enable the member image to indicate which inventory is active</param>
    /// <param name="inventory">The inventory to retrieve all items from</param>
    /// <param name="newActiveEntity">The entity to set as the current ally</param>
    private void SwitchInventories(int index, Inventory inventory, Entity newActiveEntity)
    {
        string invenName = newActiveEntity.GetName();
        memberInvenText.text = $"{invenName}'s Inventory";

        // Simply returns if the inventory clicked on is the same as the current one being shown
        if (inventory == currentInven)
            return;

        ResetPlayerBar(newActiveEntity, inventory.GetAllItems());
        GUIHandler();

        for (int i = 0; i < MaxPartyMembers; i++)
        {
            if (index == i)
                memberGoldActiveImages[i].enabled = true;
            else
                memberGoldActiveImages[i].enabled = false;
        }
    }
    public void ModifyShopQualities(string qualifier)
    {
        // Starts at 1f and the discounts deduct 
        float discountValue = 1f;

        switch (qualifier)
        {
            case "Slick Barterer":
                discountValue -= .05f;
                break;
            default:
                Debug.LogWarning($"Ability qualifier for shop not known. Please check spelling within code to make " +
                                 $"sure correct strings are implemented --> Qualifier ({qualifier})");
                break;
        }

        for (int i = 0; i < pageDic.Count; i++)
        {
            foreach (KeyValuePair<Item, int> pair in pageDic[i])
                pair.Key.ImplementDiscountValue(discountValue);
        }
    }
    public void Rest(int RestCost)
    {
        // Make sure the player has enough gold for the rest
        if (player.GetInventory().GetGold() < RestCost)
            return;

        // Fully revitalize the player
        player.IncreaseHealth(player.RetrieveMaxHealth());
        player.IncreaseMana(player.RetrieveMaxMana());
        player.StatusChanged();

        if (allies.Length is not 0)
        {
            // Fully revitalize each ally
            foreach (Ally ally in allies)
            {
                ally.IncreaseHealth(ally.RetrieveMaxHealth());
                ally.IncreaseMana(ally.RetrieveMaxMana());
                ally.StatusChanged();
            }
        }

        // Remove the necessary gold from the player's inventory
        player.GetInventory().RemoveGold(RestCost);
        gold_Text.text = "GOLD:" + player.GetInventory().GetGold().ToString("000000");

        rested = true;

        // Deactivate the rest button since everybody is fully healed and refilled
        buttons[0].GetComponent<Button>().interactable = false;
        buttons[0].GetComponent<Image>().color = DisabledColor;
    }
    private async void InitializeRestConfirmationObject()
    {
        restCost.text = RestCost.ToString();
        restConfirmObject.SetActive(true);
        
        playerConfirmation = null;
        restIndication = false;

        while (true)
        {
            if (playerConfirmation is null)
                await Task.Yield();
            else
                break;
        }

        restConfirmObject.SetActive(false);
        if (restIndication)
            Rest(RestCost);
        else
            return;
    }
    public void ConfirmRest()
    {
        restIndication = true;
        playerConfirmation = Task.CompletedTask;
    }
    public void ConfirmNoRest()
        => playerConfirmation = Task.CompletedTask;
    private int GenerateInnCost()
    {
        int encounterValue = GameManager.Instance.GetEncounterValue();

        if (encounterValue < 10)
            return Random.Range(15, 50);
        else if (encounterValue < 20)
            return Random.Range(100, 250);
        else
            return Random.Range(150, 500);
    }
    public void AdjustInnRate(object modifier, bool isAdded)
    {
        if (modifier is int intMod)
        {
            if (isAdded)
                RestCost += intMod;
            else 
                RestCost = Mathf.Clamp(RestCost - intMod, 1, int.MaxValue);
        }
        else if (modifier is float floMod)
        {
            if (isAdded)
                RestCost += (int)Mathf.Ceil(RestCost * floMod);
            else
                RestCost = Mathf.Clamp(RestCost - (int)Mathf.Ceil(RestCost * floMod), 1, int.MaxValue);
        }
    }
}