InventoryItem.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using UnityEngine.EventSystems;
  6. namespace SoftKitty.InventoryEngine
  7. {
  8. public class InventoryItem : ItemIcon
  9. {
  10. [Tooltip("Determines if this item slot is splittable.")]
  11. public bool Splittable = true;
  12. [Tooltip("Determines if this item slot is deletable.")]
  13. public bool Deletable = true;
  14. [Tooltip("Indicates whether this item slot can receive untradeable items. For example, merchant slots should have this set to false.")]
  15. public bool RecieveUntradeable = true;
  16. [Tooltip("Indicates whether this item slot can receive dragged items.")]
  17. public bool RecieveDragging = true;
  18. [Tooltip("If this item slot only accepts items with a specific tag, specify that tag here.")]
  19. public string LimitedByTag = "";
  20. [Tooltip("If this item slot only accepts items from a specific owner, specify that owner here.")]
  21. public InventoryHolder LimitedByOwner;
  22. [Tooltip("Whether this item slot can be drag.")]
  23. public bool Draggable = true;
  24. #region Variables
  25. [HideInInspector]
  26. public InventoryStack StackData;
  27. public delegate void OnItemChange(Item _item, int _changedNumber, InventoryItem _itemIcon);
  28. public Image CoolDownMask;
  29. public Text CoolDownText;
  30. private OnItemChange OnItemChangeCallback;
  31. private float mouseDownTime = 0F;
  32. private Vector3 mouseDownPos;
  33. private bool isDragging = false;
  34. private bool waittingForDrop = false;
  35. private bool firstUpdate = true;
  36. [HideInInspector]
  37. public InventoryHolder Holder;
  38. #endregion
  39. #region Internal Methods
  40. public override void EndDrag(int _add)
  41. {
  42. if (StackData.Item != null)
  43. {
  44. StartCoroutine(EndDragCo(_add));
  45. }
  46. }
  47. public override void OnHover()
  48. {
  49. if (HoverInfoAnchorPoint != null && !StackData.isEmpty()) HoverInformation.ShowHoverInfo(this, StackData.Item, StackData.Number, HoverInfoAnchorPoint, PriceMultiplier, RightClickActionHint,true,true,(Deletable && ItemManager.instance.AllowDropItem));
  50. if (ItemManager.instance.HighlightEquipmentSlotWhenHoverItem && !StackData.isEmpty() && (Holder.Type == InventoryHolder.HolderType.PlayerInventory || Holder.Type == InventoryHolder.HolderType.NpcInventory))
  51. {
  52. InventoryHolder _equipHolder = null;
  53. _equipHolder = InventoryHolder.GetInventoryHolderByType(Holder.gameObject, Holder.Type == InventoryHolder.HolderType.PlayerInventory? InventoryHolder.HolderType.PlayerEquipment: InventoryHolder.HolderType.NpcEquipment);
  54. if (_equipHolder != null && WindowsManager.getOpenedWindow(_equipHolder) != null && WindowsManager.getOpenedWindow(_equipHolder).GetComponent<EquipmentUi>())
  55. {
  56. WindowsManager.getOpenedWindow(_equipHolder).GetComponent<EquipmentUi>().HighLightSlot(StackData.Item.tags);
  57. }
  58. }
  59. }
  60. public override void ResetState()
  61. {
  62. SetItemId(-2);
  63. number = 0;
  64. upgrade = -1;
  65. isDragging = false;
  66. mouseDownTime = 0F;
  67. mouseDownPos = InputProxy.mousePosition;
  68. ToggleOutline(false);
  69. SetFavorate(false);
  70. }
  71. public override void DoUpdate()
  72. {
  73. if (!inited) return;
  74. StateUpdate();
  75. if (!Enabled) return;
  76. CheckDropping();
  77. if (itemId < 0) return;
  78. CheckDragging();
  79. CheckCoolDown();
  80. }
  81. private void CheckCoolDown()
  82. {
  83. if (!Empty && itemId >= 0 && number > 0 && CoolDownMask && CoolDownText)
  84. {
  85. float _cd = ItemManager.itemDic[itemId].GetCoolDownTime();
  86. if (_cd > 0F)
  87. {
  88. if (CoolDownMask.gameObject.activeSelf != ItemManager.itemDic[itemId].isCoolDown()) CoolDownMask.gameObject.SetActive(ItemManager.itemDic[itemId].isCoolDown());
  89. if (ItemManager.itemDic[itemId].isCoolDown())
  90. {
  91. CoolDownMask.fillAmount = ItemManager.itemDic[itemId].GetRemainCoolDownTime() / _cd;
  92. if (ItemManager.itemDic[itemId].GetRemainCoolDownTime() >= 1F)
  93. {
  94. CoolDownText.text = Mathf.CeilToInt(ItemManager.itemDic[itemId].GetRemainCoolDownTime()).ToString();
  95. }
  96. else
  97. {
  98. CoolDownText.text = ItemManager.itemDic[itemId].GetRemainCoolDownTime().ToString("0.0");
  99. }
  100. }
  101. }
  102. }
  103. }
  104. private void StateUpdate()
  105. {
  106. if (!StackData.isEmpty())
  107. {
  108. Empty = false;
  109. if ((number != StackData.Number || itemId != StackData.Item.uid) && OnItemChangeCallback != null && !firstUpdate)
  110. {
  111. if(itemId>=0 && number>0 && itemId != StackData.Item.uid) OnItemChangeCallback(ItemManager.itemDic[itemId].Copy(), -number, this);
  112. OnItemChangeCallback(StackData.Item, itemId != StackData.Item.uid?StackData.Number: StackData.Number-number, this);
  113. }
  114. if (number != StackData.Number) SetItemNumber(StackData.Number);
  115. if (upgrade != StackData.Item.upgradeLevel) SetUpgradeLevel(StackData.Item.upgradeLevel);
  116. if (Fav.activeSelf != StackData.Item.favorite) SetFavorate(StackData.Item.favorite);
  117. if (itemId != StackData.Item.uid)
  118. {
  119. SetAppearance(StackData.Item.icon, StackData.Item.GetTypeColor(), StackData.Item.GetQualityColor(), true, true);
  120. SetItemId(StackData.Item.uid);
  121. }
  122. }
  123. else
  124. {
  125. if (!Empty)
  126. {
  127. int _uid = itemId;
  128. int _number = -number;
  129. SetEmpty();
  130. if (OnItemChangeCallback != null && !firstUpdate && _uid >= 0) OnItemChangeCallback(ItemManager.itemDic[_uid].Copy(), _number, this);
  131. }
  132. }
  133. firstUpdate = false;
  134. }
  135. private void CheckDropping()
  136. {
  137. if (ItemDragManager.isDragging)
  138. {
  139. waittingForDrop = true;
  140. }
  141. else
  142. {
  143. if (waittingForDrop && ItemDragManager.DraggingSource.Type == IconType.Item && ItemDragManager.DraggingSource.Icon != Icon
  144. && isHover && isVisible)
  145. {
  146. waittingForDrop = false;
  147. if (Vector3.Distance(ItemDragManager.DropPos, transform.position) < Mathf.Min(Rect.sizeDelta.x * 0.48F, Rect.sizeDelta.y * 0.48F)* Rect.lossyScale.x)
  148. {
  149. ItemDragManager.DropReceived = true;
  150. InventoryItem _source = (InventoryItem)ItemDragManager.DraggingSource;
  151. int _id = -1;
  152. int _number = 0;
  153. if (LimitedByOwner != null && _source.Holder != LimitedByOwner && _source.Holder!=Holder) return;
  154. if (_source.LimitedByOwner != null && Holder != _source.LimitedByOwner && _source.Holder != Holder) return;
  155. if ((Holder.Type == InventoryHolder.HolderType.PlayerEquipment || Holder.Type == InventoryHolder.HolderType.NpcEquipment) && !_source.GetItem().AbleToUse(Holder)) return;
  156. if ((_source.Holder.Type == InventoryHolder.HolderType.PlayerEquipment || _source.Holder.Type == InventoryHolder.HolderType.NpcEquipment) && !GetItem().AbleToUse(_source.Holder)) return;
  157. if (LimitedByTag.Length > 0 && !_source.isTagMatchText(LimitedByTag)) return;
  158. if (_source.LimitedByTag.Length > 0 && !isTagMatchText(_source.LimitedByTag) && !isEmpty()) return;
  159. if (!RecieveDragging) return;
  160. if (!RecieveUntradeable && !_source.isTradeable()) return;
  161. if (ItemDragManager.SplitMode)
  162. {
  163. if (_source.Holder != Holder) _id = ItemDragManager.SplitData.Item.uid;
  164. if ((itemId == ItemDragManager.SplitData.Item.uid && StackData.GetAvailableSpace() > 0) || itemId < 0)
  165. {
  166. _number = ItemDragManager.SplitData.Number;
  167. InventoryStack _temp = StackData.Merge(ItemDragManager.SplitData);
  168. _source.StackData.Number += _temp.Number;
  169. _number -= _temp.Number;
  170. }
  171. else
  172. {
  173. _number = ItemDragManager.SplitData.Number;
  174. _source.StackData.Number += ItemDragManager.SplitData.Number;
  175. _source.Copy(StackData.Merge(_source.StackData));
  176. }
  177. }
  178. else
  179. {
  180. if (_source.Holder != Holder) _id = _source.StackData.Item.uid;
  181. _number = _source.StackData.Number;
  182. _source.Copy(StackData.Merge(_source.StackData));
  183. }
  184. SetHolderChanged(_id, _number);
  185. if (_source.Holder != Holder) _source.SetHolderChanged(_id, -_number);
  186. Icon.transform.localScale = Vector3.one * 0.5F;
  187. _source.Icon.transform.localScale = Vector3.one * 0.5F;
  188. RecalculateWeight();
  189. _source.RecalculateWeight();
  190. }
  191. }
  192. }
  193. }
  194. IEnumerator EndDragCo(int _add)
  195. {
  196. yield return 2;
  197. if (!ItemDragManager.DropReceived)
  198. {
  199. int _id = StackData.GetItemId();
  200. int _number = StackData.Number;
  201. if (_add > 0)
  202. {
  203. if (EventSystem.current.IsPointerOverGameObject() || !Deletable || !ItemManager.instance.AllowDropItem || !StackData.Item.deletable)
  204. {
  205. _id = -1;
  206. StackData.AddNumber(_add);
  207. }
  208. else
  209. {
  210. _number = _add;
  211. ItemDragManager.PlayDeleteAnimation(this, ItemDragManager.DropPos, _add);
  212. if (Holder != null && Holder.mItemDropCallback != null) Holder.mItemDropCallback(StackData.Item != null ? StackData.Item.Copy() : ItemManager.itemDic[_id].Copy(), _number);
  213. RecalculateWeight();
  214. SetHolderChanged(_id, -_number);
  215. }
  216. }
  217. else
  218. {
  219. if (!EventSystem.current.IsPointerOverGameObject() && Deletable && ItemManager.instance.AllowDropItem)
  220. {
  221. ItemDragManager.PlayDeleteAnimation(this, ItemDragManager.DropPos);
  222. if (Holder != null && Holder.mItemDropCallback != null) Holder.mItemDropCallback(StackData.Item != null ? StackData.Item.Copy() : ItemManager.itemDic[_id].Copy(), _number);
  223. StackData.Delete();
  224. RecalculateWeight();
  225. SetHolderChanged(_id, -_number);
  226. }
  227. }
  228. ItemDragManager.DropReceived = true;
  229. }
  230. }
  231. private void CheckDragging()
  232. {
  233. if (ItemDragManager.isDragging || !Draggable) return;
  234. if (isHover)
  235. {
  236. if (InputProxy.GetMouseButtonDown(0))
  237. {
  238. mouseDownPos = InputProxy.mousePosition;
  239. isDragging = true;
  240. }
  241. if (InputProxy.GetMouseButton(0))
  242. {
  243. mouseDownTime += Time.deltaTime;
  244. }
  245. else
  246. {
  247. mouseDownTime = 0F;
  248. }
  249. }
  250. else
  251. {
  252. mouseDownTime = 0F;
  253. }
  254. if (isDragging)
  255. {
  256. if (InputProxy.GetMouseButton(0))
  257. {
  258. if (isVisible && (mouseDownTime > 0.5F || Vector3.Distance(InputProxy.mousePosition, mouseDownPos) > 40F))
  259. {
  260. isDragging = false;
  261. ItemDragManager.StartDragging(this, GetComponent<RectTransform>());
  262. }
  263. }
  264. else
  265. {
  266. isDragging = false;
  267. }
  268. }
  269. }
  270. #endregion
  271. /// <summary>
  272. /// Retrieves the InventoryStack data of this item.
  273. /// </summary>
  274. /// <returns></returns>
  275. public override InventoryStack GetStackData()
  276. {
  277. return StackData;
  278. }
  279. /// <summary>
  280. /// Retrieves the InventoryHolder of this slot.
  281. /// </summary>
  282. /// <returns></returns>
  283. public override InventoryHolder GetStackHolder()
  284. {
  285. return Holder;
  286. }
  287. /// <summary>
  288. /// Registers a callback for when this item has changed.
  289. /// </summary>
  290. /// <param name="_callback"></param>
  291. public void RegisterOnItemChangeCallback(OnItemChange _callback)
  292. {
  293. OnItemChangeCallback = _callback;
  294. }
  295. /// <summary>
  296. /// Unregisters the callback for when this item has changed.
  297. /// </summary>
  298. public void UnRegisterOnItemChangeCallback()
  299. {
  300. OnItemChangeCallback = null;
  301. }
  302. /// <summary>
  303. /// Pop up the split interface to split this item into two stacks.
  304. /// </summary>
  305. public void Split()
  306. {
  307. if (StackData.isEmpty() || StackData.Number <= 1 || !Splittable || !isVisible) return;
  308. NumberInput.GetNumber(StackData.Number, StackData.Number, Rect, Split);
  309. }
  310. /// <summary>
  311. /// Mark this item as Favorite item.
  312. /// </summary>
  313. public void MarkFav()
  314. {
  315. if (StackData.isEmpty()) return;
  316. StackData.Item.favorite = !StackData.Item.favorite;
  317. SetFavorate(StackData.Item.favorite);
  318. Holder.CheckAutoSave();
  319. }
  320. /// <summary>
  321. /// Drop this item.
  322. /// </summary>
  323. public void Drop()
  324. {
  325. if (!Deletable || !ItemManager.instance.AllowDropItem || StackData.isEmpty()) return;
  326. int _id = StackData.GetItemId();
  327. int _number = StackData.Number;
  328. if (Holder != null && Holder.mItemDropCallback != null) Holder.mItemDropCallback(StackData.Item != null ? StackData.Item.Copy() : ItemManager.itemDic[_id].Copy(), _number);
  329. StackData.Delete();
  330. RecalculateWeight();
  331. SetHolderChanged(_id, -_number);
  332. }
  333. /// <summary>
  334. /// Retrieves the Item in this slot.
  335. /// </summary>
  336. /// <returns></returns>
  337. public override Item GetItem()
  338. {
  339. return StackData.Item;
  340. }
  341. /// <summary>
  342. /// Sets the InventoryHolder for this slot.
  343. /// </summary>
  344. /// <param name="_holder"></param>
  345. public void SetHolder(InventoryHolder _holder)
  346. {
  347. Holder = _holder;
  348. }
  349. /// <summary>
  350. /// If the item has changed, inform the holder to update its data.
  351. /// </summary>
  352. /// <param name="_id"></param>
  353. /// <param name="_number"></param>
  354. public void SetHolderChanged(int _id, int _number)
  355. {
  356. Dictionary<Item, int> _changedItems = new Dictionary<Item, int>();
  357. if(_id!=-1) _changedItems.Add(ItemManager.itemDic[_id].Copy(),_number);
  358. if (Holder != null ) Holder.ItemChanged(_changedItems);
  359. }
  360. /// <summary>
  361. /// Inform the holder to recalculate the total weight
  362. /// </summary>
  363. public void RecalculateWeight()
  364. {
  365. if (Holder != null) Holder.CalWeight();
  366. }
  367. /// <summary>
  368. /// Initialize the data.
  369. /// </summary>
  370. /// <param name="_data"></param>
  371. public void Initialize(InventoryStack _data)
  372. {
  373. ResetState();
  374. StackData = _data;
  375. inited = true;
  376. }
  377. /// <summary>
  378. /// Copy data from an InventoryStack.
  379. /// </summary>
  380. /// <param name="_data"></param>
  381. public void Copy(InventoryStack _data)
  382. {
  383. inited = false;
  384. ResetState();
  385. if (_data.Item != null)
  386. StackData.Item = _data.Item.Copy();
  387. else
  388. StackData.Item = null;
  389. StackData.Number = _data.Number;
  390. StackData.Empty = _data.Empty;
  391. inited = true;
  392. }
  393. /// <summary>
  394. /// Returns whether the item name matches the provided string.
  395. /// </summary>
  396. /// <param name="_name"></param>
  397. /// <returns></returns>
  398. public bool isNameMatch(string _name)
  399. {
  400. if (_name == "" || itemId < 0 || !inited || StackData.isEmpty()) return true;
  401. return StackData.Item.name.ToLower().Contains(_name.ToLower());
  402. }
  403. /// <summary>
  404. /// Returns whether the item category matches the provided category ID.
  405. /// </summary>
  406. /// <param name="_type"></param>
  407. /// <returns></returns>
  408. public bool isTypeMatch(int _type)
  409. {
  410. if (_type == 0 || itemId < 0 || !inited || StackData.isEmpty()) return true;
  411. return StackData.Item.type == _type - 1;
  412. }
  413. /// <summary>
  414. /// Returns whether the item can be traded. Returns _emptyResult when the slot is empty.
  415. /// </summary>
  416. /// <param name="_emptyResult"></param>
  417. /// <returns></returns>
  418. public bool isTradeable(bool _emptyResult=true)
  419. {
  420. if (itemId < 0 || !inited || StackData.isEmpty()) return _emptyResult;
  421. return StackData.Item.tradeable;
  422. }
  423. /// <summary>
  424. /// Returns whether the item can be used. Returns _emptyResult when the slot is empty.
  425. /// </summary>
  426. /// <param name="_emptyResult"></param>
  427. /// <returns></returns>
  428. public bool isUseable(bool _emptyResult = true)
  429. {
  430. if (itemId < 0 || !inited || StackData.isEmpty()) return _emptyResult;
  431. return StackData.Item.useable;
  432. }
  433. /// <summary>
  434. /// Returns whether the item can be consumed. Returns _emptyResult when the slot is empty.
  435. /// </summary>
  436. /// <param name="_emptyResult"></param>
  437. /// <returns></returns>
  438. public bool isConsumable(bool _emptyResult = true)
  439. {
  440. if (itemId < 0 || !inited || StackData.isEmpty()) return _emptyResult;
  441. return StackData.Item.consumable;
  442. }
  443. /// <summary>
  444. /// Returns whether the item can be deleted. Returns _emptyResult when the slot is empty.
  445. /// </summary>
  446. /// <param name="_emptyResult"></param>
  447. /// <returns></returns>
  448. public bool isDeletable(bool _emptyResult = true)
  449. {
  450. if (itemId < 0 || !inited || StackData.isEmpty()) return _emptyResult;
  451. return StackData.Item.deletable;
  452. }
  453. /// <summary>
  454. /// Splits the item in this slot.
  455. /// </summary>
  456. /// <param name="_result"></param>
  457. public void Split(int _result)
  458. {
  459. if (_result > 0)
  460. {
  461. if (_result < StackData.Number)
  462. {
  463. ItemDragManager.StartDragging(this, GetComponent<RectTransform>(), _result);
  464. }
  465. else
  466. {
  467. ItemDragManager.StartDragging(this, GetComponent<RectTransform>());
  468. }
  469. }
  470. }
  471. /// <summary>
  472. /// Set the number of the item.
  473. /// </summary>
  474. /// <param name="_number"></param>
  475. public void SetDataNumber(int _number)
  476. {
  477. StackData.Number = _number;
  478. }
  479. }
  480. }