MerchantUi.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. namespace SoftKitty.InventoryEngine
  6. {
  7. public class MerchantUi : UiWindow
  8. {
  9. #region Variables
  10. public RectTransform HoverInfoAnchorPlayer;
  11. public RectTransform HoverInfoAnchorMerchant;
  12. public RawImage MerchantAvatar;
  13. public InventoryItem PlayerItemPrefab;
  14. public InventoryItem MerchantItemPrefab;
  15. public CurrenyInfo PlayerCurrencyPrefab;
  16. public CurrenyInfo MerchantCurrencyPrefab;
  17. public InputField SearchInput;
  18. public GameObject ClearFilterButton;
  19. public GameObject FavActiveIcon;
  20. public Text MerchantNameText;
  21. public Text SubtitleText;
  22. private InventoryItem[] playerItems;
  23. private InventoryItem[] merchantItems;
  24. private InventoryHolder playerHolder;
  25. private InventoryHolder merchantHolder;
  26. public Button TradeButton;
  27. private bool filterFav = false;
  28. private bool inited = false;
  29. private InventorySnapShot playerSnapshot;
  30. private InventorySnapShot merchantSnapshot;
  31. private List<CurrenyInfo> playerCurrencyItems = new List<CurrenyInfo>();
  32. private List<CurrenyInfo> merchantCurrencyItems = new List<CurrenyInfo>();
  33. public Image BlockImage;
  34. #endregion
  35. #region MonoBehaviour
  36. void Start()
  37. {
  38. FavActiveIcon.GetComponent<Image>().color = InventorySkin.instance.FavoriteColor;
  39. }
  40. public override void Update()
  41. {
  42. if (!inited) return;
  43. base.Update();
  44. FilterItems();
  45. CheckBlock();
  46. }
  47. #endregion
  48. public void SetMerchantAvatar(Texture _avatar) //Set the avatar image of the merchant to display on the top right of the window
  49. {
  50. MerchantAvatar.texture = _avatar;
  51. }
  52. public override void Initialize(InventoryHolder _playerHolder, InventoryHolder _merchantHolder, string _merchantName= "Merchant")//Initialize this interface
  53. {
  54. playerHolder = _playerHolder;
  55. merchantHolder = _merchantHolder;
  56. MerchantNameText.text = _merchantName;
  57. SubtitleText.text= " "+_merchantName.ToUpper();
  58. PlayerItemPrefab.Outline.color = InventorySkin.instance.ItemSelectedColor;
  59. PlayerItemPrefab.Hover.color = InventorySkin.instance.ItemHoverColor;
  60. PlayerItemPrefab.Fav.GetComponent<Image>().color = InventorySkin.instance.FavoriteColor;
  61. PlayerItemPrefab.LimitedByOwner = _merchantHolder;
  62. MerchantItemPrefab.Outline.color = InventorySkin.instance.ItemSelectedColor;
  63. MerchantItemPrefab.Hover.color = InventorySkin.instance.ItemHoverColor;
  64. MerchantItemPrefab.Fav.GetComponent<Image>().color = InventorySkin.instance.FavoriteColor;
  65. MerchantItemPrefab.LimitedByOwner = _playerHolder;
  66. playerHolder.RegisterItemChangeCallback(OnPlayerItemChange);
  67. merchantHolder.RegisterItemChangeCallback(OnMerchantItemChange);
  68. ShowList();
  69. for (int i = 0; i < playerHolder.Currency.Count; i++)
  70. {
  71. GameObject _newItem = Instantiate(PlayerCurrencyPrefab.gameObject, PlayerCurrencyPrefab.transform.parent);
  72. _newItem.transform.localScale = Vector3.one;
  73. _newItem.SetActive(true);
  74. _newItem.GetComponent<CurrenyInfo>().AutoCalculateChanges = false;
  75. _newItem.GetComponent<CurrenyInfo>().Initialize(i, playerHolder);
  76. playerCurrencyItems.Add(_newItem.GetComponent<CurrenyInfo>());
  77. }
  78. for (int i = 0; i < merchantHolder.Currency.Count; i++)
  79. {
  80. GameObject _newItem = Instantiate(MerchantCurrencyPrefab.gameObject, MerchantCurrencyPrefab.transform.parent);
  81. _newItem.transform.localScale = Vector3.one;
  82. _newItem.SetActive(true);
  83. _newItem.GetComponent<CurrenyInfo>().AutoCalculateChanges = false;
  84. _newItem.GetComponent<CurrenyInfo>().Initialize(i, merchantHolder);
  85. merchantCurrencyItems.Add(_newItem.GetComponent<CurrenyInfo>());
  86. }
  87. playerSnapshot = playerHolder.GetSnapShot();
  88. merchantSnapshot = merchantHolder.GetSnapShot();
  89. playerHolder.AutoSave = false;
  90. merchantHolder.BlockAutoSave = true;
  91. playerHolder.BlockAutoSave = true;
  92. inited = true;
  93. }
  94. private void ShowList()//Show item list for both side
  95. {
  96. playerItems = new InventoryItem[playerHolder.Stacks.Count];
  97. for (int i = 0; i < playerHolder.Stacks.Count; i++)
  98. {
  99. GameObject _newItem = Instantiate(PlayerItemPrefab.gameObject, PlayerItemPrefab.transform.parent);
  100. _newItem.transform.localScale = Vector3.one;
  101. _newItem.GetComponent<InventoryItem>().Initialize(playerHolder.Stacks[i]);
  102. _newItem.GetComponent<InventoryItem>().SetHolder(playerHolder);
  103. _newItem.GetComponent<InventoryItem>().HoverInfoAnchorPoint = HoverInfoAnchorPlayer;
  104. _newItem.GetComponent<InventoryItem>().RegisterClickCallback(i, OnPlayerItemClick);
  105. _newItem.GetComponent<InventoryItem>().PriceMultiplier = merchantHolder.BuyPriceMultiplier;
  106. _newItem.gameObject.SetActive(true);
  107. playerItems[i] = _newItem.GetComponent<InventoryItem>();
  108. }
  109. merchantItems = new InventoryItem[merchantHolder.Stacks.Count];
  110. for (int i = 0; i < merchantHolder.Stacks.Count; i++)
  111. {
  112. GameObject _newItem = Instantiate(MerchantItemPrefab.gameObject, MerchantItemPrefab.transform.parent);
  113. _newItem.transform.localScale = Vector3.one;
  114. _newItem.GetComponent<InventoryItem>().Initialize(merchantHolder.Stacks[i]);
  115. _newItem.GetComponent<InventoryItem>().SetHolder(merchantHolder);
  116. _newItem.GetComponent<InventoryItem>().HoverInfoAnchorPoint = HoverInfoAnchorMerchant;
  117. _newItem.GetComponent<InventoryItem>().RegisterClickCallback(i, OnMerchantItemClick);
  118. _newItem.GetComponent<InventoryItem>().PriceMultiplier = merchantHolder.SellPriceMultiplier;
  119. _newItem.GetComponent<InventoryItem>().RecieveUntradeable = false;
  120. _newItem.gameObject.SetActive(true);
  121. merchantItems[i] = _newItem.GetComponent<InventoryItem>();
  122. }
  123. }
  124. private bool isKeyMatch(AlterKeys _key)
  125. {
  126. switch (_key)
  127. {
  128. case AlterKeys.None:
  129. return true;
  130. case AlterKeys.LeftCtrl:
  131. return InputProxy.GetKey(KeyCode.LeftControl);
  132. case AlterKeys.LeftAlt:
  133. return InputProxy.GetKey(KeyCode.LeftAlt);
  134. case AlterKeys.LeftShift:
  135. return InputProxy.GetKey(KeyCode.LeftShift);
  136. }
  137. return false;
  138. }
  139. public void OnPlayerItemClick(int _index, int _button)//Callback for when player click an item in player's inventory.
  140. {
  141. if ( !playerItems[_index].isEmpty() && playerItems[_index].isTradeable()
  142. && (merchantHolder.TradeAllItems || merchantHolder.TradeList.Contains(playerItems[_index].GetItemId()) || merchantHolder.TradeCategoryList.Contains(playerItems[_index].GetCategory())))
  143. {
  144. foreach (var setting in ItemManager.instance.clickSettings)
  145. {
  146. if (_button == (int)setting.mouseButton && isKeyMatch(setting.key))
  147. {
  148. if (setting.function == ClickFunctions.Use )
  149. {
  150. playerHolder.RemoveItem(playerItems[_index].GetItemId(), 1 - merchantHolder.AddItem(playerItems[_index].GetItem(), 1).Number, _index);
  151. SoundManager.Play2D("ItemDrop");
  152. }
  153. else if (setting.function == ClickFunctions.MarkFavorite)
  154. {
  155. playerItems[_index].MarkFav();
  156. }
  157. }
  158. }
  159. }
  160. }
  161. public void OnMerchantItemClick(int _index, int _button)//Callback for when player click an item in merchant's inventory.
  162. {
  163. if (!merchantItems[_index].isEmpty() && merchantItems[_index].isTradeable())
  164. {
  165. foreach (var setting in ItemManager.instance.clickSettings)
  166. {
  167. if (_button == (int)setting.mouseButton && isKeyMatch(setting.key))
  168. {
  169. if (setting.function == ClickFunctions.Use)
  170. {
  171. merchantHolder.RemoveItem(merchantItems[_index].GetItemId(), 1 - playerHolder.AddItem(merchantItems[_index].GetItem(), 1).Number, _index);
  172. SoundManager.Play2D("ItemDrop");
  173. }
  174. }
  175. }
  176. }
  177. }
  178. private void OnDestroy()//UnRegisterI all callbacks
  179. {
  180. playerHolder.UnRegisterItemChangeCallback(OnPlayerItemChange);
  181. merchantHolder.UnRegisterItemChangeCallback(OnMerchantItemChange);
  182. merchantHolder.BlockAutoSave = false;
  183. playerHolder.BlockAutoSave = false;
  184. }
  185. public void OnPlayerItemChange(Dictionary<Item, int> _changedItems)//Callback for when items in player's inventory has changed.
  186. {
  187. GetCurrencyChange();
  188. }
  189. public void OnMerchantItemChange(Dictionary<Item, int> _changedItems)//Callback for when items in merchant's inventory has changed.
  190. {
  191. GetCurrencyChange();
  192. }
  193. private void GetCurrencyChange()//Compare the items with the snapeshot, calculate the difference by their cost.
  194. {
  195. Dictionary<int, int> _playerDic = new Dictionary<int, int>();
  196. Dictionary<int ,int> _merchantDic = new Dictionary<int, int>();
  197. foreach (var obj in playerHolder.Stacks)
  198. {
  199. if (!obj.isEmpty())
  200. {
  201. if (!_playerDic.ContainsKey(obj.GetItemId()))
  202. {
  203. _playerDic.Add(obj.GetItemId(), obj.Number);
  204. }
  205. else
  206. {
  207. _playerDic[obj.GetItemId()] += obj.Number;
  208. }
  209. }
  210. }
  211. foreach (var obj in playerSnapshot.Stacks)
  212. {
  213. if (!obj.isEmpty())
  214. {
  215. if (!_playerDic.ContainsKey(obj.GetItemId())) _playerDic.Add(obj.GetItemId(),0);
  216. }
  217. }
  218. foreach (var obj in merchantHolder.Stacks)
  219. {
  220. if (!obj.isEmpty())
  221. {
  222. if (!_merchantDic.ContainsKey(obj.GetItemId()))
  223. {
  224. _merchantDic.Add(obj.GetItemId(), obj.Number);
  225. }
  226. else
  227. {
  228. _merchantDic[obj.GetItemId()] += obj.Number;
  229. }
  230. }
  231. }
  232. foreach (var obj in merchantSnapshot.Stacks)
  233. {
  234. if (!obj.isEmpty())
  235. {
  236. if (!_merchantDic.ContainsKey(obj.GetItemId())) _merchantDic.Add(obj.GetItemId(), 0);
  237. }
  238. }
  239. int[] _currencyChange = new int[ItemManager.instance.currencies.Count];
  240. foreach (var key in _playerDic.Keys)
  241. {
  242. int _change = _playerDic[key] - playerSnapshot.GetItemNumber(key);
  243. if (_merchantDic.ContainsKey(key)) { //Compare with the change of merchant's item, make sure player is not cheating.
  244. int _merchantChange = _merchantDic[key] - merchantSnapshot.GetItemNumber(key);
  245. int _finalChange = Mathf.Max(_change, -_merchantChange);//Clamp on what merchant get or lost, make sure player is not cheating.
  246. if (_finalChange > 0)
  247. {//Buy
  248. _currencyChange[ItemManager.itemDic[key].currency] -= Mathf.CeilToInt(ItemManager.itemDic[key].price * merchantHolder.SellPriceMultiplier * _finalChange);
  249. }
  250. else if (_finalChange < 0)
  251. {//Sell
  252. _currencyChange[ItemManager.itemDic[key].currency] += Mathf.CeilToInt(ItemManager.itemDic[key].price * merchantHolder.BuyPriceMultiplier * -_finalChange);
  253. }
  254. }
  255. }
  256. bool _lackOfCurrency = false;
  257. for (int i = 0; i < _currencyChange.Length; i++)
  258. {
  259. playerHolder.SetCurrency(i,playerSnapshot.GetCurrency(i,false)+ _currencyChange[i]);
  260. merchantHolder.SetCurrency(i,merchantSnapshot.GetCurrency(i, false) - _currencyChange[i]);
  261. if (playerHolder.GetCurrency(i, true) < 0 || merchantHolder.GetCurrency(i,true) < 0) _lackOfCurrency = true;
  262. }
  263. TradeButton.interactable = !_lackOfCurrency;
  264. TradeButton.GetComponent<CanvasGroup>().alpha = _lackOfCurrency ? 0.2F : 1F;
  265. List<int> _playerCurrencyDifference = playerHolder.GetCurrencyDifference(playerSnapshot.CurrencyValue);
  266. for (int i = 0; i < playerCurrencyItems.Count; i++) playerCurrencyItems[i].SetChangeText(_playerCurrencyDifference[i]);
  267. List<int> _merchantCurrencyDifference = merchantHolder.GetCurrencyDifference(merchantSnapshot.CurrencyValue);
  268. for (int i = 0; i < merchantCurrencyItems.Count; i++) merchantCurrencyItems[i].SetChangeText(_merchantCurrencyDifference[i]);
  269. }
  270. public override void Close()//Revert to the snapshot for both side if the window is closed.
  271. {
  272. playerHolder.RevertSnapShot(playerSnapshot);
  273. merchantHolder.RevertSnapShot(merchantSnapshot);
  274. base.Close();
  275. }
  276. public void Cancel()//Revert to the snapshot for both side
  277. {
  278. SoundManager.Play2D("Sort");
  279. playerHolder.RevertSnapShot(playerSnapshot);
  280. merchantHolder.RevertSnapShot(merchantSnapshot);
  281. foreach (var obj in playerCurrencyItems)
  282. {
  283. obj.SetChangeText(0);
  284. }
  285. foreach (var obj in merchantCurrencyItems)
  286. {
  287. obj.SetChangeText(0);
  288. }
  289. }
  290. public void Purchase()//Confirm the purchase and close the window
  291. {
  292. SoundManager.Play2D("Trade");
  293. SoundManager.Play2D("DoneDeal");
  294. merchantHolder.BlockAutoSave = false;
  295. playerHolder.BlockAutoSave = false;
  296. playerHolder.Save();
  297. merchantHolder.Save();
  298. playerSnapshot = playerHolder.GetSnapShot();
  299. merchantSnapshot = merchantHolder.GetSnapShot();
  300. foreach (var obj in playerCurrencyItems) {
  301. obj.SetChangeText(0);
  302. }
  303. foreach (var obj in merchantCurrencyItems)
  304. {
  305. obj.SetChangeText(0);
  306. }
  307. }
  308. public void FilterItems()//Filter the items by their name and "isTradeable" mark
  309. {
  310. for (int i = 0; i < playerItems.Length; i++)
  311. {
  312. playerItems[i].SetVisible(playerItems[i].isNameMatch(SearchInput.text) && (!filterFav || playerItems[i].Fav.activeSelf) && playerItems[i].isTradeable(true)
  313. && (merchantHolder.TradeAllItems || merchantHolder.TradeList.Contains(playerItems[i].GetItemId()) || merchantHolder.TradeCategoryList.Contains(playerItems[i].GetCategory())));
  314. }
  315. for (int i = 0; i < merchantItems.Length; i++)
  316. {
  317. merchantItems[i].SetVisible(merchantItems[i].isNameMatch(SearchInput.text));
  318. }
  319. ClearFilterButton.SetActive(SearchInput.text != "");
  320. }
  321. public void ClearFilter()//Clear all filters.
  322. {
  323. SearchInput.text = "";
  324. ClearFilterButton.SetActive(false);
  325. filterFav = false;
  326. for (int i = 0; i < playerItems.Length; i++)
  327. {
  328. playerItems[i].SetVisible(true);
  329. }
  330. for (int i = 0; i < merchantItems.Length; i++)
  331. {
  332. merchantItems[i].SetVisible(true);
  333. }
  334. }
  335. public void ShowFavItems()//Only show favorite items
  336. {
  337. SoundManager.Play2D("Tab");
  338. filterFav = !filterFav;
  339. FavActiveIcon.SetActive(filterFav);
  340. FilterItems();
  341. }
  342. private void CheckBlock()//Check if the interface should be blocked.
  343. {
  344. if (NumberInput.instance != null)
  345. {
  346. BlockImage.gameObject.SetActive(true);
  347. BlockImage.color = new Color(0F, 0F, 0F, Mathf.Lerp(BlockImage.color.a, 0.94F, Time.deltaTime * 3F));
  348. }
  349. else
  350. {
  351. if (BlockImage.color.a > 0F)
  352. {
  353. BlockImage.color = new Color(0F, 0F, 0F, Mathf.MoveTowards(BlockImage.color.a, 0F, Time.deltaTime * 2F));
  354. }
  355. else
  356. {
  357. if (BlockImage.gameObject.activeSelf) BlockImage.gameObject.SetActive(false);
  358. }
  359. }
  360. }
  361. }
  362. }