ShopUI.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.UIElements;
  5. public class ShopUI : MonoBehaviour
  6. {
  7. [Header("Shop Settings")]
  8. public Shop currentShop;
  9. private UIDocument uiDocument;
  10. private Character currentCharacter;
  11. private Bank currentBank;
  12. private Inventory currentInventory;
  13. // UI Elements
  14. private VisualElement shopContainer;
  15. private TextField searchField;
  16. private DropdownField categoryFilter;
  17. private ScrollView itemList;
  18. private Label shopTitle;
  19. private Label playerMoney;
  20. private Button closeButton;
  21. // Current filter state
  22. private ItemType? currentFilter = null;
  23. private string currentSearchTerm = "";
  24. void Awake()
  25. {
  26. uiDocument = GetComponent<UIDocument>();
  27. if (uiDocument == null)
  28. {
  29. Debug.LogError("ShopUI requires a UIDocument component");
  30. return;
  31. }
  32. InitializeUI();
  33. }
  34. void InitializeUI()
  35. {
  36. var root = uiDocument.rootVisualElement;
  37. shopContainer = root.Q<VisualElement>("ShopContainer");
  38. searchField = root.Q<TextField>("SearchField");
  39. categoryFilter = root.Q<DropdownField>("CategoryFilter");
  40. itemList = root.Q<ScrollView>("ItemList");
  41. shopTitle = root.Q<Label>("ShopTitle");
  42. playerMoney = root.Q<Label>("PlayerMoney");
  43. closeButton = root.Q<Button>("CloseButton");
  44. // Setup category filter
  45. if (categoryFilter != null)
  46. {
  47. categoryFilter.choices = new List<string> { "All", "Weapons", "Armor", "Miscellaneous" };
  48. categoryFilter.value = "All";
  49. categoryFilter.RegisterValueChangedCallback(OnCategoryChanged);
  50. }
  51. // Setup search field
  52. if (searchField != null)
  53. {
  54. searchField.RegisterValueChangedCallback(OnSearchChanged);
  55. }
  56. // Setup close button
  57. if (closeButton != null)
  58. {
  59. closeButton.clicked += CloseShop;
  60. }
  61. // Hide shop initially
  62. if (shopContainer != null)
  63. {
  64. shopContainer.style.display = DisplayStyle.None;
  65. }
  66. }
  67. public void OpenShop(Shop shop, Character character)
  68. {
  69. if (shop == null || character == null)
  70. {
  71. Debug.LogError("Cannot open shop: missing shop or character");
  72. return;
  73. }
  74. currentShop = shop;
  75. currentCharacter = character;
  76. currentBank = character.GetComponent<Bank>();
  77. currentInventory = character.GetComponent<Inventory>();
  78. if (currentBank == null)
  79. {
  80. Debug.LogError("Character must have a Bank component to use shop");
  81. return;
  82. }
  83. if (currentInventory == null)
  84. {
  85. Debug.LogError("Character must have an Inventory component to use shop");
  86. return;
  87. }
  88. // Update UI
  89. if (shopTitle != null)
  90. {
  91. shopTitle.text = shop.shopName;
  92. }
  93. UpdatePlayerMoney();
  94. RefreshItemList();
  95. // Show shop
  96. if (shopContainer != null)
  97. {
  98. shopContainer.style.display = DisplayStyle.Flex;
  99. }
  100. Debug.Log($"Opened {shop.shopName} for {character.CharacterName}");
  101. }
  102. public void CloseShop()
  103. {
  104. if (shopContainer != null)
  105. {
  106. shopContainer.style.display = DisplayStyle.None;
  107. }
  108. currentShop = null;
  109. currentCharacter = null;
  110. currentBank = null;
  111. currentInventory = null;
  112. Debug.Log("Closed shop");
  113. }
  114. private void OnCategoryChanged(ChangeEvent<string> evt)
  115. {
  116. switch (evt.newValue)
  117. {
  118. case "All":
  119. currentFilter = null;
  120. break;
  121. case "Weapons":
  122. currentFilter = ItemType.Weapon;
  123. break;
  124. case "Armor":
  125. currentFilter = ItemType.Armor;
  126. break;
  127. case "Miscellaneous":
  128. currentFilter = ItemType.Miscellaneous;
  129. break;
  130. }
  131. RefreshItemList();
  132. }
  133. private void OnSearchChanged(ChangeEvent<string> evt)
  134. {
  135. currentSearchTerm = evt.newValue;
  136. RefreshItemList();
  137. }
  138. private void RefreshItemList()
  139. {
  140. if (itemList == null || currentShop == null) return;
  141. itemList.Clear();
  142. var filteredItems = currentShop.GetFilteredItems(currentFilter, currentSearchTerm);
  143. foreach (var item in filteredItems)
  144. {
  145. var itemElement = CreateItemElement(item);
  146. itemList.Add(itemElement);
  147. }
  148. }
  149. private VisualElement CreateItemElement(Item item)
  150. {
  151. var container = new VisualElement();
  152. container.AddToClassList("shop-item");
  153. // Item info section
  154. var infoSection = new VisualElement();
  155. infoSection.AddToClassList("item-info");
  156. var nameLabel = new Label(item.itemName);
  157. nameLabel.AddToClassList("item-name");
  158. infoSection.Add(nameLabel);
  159. var descriptionLabel = new Label(item.description);
  160. descriptionLabel.AddToClassList("item-description");
  161. infoSection.Add(descriptionLabel);
  162. // Item stats section (for weapons/armor)
  163. if (item is WeaponItem weapon)
  164. {
  165. var statsLabel = new Label($"Damage: {weapon.minDamage}-{weapon.maxDamage}, Range: {weapon.range}, Speed: {weapon.attackSpeed:F1}s");
  166. statsLabel.AddToClassList("item-stats");
  167. infoSection.Add(statsLabel);
  168. }
  169. else if (item is ArmorItem armor)
  170. {
  171. var statsLabel = new Label($"AC: +{armor.armorClass}, Slot: {armor.armorSlot}");
  172. statsLabel.AddToClassList("item-stats");
  173. infoSection.Add(statsLabel);
  174. }
  175. container.Add(infoSection);
  176. // Price and buy section
  177. var buySection = new VisualElement();
  178. buySection.AddToClassList("buy-section");
  179. var priceLabel = new Label(item.GetCostString());
  180. priceLabel.AddToClassList("item-price");
  181. buySection.Add(priceLabel);
  182. var buyButton = new Button(() => PurchaseItem(item));
  183. buyButton.text = "Buy";
  184. buyButton.AddToClassList("buy-button");
  185. // Check if player can afford the item
  186. bool canAfford = item.CanAfford(currentBank);
  187. buyButton.SetEnabled(canAfford);
  188. if (!canAfford)
  189. {
  190. buyButton.AddToClassList("cannot-afford");
  191. buyButton.text = "Can't Afford";
  192. }
  193. buySection.Add(buyButton);
  194. container.Add(buySection);
  195. return container;
  196. }
  197. private void PurchaseItem(Item item)
  198. {
  199. if (currentBank == null || currentInventory == null || item == null)
  200. {
  201. Debug.LogError("Cannot purchase item: missing components");
  202. return;
  203. }
  204. if (!item.CanAfford(currentBank))
  205. {
  206. Debug.LogWarning($"Cannot afford {item.itemName}");
  207. return;
  208. }
  209. // Check if inventory has space
  210. if (!currentInventory.AddItem(item))
  211. {
  212. Debug.LogWarning($"No space in inventory for {item.itemName}");
  213. return;
  214. }
  215. // Complete the purchase
  216. item.Purchase(currentBank);
  217. UpdatePlayerMoney();
  218. RefreshItemList(); // Refresh to update affordability
  219. Debug.Log($"Purchased {item.itemName}");
  220. }
  221. private void UpdatePlayerMoney()
  222. {
  223. if (playerMoney != null && currentBank != null)
  224. {
  225. playerMoney.text = currentBank.GetCurrencyString();
  226. }
  227. }
  228. }