using System; using System.Collections.Generic; using System.Linq; using Assets.HeroEditor4D.Common.Scripts.CharacterScripts; using Assets.HeroEditor4D.Common.Scripts.Common; using Assets.HeroEditor4D.InventorySystem.Scripts.Data; using Assets.HeroEditor4D.InventorySystem.Scripts.Enums; using Assets.HeroEditor4D.InventorySystem.Scripts.Elements; using UnityEngine; using UnityEngine.UI; namespace Assets.HeroEditor4D.InventorySystem.Scripts { /// /// High-level shop interface. /// public class ShopBase : ItemWorkspace { public ScrollInventory TraderInventory; public ScrollInventory PlayerInventory; public InputField AmountInput; public Button BuyButton; public Button SellButton; public AudioSource AudioSource; public AudioClip TradeSound; public AudioClip NoMoney; public Character Dummy; public bool ExampleInitialize; public string CurrencyId = "Gold"; public int Amount; // These callbacks can be used outside; public Action OnRefresh; public Action OnBuy; public Action OnSell; public void Awake() { // You must to set an active collection (as there may be several different collections in Resources). ItemCollection.Active = ItemCollection; } public void Start() { if (ExampleInitialize) { TestInitialize(); } } public virtual bool CanBuy(Item item) // Override this function to fit your needs! { return true; } public virtual bool CanSell(Item item) // Override this function to fit your needs! { return true; } public virtual int GetPrice(Item item) // Override this function to fit your needs! { var trader = TraderInventory.Items.Contains(item); var price = item.Params.Price * Amount; if (trader) { price *= GetTraderMarkup(item); } return price; } public static int GetTraderMarkup(Item item) // Override this function to fit your needs! { if (item.Params.Rarity > ItemRarity.Common) return 2; switch (item.Params.Type) { case ItemType.Weapon: case ItemType.Armor: case ItemType.Helmet: case ItemType.Shield: case ItemType.Backpack: return 3; default: return 2; } } public void RegisterCallbacks() { InventoryItem.OnLeftClick = SelectItem; InventoryItem.OnRightClick = InventoryItem.OnDoubleClick = item => { SelectItem(item); if (TraderInventory.Items.Contains(item)) Buy(); else Sell(); }; } /// /// Initialize owned items and trader items (just for example). /// public void TestInitialize() { var inventory = new List { new Item(CurrencyId, 10000) }; var shop = ItemCollection.Active.Items.Select(i => new Item(i.Id, 2)).ToList(); shop.Single(i => i.Id == CurrencyId).Count = 99999; RegisterCallbacks(); TraderInventory.Initialize(ref shop); PlayerInventory.Initialize(ref inventory); if (!TraderInventory.SelectAny() && !PlayerInventory.SelectAny()) { ItemInfo.Reset(); } } public void Initialize(ref List traderItems, ref List playerItems) { RegisterCallbacks(); TraderInventory.Initialize(ref traderItems); PlayerInventory.Initialize(ref playerItems); if (!TraderInventory.SelectAny() && !PlayerInventory.SelectAny()) { ItemInfo.Reset(); } } public void SelectItem(Item item) { SelectedItem = item; SetAmount(1); ItemInfo.Initialize(SelectedItem, GetPrice(SelectedItem), TraderInventory.Items.Contains(item)); Refresh(); } public void Buy() { if (!BuyButton.gameObject.activeSelf || !BuyButton.interactable || !CanBuy(SelectedItem)) return; var item = SelectedItem; var price = GetPrice(item); if (GetCurrency(PlayerInventory, CurrencyId) < price) { #if TAP_HEROES TapHeroes.Scripts.Interface.Popup.Instance.ShowMessage(SimpleLocalization.LocalizationManager.Localize("Common.NoFunds", "[" + TapHeroes.Scripts.Extensions.GetLocalizedName(new Item(CurrencyId).Params) + "]"), CurrencyId, NoMoney); #else Debug.LogWarning("You don't have enough gold!"); AudioSource.PlayOneShot(NoMoney, SfxVolume); #endif return; } OnBuy?.Invoke(item); AddMoney(PlayerInventory, -price, CurrencyId); AddMoney(TraderInventory, price, CurrencyId); MoveItem(item, TraderInventory, PlayerInventory, Amount, currencyId: CurrencyId); AudioSource.PlayOneShot(TradeSound, SfxVolume); #if TAP_HEROES TapHeroes.Scripts.Interface.Tutorial.Instance.OnBuyItem(item.Id); // TODO: Create OnBuyCallback; #endif } public void Sell() { if (!SellButton.gameObject.activeSelf || !SellButton.interactable || !CanSell(SelectedItem)) return; var price = GetPrice(SelectedItem); if (GetCurrency(TraderInventory, CurrencyId) < price) { #if TAP_HEROES TapHeroes.Scripts.Interface.Popup.Instance.ShowMessage(SimpleLocalization.LocalizationManager.Localize("Common.NoFunds", "[" + TapHeroes.Scripts.Extensions.GetLocalizedName(new Item(CurrencyId).Params) + "]"), CurrencyId, NoMoney); #else Debug.LogWarning("Trader doesn't have enough gold!"); AudioSource.PlayOneShot(NoMoney, SfxVolume); #endif return; } OnSell?.Invoke(SelectedItem); AddMoney(PlayerInventory, price, CurrencyId); AddMoney(TraderInventory, -price, CurrencyId); MoveItem(SelectedItem, PlayerInventory, TraderInventory, Amount, currencyId: CurrencyId); AudioSource.PlayOneShot(TradeSound, SfxVolume); } public override void Refresh() { if (SelectedItem == null) { ItemInfo.Reset(); BuyButton.SetActive(false); SellButton.SetActive(false); } else { if (TraderInventory.Items.Contains(SelectedItem)) { InitBuy(); } else if (PlayerInventory.Items.Contains(SelectedItem)) { InitSell(); } else if (TraderInventory.Items.Any(i => i.Hash == SelectedItem.Hash)) { InitBuy(); } else if (PlayerInventory.Items.Any(i => i.Hash == SelectedItem.Hash)) { InitSell(); } } OnRefresh?.Invoke(SelectedItem); } public void SetMinAmount() { SetAmount(1); } public void IncAmount(int value) { SetAmount(Amount + value); } public void SetMaxAmount() { SetAmount(SelectedItem.Count); } public void OnAmountChanged(string value) { if (value.IsEmpty()) return; SetAmount(int.Parse(value)); } public void OnAmountEndEdit(string value) { if (value.IsEmpty()) { SetAmount(1); } } private void SetAmount(int amount) { Amount = Mathf.Max(1, Mathf.Min(SelectedItem.Count, amount)); AmountInput?.SetTextWithoutNotify(Amount.ToString()); ItemInfo.UpdatePrice(SelectedItem, GetPrice(SelectedItem), TraderInventory.Items.Contains(SelectedItem)); } private void InitBuy() { BuyButton.SetActive(SelectedItem.Params.Type != ItemType.Currency && SelectedItem.Count > 0 && !SelectedItem.Params.Tags.Contains(ItemTag.NotForSale) && !SelectedItem.Params.Tags.Contains(ItemTag.Quest) && CanBuy(SelectedItem)); SellButton.SetActive(false); //BuyButton.interactable = GetCurrency(Bag, CurrencyId) >= SelectedItem.Params.Price; } private void InitSell() { BuyButton.SetActive(false); SellButton.SetActive(SelectedItem.Count > 0 && !SelectedItem.Params.Tags.Contains(ItemTag.NotForSale) && !SelectedItem.Params.Tags.Contains(ItemTag.Quest) && SelectedItem.Id != CurrencyId && CanSell(SelectedItem)); //SellButton.interactable = GetCurrency(Trader, CurrencyId) >= SelectedItem.Params.Price; } public static long GetCurrency(ItemContainer bag, string currencyId) { var currency = bag.Items.SingleOrDefault(i => i.Id == currencyId); return currency?.Count ?? 0; } private static void AddMoney(ItemContainer inventory, int value, string currencyId) { var currency = inventory.Items.SingleOrDefault(i => i.Id == currencyId); if (currency == null) { inventory.Items.Insert(0, new Item(currencyId, value)); } else { currency.Count += value; if (currency.Count == 0) { inventory.Items.Remove(currency); } } } } }