Shop item prices updating in UI, but not in transaction

I’ve triple checked everything I could possibly think of at this point, and the referenced code matches up(to my knowledge), so let’s see if we can fix this.

When I open up any shop, all of the items and their correctly discounted prices show up. When I purchase an item with a discount, my wallet actually ends up reflecting a new balance as if I bought the item at full price. Same deal with selling; if I go to the selling menu, the properly discounted price shows up, but if I sell the item, my balance is back up to where it started as if I didn’t buy anything.

Basically, the discounts are only being reflected in the UI, and not in the actual transaction.

I am willing to share more code if needed.
Here are the scripts that I believe are in-play here:

Shop.cs:

using GameDevTV.Inventories;
using GameDevTV.Saving;
using RPG.Control;
using RPG.Inventories;
using RPG.Stats;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.Shops
{
    public class Shop : MonoBehaviour, IRaycastable, ISaveable
    {
        public event Action OnChange;

        [SerializeField] string shopName;
        [Range(0, 100)]
        [SerializeField] float sellingPercentage = 80f;
        

        [SerializeField] StockItemConfig[] stockConfig;

        Dictionary<InventoryItem, int> transaction = new Dictionary<InventoryItem, int>();
        Dictionary<InventoryItem, int> stockSold = new Dictionary<InventoryItem, int>();
        Shopper currentShopper;
        ItemCategory filter;

        bool isBuyingMode = true;

        [Serializable]
        class StockItemConfig
        {
            public InventoryItem item;
            public int initialStock;
            [Range(0, 100)]
            public float buyingDiscountPercent;
            public int levelRequiredToUnlock;
        }

        public void SetShopper(Shopper shopper)
        {
            currentShopper = shopper;
        }

        public IEnumerable<ShopItem> GetFilteredItems()
        {
            foreach (ShopItem shopItem in GetAllItems())
            {
                InventoryItem item = shopItem.GetInventoryItem();
                if (filter == ItemCategory.None || item.GetCategory() == filter)
                {
                    yield return shopItem;
                }
            }
        }
        

        public IEnumerable<ShopItem> GetAllItems()
        {
            Dictionary<InventoryItem, float> prices = GetPrices();
            Dictionary<InventoryItem, int> availabilities = GetAvailabilities();

            foreach (InventoryItem item in availabilities.Keys)
            {
                if (availabilities[item] <= 0) continue;

                float price = prices[item];
                int quantityInTransation = 0;
                transaction.TryGetValue(item, out quantityInTransation);
                int availability = availabilities[item];
                yield return new ShopItem(item, availability, price, quantityInTransation); //The ShopItem works as a middle man / interface between UI and the backend
            }
        }

        public void SelectFilter(ItemCategory category)
        {
            filter = category;
            OnChange?.Invoke();
        }

        public ItemCategory GetFilter()
        {
            return filter;
        }

        public void ConfirmTransaction()
        {
            Inventory shopperInventory = currentShopper.GetComponent<Inventory>();
            Wallet wallet = currentShopper.GetComponent<Wallet>();
            if (shopperInventory == null || wallet == null) return;

            foreach (ShopItem shopItem in GetAllItems())
            {
                InventoryItem item = shopItem.GetInventoryItem();
                int quantityInTransation = shopItem.GetQuantity();
                float price = item.GetPrice();

                for (int i = 0; i < quantityInTransation; i++) //This for loop goes through each item within the transaction and adds it one by one so non-stackables wont be stacked.
                {
                    if (isBuyingMode)
                    {
                        BuyItem(shopperInventory, wallet, item, price);
                    }
                    else
                    {
                        SellItem(shopperInventory, wallet, item, price);
                    }
                }
            }
            OnChange?.Invoke();
        }

        public void SelectMode(bool isBuying)
        {
            isBuyingMode = isBuying;
            OnChange?.Invoke();
        }

        public bool IsBuyingMode()
        {
            return isBuyingMode;
        }

        public string GetShopName()
        {
            return shopName;
        }

        public bool CanTransact()
        {
            if (IsTransactionEmpty()) return false;
            if (!HasSufficientFunds()) return false;
            if (!HasInventorySpace()) return false;

            return true;
        }

        public float TransactionTotal()
        {
            float transactionTotal = 0;

            foreach (var item in GetAllItems())
            {
                transactionTotal += item.GetPrice() * item.GetQuantity();
            }
            return transactionTotal;
        }

        public void AddToTransaction(InventoryItem item, int quantity)
        {
            
            if (!transaction.ContainsKey(item))
            {
                transaction[item] = 0;
            }

            var availabilities = GetAvailabilities();
            int availability = availabilities[item];

            if (transaction[item] + quantity > availability)
            {
                transaction[item] = availability;
            }
            else
            {
                transaction[item] += quantity;
            }

            if (transaction[item] <= 0)
            {
                transaction.Remove(item);
            }
            OnChange?.Invoke();
        }

        public CursorType GetCursorType()
        {
            return CursorType.Shop;
        }

        public bool HandleRaycast(PlayerController callingController)
        {
            if (Input.GetMouseButtonDown(0))
            {
                callingController.GetComponent<Shopper>().SetActiveShop(this);
            }
            return true;
        }
        public bool HasSufficientFunds()
        {
            if (!isBuyingMode) return true;

            Wallet playerWallet = currentShopper.GetComponent<Wallet>();
            if (playerWallet == null)
            {
                print("playerWallet is null for whatever reason");
                return false;
            }

            return playerWallet.GetBalance() >= TransactionTotal();
        }
        public bool HasInventorySpace()
        {
            if (!isBuyingMode) return true;

            Inventory playerInventory = currentShopper.GetComponent<Inventory>();
            if (playerInventory == null)
            {
                print("Playerinventory is null");
                return false;
            }

            List<InventoryItem> flatItems = new List<InventoryItem>();
            foreach (var shopItem in GetAllItems())
            {
                InventoryItem item = shopItem.GetInventoryItem();
                int quantityInTransation = shopItem.GetQuantity();
                for (int i = 0; i < quantityInTransation; i++)
                {
                    flatItems.Add(item);
                }
            }
            return playerInventory.HasSpaceFor(flatItems);
        }

        void BuyItem(Inventory shopperInventory, Wallet wallet, InventoryItem item, float price)
        {
            if (wallet.GetBalance() < price) return;
            bool success = shopperInventory.AddToFirstEmptySlot(item, 1);

            if (success)
            {
                AddToTransaction(item, -1);
                if (!stockSold.ContainsKey(item))
                {
                    stockSold[item] = 0;
                }
                stockSold[item]++;
                wallet.UpdateBalance(-price);
            }
        }

        void SellItem(Inventory shopperInventory, Wallet wallet, InventoryItem item, float price)
        {
            int slot = FindFirstItemSlot(shopperInventory, item);
            if (slot == -1) return;

            AddToTransaction(item, -1);
            shopperInventory.RemoveFromSlot(slot, 1);
            if (!stockSold.ContainsKey(item))
            {
                stockSold[item] = 0;
            }
            stockSold[item]--;
            wallet.UpdateBalance(price);
        }

        int FindFirstItemSlot(Inventory shopperInventory, InventoryItem item)
        {
            for (int i = 0; i < shopperInventory.GetSize(); i++)
            {
                if (shopperInventory.GetItemInSlot(i) == item)
                {
                    return i;
                }
            }
            return -1;
        }

        Dictionary<InventoryItem, float> GetPrices()
        {
            Dictionary<InventoryItem, float> prices = new Dictionary<InventoryItem, float>();

            foreach (var config in GetAvailableConfigs())
            {
                if (isBuyingMode)
                {
                    if (!prices.ContainsKey(config.item))
                    {
                        prices[config.item] = config.item.GetPrice();
                    }
                    prices[config.item] *= (1 - config.buyingDiscountPercent / 100);
                }
                else
                {
                    prices[config.item] = config.item.GetPrice() * (sellingPercentage / 100);
                }
            }

            return prices;
        }

        Dictionary<InventoryItem, int> GetAvailabilities()
        {
            Dictionary<InventoryItem, int> availabilities = new Dictionary<InventoryItem, int>();

            foreach (var config in GetAvailableConfigs())
            {
                if (isBuyingMode)
                {
                    if (!availabilities.ContainsKey(config.item))
                    {
                        int soldAmount = 0;
                        stockSold.TryGetValue(config.item, out soldAmount);
                        availabilities[config.item] = -soldAmount;
                    }
                    availabilities[config.item] += config.initialStock; //accumulates all availabilities for one item so that way multiple instances of an item can still be considered the same inventory item.
                }
                else
                {
                    availabilities[config.item] = CountItemsInInventory(config.item);
                }
            }

            return availabilities;
        }

        IEnumerable<StockItemConfig> GetAvailableConfigs()
        {
            int shopperLevel = GetShopperLevel();
            foreach (var config in stockConfig)
            {
                if (config.levelRequiredToUnlock > shopperLevel) continue;

                yield return config;
            }
        }

        int CountItemsInInventory(InventoryItem item)
        {
            var shopperInventory = currentShopper.GetComponent<Inventory>();
            int total = 0;
            if (shopperInventory == null) return 0;

            for (int i = 0; i < shopperInventory.GetSize(); i++)
            {
                if (shopperInventory.GetItemInSlot(i) == item)
                {
                    total += shopperInventory.GetNumberInSlot(i);
                }
            }
            return total;
        }

        bool IsTransactionEmpty()
        {
            return transaction.Count == 0;
        }

        int GetShopperLevel()
        {
            BaseStats stats = currentShopper.GetComponent<BaseStats>();
            if (stats == null) return 0;

            return stats.GetLevel();
        }

        public object CaptureState()
        {
            Dictionary<string, int> saveObject = new Dictionary<string, int>();
            foreach (var pair in stockSold)
            {
                saveObject[pair.Key.GetItemID()] = pair.Value;
            }
            return saveObject;
        }

        public void RestoreState(object state)
        {
            stockSold.Clear();
            Dictionary<string, int> saveObject = (Dictionary<string, int>) state;
            foreach (var pair in saveObject)
            {
                stockSold[InventoryItem.GetFromID(pair.Key)] = pair.Value;
            }
        }
    }
}

Wallet.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using GameDevTV.Saving;

namespace RPG.Inventories
{
    public class Wallet : MonoBehaviour, ISaveable
    {
        [SerializeField] float startingBalance = 100f;

        float currentBalance;

        public event Action OnChange;

        void Awake()
        {
            currentBalance = startingBalance;
        }

        public float GetBalance()
        {
            return currentBalance;
        }

        public void UpdateBalance(float amount)
        {
            currentBalance += amount;
            OnChange?.Invoke();
        }

        public object CaptureState()
        {
            return currentBalance;
        }

        public void RestoreState(object state)
        {
            currentBalance = (float) state;
        }
    }
}

I believe this is the culprit. This is in Confirm Transaction, where the retail price is being charged instead of the sale price. Take a look at the line float price = item.GetPrice();

The item.price is the retail price.
shopItem.price is the sale price…

You found it. Brian, I have so many thanks for you, it’s unbelievable. You’re saving countless gray hairs for me haha

Glad to help.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms