ShopBase.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Assets.HeroEditor4D.Common.Scripts.CharacterScripts;
  5. using Assets.HeroEditor4D.Common.Scripts.Common;
  6. using Assets.HeroEditor4D.InventorySystem.Scripts.Data;
  7. using Assets.HeroEditor4D.InventorySystem.Scripts.Enums;
  8. using Assets.HeroEditor4D.InventorySystem.Scripts.Elements;
  9. using UnityEngine;
  10. using UnityEngine.UI;
  11. namespace Assets.HeroEditor4D.InventorySystem.Scripts
  12. {
  13. /// <summary>
  14. /// High-level shop interface.
  15. /// </summary>
  16. public class ShopBase : ItemWorkspace
  17. {
  18. public ScrollInventory TraderInventory;
  19. public ScrollInventory PlayerInventory;
  20. public InputField AmountInput;
  21. public Button BuyButton;
  22. public Button SellButton;
  23. public AudioSource AudioSource;
  24. public AudioClip TradeSound;
  25. public AudioClip NoMoney;
  26. public Character Dummy;
  27. public bool ExampleInitialize;
  28. public string CurrencyId = "Gold";
  29. public int Amount;
  30. // These callbacks can be used outside;
  31. public Action<Item> OnRefresh;
  32. public Action<Item> OnBuy;
  33. public Action<Item> OnSell;
  34. public void Awake()
  35. {
  36. // You must to set an active collection (as there may be several different collections in Resources).
  37. ItemCollection.Active = ItemCollection;
  38. }
  39. public void Start()
  40. {
  41. if (ExampleInitialize)
  42. {
  43. TestInitialize();
  44. }
  45. }
  46. public virtual bool CanBuy(Item item) // Override this function to fit your needs!
  47. {
  48. return true;
  49. }
  50. public virtual bool CanSell(Item item) // Override this function to fit your needs!
  51. {
  52. return true;
  53. }
  54. public virtual int GetPrice(Item item) // Override this function to fit your needs!
  55. {
  56. var trader = TraderInventory.Items.Contains(item);
  57. var price = item.Params.Price * Amount;
  58. if (trader)
  59. {
  60. price *= GetTraderMarkup(item);
  61. }
  62. return price;
  63. }
  64. public static int GetTraderMarkup(Item item) // Override this function to fit your needs!
  65. {
  66. if (item.Params.Rarity > ItemRarity.Common) return 2;
  67. switch (item.Params.Type)
  68. {
  69. case ItemType.Weapon:
  70. case ItemType.Armor:
  71. case ItemType.Helmet:
  72. case ItemType.Shield:
  73. case ItemType.Backpack: return 3;
  74. default: return 2;
  75. }
  76. }
  77. public void RegisterCallbacks()
  78. {
  79. InventoryItem.OnLeftClick = SelectItem;
  80. InventoryItem.OnRightClick = InventoryItem.OnDoubleClick = item => { SelectItem(item); if (TraderInventory.Items.Contains(item)) Buy(); else Sell(); };
  81. }
  82. /// <summary>
  83. /// Initialize owned items and trader items (just for example).
  84. /// </summary>
  85. public void TestInitialize()
  86. {
  87. var inventory = new List<Item> { new Item(CurrencyId, 10000) };
  88. var shop = ItemCollection.Active.Items.Select(i => new Item(i.Id, 2)).ToList();
  89. shop.Single(i => i.Id == CurrencyId).Count = 99999;
  90. RegisterCallbacks();
  91. TraderInventory.Initialize(ref shop);
  92. PlayerInventory.Initialize(ref inventory);
  93. if (!TraderInventory.SelectAny() && !PlayerInventory.SelectAny())
  94. {
  95. ItemInfo.Reset();
  96. }
  97. }
  98. public void Initialize(ref List<Item> traderItems, ref List<Item> playerItems)
  99. {
  100. RegisterCallbacks();
  101. TraderInventory.Initialize(ref traderItems);
  102. PlayerInventory.Initialize(ref playerItems);
  103. if (!TraderInventory.SelectAny() && !PlayerInventory.SelectAny())
  104. {
  105. ItemInfo.Reset();
  106. }
  107. }
  108. public void SelectItem(Item item)
  109. {
  110. SelectedItem = item;
  111. SetAmount(1);
  112. ItemInfo.Initialize(SelectedItem, GetPrice(SelectedItem), TraderInventory.Items.Contains(item));
  113. Refresh();
  114. }
  115. public void Buy()
  116. {
  117. if (!BuyButton.gameObject.activeSelf || !BuyButton.interactable || !CanBuy(SelectedItem)) return;
  118. var item = SelectedItem;
  119. var price = GetPrice(item);
  120. if (GetCurrency(PlayerInventory, CurrencyId) < price)
  121. {
  122. #if TAP_HEROES
  123. TapHeroes.Scripts.Interface.Popup.Instance.ShowMessage(SimpleLocalization.LocalizationManager.Localize("Common.NoFunds", "[" + TapHeroes.Scripts.Extensions.GetLocalizedName(new Item(CurrencyId).Params) + "]"), CurrencyId, NoMoney);
  124. #else
  125. Debug.LogWarning("You don't have enough gold!");
  126. AudioSource.PlayOneShot(NoMoney, SfxVolume);
  127. #endif
  128. return;
  129. }
  130. OnBuy?.Invoke(item);
  131. AddMoney(PlayerInventory, -price, CurrencyId);
  132. AddMoney(TraderInventory, price, CurrencyId);
  133. MoveItem(item, TraderInventory, PlayerInventory, Amount, currencyId: CurrencyId);
  134. AudioSource.PlayOneShot(TradeSound, SfxVolume);
  135. #if TAP_HEROES
  136. TapHeroes.Scripts.Interface.Tutorial.Instance.OnBuyItem(item.Id); // TODO: Create OnBuyCallback;
  137. #endif
  138. }
  139. public void Sell()
  140. {
  141. if (!SellButton.gameObject.activeSelf || !SellButton.interactable || !CanSell(SelectedItem)) return;
  142. var price = GetPrice(SelectedItem);
  143. if (GetCurrency(TraderInventory, CurrencyId) < price)
  144. {
  145. #if TAP_HEROES
  146. TapHeroes.Scripts.Interface.Popup.Instance.ShowMessage(SimpleLocalization.LocalizationManager.Localize("Common.NoFunds", "[" + TapHeroes.Scripts.Extensions.GetLocalizedName(new Item(CurrencyId).Params) + "]"), CurrencyId, NoMoney);
  147. #else
  148. Debug.LogWarning("Trader doesn't have enough gold!");
  149. AudioSource.PlayOneShot(NoMoney, SfxVolume);
  150. #endif
  151. return;
  152. }
  153. OnSell?.Invoke(SelectedItem);
  154. AddMoney(PlayerInventory, price, CurrencyId);
  155. AddMoney(TraderInventory, -price, CurrencyId);
  156. MoveItem(SelectedItem, PlayerInventory, TraderInventory, Amount, currencyId: CurrencyId);
  157. AudioSource.PlayOneShot(TradeSound, SfxVolume);
  158. }
  159. public override void Refresh()
  160. {
  161. if (SelectedItem == null)
  162. {
  163. ItemInfo.Reset();
  164. BuyButton.SetActive(false);
  165. SellButton.SetActive(false);
  166. }
  167. else
  168. {
  169. if (TraderInventory.Items.Contains(SelectedItem))
  170. {
  171. InitBuy();
  172. }
  173. else if (PlayerInventory.Items.Contains(SelectedItem))
  174. {
  175. InitSell();
  176. }
  177. else if (TraderInventory.Items.Any(i => i.Hash == SelectedItem.Hash))
  178. {
  179. InitBuy();
  180. }
  181. else if (PlayerInventory.Items.Any(i => i.Hash == SelectedItem.Hash))
  182. {
  183. InitSell();
  184. }
  185. }
  186. OnRefresh?.Invoke(SelectedItem);
  187. }
  188. public void SetMinAmount()
  189. {
  190. SetAmount(1);
  191. }
  192. public void IncAmount(int value)
  193. {
  194. SetAmount(Amount + value);
  195. }
  196. public void SetMaxAmount()
  197. {
  198. SetAmount(SelectedItem.Count);
  199. }
  200. public void OnAmountChanged(string value)
  201. {
  202. if (value.IsEmpty()) return;
  203. SetAmount(int.Parse(value));
  204. }
  205. public void OnAmountEndEdit(string value)
  206. {
  207. if (value.IsEmpty())
  208. {
  209. SetAmount(1);
  210. }
  211. }
  212. private void SetAmount(int amount)
  213. {
  214. Amount = Mathf.Max(1, Mathf.Min(SelectedItem.Count, amount));
  215. AmountInput?.SetTextWithoutNotify(Amount.ToString());
  216. ItemInfo.UpdatePrice(SelectedItem, GetPrice(SelectedItem), TraderInventory.Items.Contains(SelectedItem));
  217. }
  218. private void InitBuy()
  219. {
  220. BuyButton.SetActive(SelectedItem.Params.Type != ItemType.Currency && SelectedItem.Count > 0 && !SelectedItem.Params.Tags.Contains(ItemTag.NotForSale) && !SelectedItem.Params.Tags.Contains(ItemTag.Quest) && CanBuy(SelectedItem));
  221. SellButton.SetActive(false);
  222. //BuyButton.interactable = GetCurrency(Bag, CurrencyId) >= SelectedItem.Params.Price;
  223. }
  224. private void InitSell()
  225. {
  226. BuyButton.SetActive(false);
  227. SellButton.SetActive(SelectedItem.Count > 0 && !SelectedItem.Params.Tags.Contains(ItemTag.NotForSale) && !SelectedItem.Params.Tags.Contains(ItemTag.Quest) && SelectedItem.Id != CurrencyId && CanSell(SelectedItem));
  228. //SellButton.interactable = GetCurrency(Trader, CurrencyId) >= SelectedItem.Params.Price;
  229. }
  230. public static long GetCurrency(ItemContainer bag, string currencyId)
  231. {
  232. var currency = bag.Items.SingleOrDefault(i => i.Id == currencyId);
  233. return currency?.Count ?? 0;
  234. }
  235. private static void AddMoney(ItemContainer inventory, int value, string currencyId)
  236. {
  237. var currency = inventory.Items.SingleOrDefault(i => i.Id == currencyId);
  238. if (currency == null)
  239. {
  240. inventory.Items.Insert(0, new Item(currencyId, value));
  241. }
  242. else
  243. {
  244. currency.Count += value;
  245. if (currency.Count == 0)
  246. {
  247. inventory.Items.Remove(currency);
  248. }
  249. }
  250. }
  251. }
  252. }