ItemShopManager.cs 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UIElements;
  5. using UnityEngine.SceneManagement;
  6. using System.Linq;
  7. public class ItemShopManager : MonoBehaviour
  8. {
  9. [Header("Shop Settings")]
  10. public string shopName = "General Store";
  11. [Header("Shop Items (ScriptableObjects)")]
  12. [SerializeField] private List<Item> availableItems = new List<Item>();
  13. private UIDocument uiDocument;
  14. private TeamCharacter currentCustomer;
  15. // Callback for when character data changes
  16. public System.Action<TeamCharacter> OnCharacterDataChanged;
  17. // UI Elements
  18. private VisualElement shopContainer;
  19. private TextField searchField;
  20. private DropdownField categoryFilter;
  21. private DropdownField customerDropdown;
  22. private ScrollView itemList;
  23. private Label shopTitle;
  24. private Label playerMoney;
  25. private Button closeButton;
  26. // Current filter state
  27. private string currentCategory = "All";
  28. private string currentSearchTerm = "";
  29. void Awake()
  30. {
  31. // Load all Item ScriptableObjects from Resources
  32. LoadAllItems();
  33. }
  34. void Start()
  35. {
  36. // Use a coroutine to delay initialization by one frame
  37. // This ensures other scripts that might modify UIDocument have finished
  38. StartCoroutine(DelayedInitialization());
  39. }
  40. private IEnumerator DelayedInitialization()
  41. {
  42. // Wait one frame to ensure all other Start() methods have completed
  43. yield return null;
  44. // Get all UIDocument components to debug
  45. UIDocument[] allUIDocuments = GetComponents<UIDocument>();
  46. Debug.Log($"Found {allUIDocuments.Length} UIDocument components on this GameObject");
  47. // Initialize UI in Start() to ensure UIDocument is ready
  48. uiDocument = GetComponent<UIDocument>();
  49. if (uiDocument == null)
  50. {
  51. Debug.LogWarning("ItemShopManager: No UIDocument component found. Shop UI will be initialized when needed.");
  52. // Try to find UIDocument on parent or children as fallback
  53. uiDocument = GetComponentInParent<UIDocument>();
  54. if (uiDocument == null)
  55. {
  56. uiDocument = GetComponentInChildren<UIDocument>();
  57. }
  58. if (uiDocument != null)
  59. {
  60. Debug.Log("Found UIDocument on parent/child, using that instead");
  61. }
  62. else
  63. {
  64. Debug.Log("No UIDocument found anywhere in hierarchy. Will create one when shop is opened.");
  65. yield break; // Exit gracefully instead of throwing an error
  66. }
  67. }
  68. if (uiDocument.visualTreeAsset == null)
  69. {
  70. Debug.LogWarning("ItemShopManager: UIDocument needs a Visual Tree Asset assigned! Will try to load when shop is opened.");
  71. yield break;
  72. }
  73. // Load and apply stylesheet
  74. var stylesheet = Resources.Load<StyleSheet>("UI/TownShopUI");
  75. if (stylesheet != null)
  76. {
  77. uiDocument.rootVisualElement.styleSheets.Add(stylesheet);
  78. Debug.Log("✓ ItemShopManager: Stylesheet loaded successfully");
  79. }
  80. else
  81. {
  82. Debug.LogWarning("⚠ ItemShopManager: Could not load TownShopUI stylesheet from Resources/UI/");
  83. }
  84. // Ensure panel settings and proper sorting order are set
  85. EnsurePanelSettings();
  86. InitializeUI();
  87. }
  88. void LoadAllItems()
  89. {
  90. availableItems.Clear();
  91. // Load all Item ScriptableObjects from Resources/Items folder and subfolders
  92. Item[] allItems = Resources.LoadAll<Item>("Items");
  93. if (allItems.Length == 0)
  94. {
  95. Debug.LogWarning("No Item ScriptableObjects found in Resources/Items folder. Creating some default items...");
  96. CreateDefaultItems();
  97. }
  98. else
  99. {
  100. availableItems.AddRange(allItems);
  101. }
  102. // Also check for items in the direct Resources folder
  103. Item[] directItems = Resources.LoadAll<Item>("");
  104. foreach (Item item in directItems)
  105. {
  106. if (!availableItems.Contains(item))
  107. {
  108. availableItems.Add(item);
  109. }
  110. }
  111. Debug.Log($"Total items available in shop: {availableItems.Count}");
  112. }
  113. void CreateDefaultItems()
  114. {
  115. // Create some default items if none are found
  116. // These will be temporary runtime items, but you should create proper ScriptableObject assets
  117. // Note: This creates runtime instances, not asset files
  118. var simpleSword = ScriptableObject.CreateInstance<WeaponItem>();
  119. simpleSword.itemName = "Basic Sword"; // Match actual asset name
  120. simpleSword.description = "A basic sword for beginners.";
  121. simpleSword.itemType = ItemType.Weapon;
  122. simpleSword.goldCost = 10;
  123. simpleSword.minDamage = 1;
  124. simpleSword.maxDamage = 6;
  125. simpleSword.weaponType = WeaponType.Sword;
  126. simpleSword.searchTags = new string[] { "sword", "melee", "blade", "basic" };
  127. availableItems.Add(simpleSword);
  128. var simpleBow = ScriptableObject.CreateInstance<WeaponItem>();
  129. simpleBow.itemName = "Basic Bow"; // Match actual asset name
  130. simpleBow.description = "A basic bow for shooting arrows.";
  131. simpleBow.itemType = ItemType.Weapon;
  132. simpleBow.goldCost = 15;
  133. simpleBow.minDamage = 1;
  134. simpleBow.maxDamage = 4;
  135. simpleBow.range = 150;
  136. simpleBow.weaponType = WeaponType.Bow;
  137. simpleBow.searchTags = new string[] { "bow", "ranged", "arrow", "basic" };
  138. availableItems.Add(simpleBow);
  139. var leatherArmor = ScriptableObject.CreateInstance<ArmorItem>();
  140. leatherArmor.itemName = "Leather Armor";
  141. leatherArmor.description = "Basic leather protection.";
  142. leatherArmor.itemType = ItemType.Armor;
  143. leatherArmor.goldCost = 12;
  144. leatherArmor.armorClass = 1;
  145. leatherArmor.armorType = ArmorType.Light;
  146. leatherArmor.armorSlot = ArmorSlot.Chest;
  147. leatherArmor.searchTags = new string[] { "leather", "armor", "chest", "light" };
  148. availableItems.Add(leatherArmor);
  149. var healthPotion = ScriptableObject.CreateInstance<MiscellaneousItem>();
  150. healthPotion.itemName = "Health Potion";
  151. healthPotion.description = "Restores health when consumed.";
  152. healthPotion.itemType = ItemType.Consumable;
  153. healthPotion.goldCost = 3;
  154. healthPotion.isConsumable = true;
  155. healthPotion.healthDiceCount = 1;
  156. healthPotion.healthDiceType = 6;
  157. healthPotion.healthBonus = 1;
  158. healthPotion.searchTags = new string[] { "potion", "health", "healing", "consumable" };
  159. availableItems.Add(healthPotion);
  160. Debug.Log("Created default runtime items since no ScriptableObject assets were found.");
  161. }
  162. private bool SetupUIDocument()
  163. {
  164. // Try to get UIDocument component
  165. uiDocument = GetComponent<UIDocument>();
  166. if (uiDocument == null)
  167. {
  168. // Add UIDocument component if it doesn't exist
  169. uiDocument = gameObject.AddComponent<UIDocument>();
  170. }
  171. // Try to load the TownShopUI asset
  172. var shopUIAsset = Resources.Load<VisualTreeAsset>("UI/TownShopUI");
  173. if (shopUIAsset == null)
  174. {
  175. Debug.LogError("Could not load TownShopUI.uxml from Resources/UI/");
  176. return false;
  177. }
  178. uiDocument.visualTreeAsset = shopUIAsset;
  179. // Load and apply stylesheet
  180. var stylesheet = Resources.Load<StyleSheet>("UI/TownShopUI");
  181. if (stylesheet != null)
  182. {
  183. uiDocument.rootVisualElement.styleSheets.Add(stylesheet);
  184. Debug.Log("✓ ItemShopManager: Stylesheet loaded successfully");
  185. }
  186. // Ensure panel settings
  187. EnsurePanelSettings();
  188. return true;
  189. }
  190. private void InitializeUI()
  191. {
  192. var root = uiDocument.rootVisualElement;
  193. // Use the correct element names from TownShopUI.uxml
  194. shopContainer = root.Q<VisualElement>("shop-container");
  195. searchField = root.Q<TextField>("search-field");
  196. categoryFilter = root.Q<DropdownField>("category-filter");
  197. customerDropdown = root.Q<DropdownField>("customer-dropdown");
  198. itemList = root.Q<ScrollView>("item-list");
  199. shopTitle = root.Q<Label>("shop-name");
  200. playerMoney = root.Q<Label>("money-label");
  201. closeButton = root.Q<Button>("close-button");
  202. // Debug which elements were found
  203. // Setup category filter
  204. if (categoryFilter != null)
  205. {
  206. categoryFilter.choices = new List<string> { "All", "Weapons", "Armor", "Consumables", "Tools", "Accessories", "Miscellaneous" };
  207. categoryFilter.value = "All";
  208. categoryFilter.RegisterValueChangedCallback(OnCategoryChanged);
  209. }
  210. // Setup customer dropdown (will be populated when opening shop)
  211. if (customerDropdown != null)
  212. {
  213. // Initialize with empty choices to prevent index errors
  214. customerDropdown.choices = new List<string>();
  215. customerDropdown.RegisterValueChangedCallback(OnCustomerChanged);
  216. }
  217. // Setup search field
  218. if (searchField != null)
  219. {
  220. searchField.RegisterValueChangedCallback(OnSearchChanged);
  221. }
  222. // Setup close button
  223. if (closeButton != null)
  224. {
  225. closeButton.clicked += CloseShop;
  226. }
  227. // Hide shop initially
  228. if (shopContainer != null)
  229. {
  230. shopContainer.style.display = DisplayStyle.None;
  231. Debug.Log("ItemShopManager: Shop initially hidden");
  232. }
  233. }
  234. public void OpenShop(TeamCharacter customer)
  235. {
  236. if (customer == null)
  237. {
  238. Debug.LogError("Cannot open shop: customer is null");
  239. return;
  240. }
  241. Debug.Log($"ItemShopManager: Opening shop for {customer.name}");
  242. // Ensure UIDocument is initialized
  243. if (uiDocument == null)
  244. {
  245. uiDocument = GetComponent<UIDocument>();
  246. }
  247. if (uiDocument == null)
  248. {
  249. Debug.LogError("ItemShopManager: UIDocument component not found! Please add a UIDocument component to this GameObject.");
  250. Debug.LogError($"GameObject name: {gameObject.name}");
  251. return;
  252. }
  253. if (uiDocument.visualTreeAsset == null)
  254. {
  255. Debug.LogError("ItemShopManager: UIDocument needs a Visual Tree Asset assigned! Please assign ShopUI.uxml");
  256. return;
  257. }
  258. // Ensure UI is initialized
  259. if (shopContainer == null)
  260. {
  261. Debug.Log("ItemShopManager: UI not initialized, attempting to set up...");
  262. // Try to set up UIDocument if not already done
  263. if (uiDocument == null)
  264. {
  265. if (!SetupUIDocument())
  266. {
  267. Debug.LogError("ItemShopManager: Could not set up UIDocument. Cannot open shop.");
  268. return;
  269. }
  270. }
  271. InitializeUI();
  272. }
  273. if (shopContainer == null)
  274. {
  275. Debug.LogError("ItemShopManager: shopContainer is null! Make sure TownShopUI.uxml is assigned to the UIDocument and contains a 'shop-container' element.");
  276. return;
  277. }
  278. currentCustomer = customer;
  279. // Update customer dropdown
  280. UpdateCustomerDropdown();
  281. // Update UI
  282. if (shopTitle != null)
  283. {
  284. shopTitle.text = shopName;
  285. }
  286. UpdatePlayerMoney();
  287. RefreshItemList();
  288. // Show shop
  289. if (shopContainer != null)
  290. {
  291. shopContainer.style.display = DisplayStyle.Flex;
  292. }
  293. Debug.Log($"Opened {shopName} for {customer.name}");
  294. }
  295. public void CloseShop()
  296. {
  297. if (shopContainer != null)
  298. {
  299. shopContainer.style.display = DisplayStyle.None;
  300. }
  301. currentCustomer = null;
  302. }
  303. private void OnCategoryChanged(ChangeEvent<string> evt)
  304. {
  305. currentCategory = evt.newValue;
  306. RefreshItemList();
  307. }
  308. private void OnSearchChanged(ChangeEvent<string> evt)
  309. {
  310. currentSearchTerm = evt.newValue;
  311. RefreshItemList();
  312. }
  313. private void RefreshItemList()
  314. {
  315. if (itemList == null) return;
  316. itemList.Clear();
  317. var filteredItems = GetFilteredItems();
  318. foreach (var item in filteredItems)
  319. {
  320. var itemElement = CreateItemElement(item);
  321. itemList.Add(itemElement);
  322. }
  323. }
  324. private List<Item> GetFilteredItems()
  325. {
  326. var filteredItems = new List<Item>(availableItems);
  327. // Apply category filter
  328. if (currentCategory != "All")
  329. {
  330. ItemType filterType;
  331. switch (currentCategory)
  332. {
  333. case "Weapons":
  334. filterType = ItemType.Weapon;
  335. break;
  336. case "Armor":
  337. filterType = ItemType.Armor;
  338. break;
  339. case "Consumables":
  340. filterType = ItemType.Consumable;
  341. break;
  342. case "Tools":
  343. filterType = ItemType.Tool;
  344. break;
  345. case "Accessories":
  346. filterType = ItemType.Accessory;
  347. break;
  348. case "Miscellaneous":
  349. filterType = ItemType.Miscellaneous;
  350. break;
  351. default:
  352. filterType = ItemType.Miscellaneous;
  353. break;
  354. }
  355. filteredItems = filteredItems.Where(item => item.itemType == filterType).ToList();
  356. }
  357. // Apply search filter
  358. if (!string.IsNullOrEmpty(currentSearchTerm))
  359. {
  360. filteredItems = filteredItems.Where(item => item.MatchesSearch(currentSearchTerm)).ToList();
  361. }
  362. return filteredItems;
  363. }
  364. private VisualElement CreateItemElement(Item item)
  365. {
  366. var itemContainer = new VisualElement();
  367. itemContainer.AddToClassList("shop-item");
  368. // Item name
  369. var nameLabel = new Label(item.itemName);
  370. nameLabel.AddToClassList("item-name");
  371. itemContainer.Add(nameLabel);
  372. // Item description with stats
  373. string description = item.description;
  374. string statsString = GetItemStatsString(item);
  375. if (!string.IsNullOrEmpty(statsString))
  376. {
  377. description += $" {statsString}";
  378. }
  379. var descriptionLabel = new Label(description);
  380. descriptionLabel.AddToClassList("item-description");
  381. itemContainer.Add(descriptionLabel);
  382. // Price and buy button container
  383. var priceButtonContainer = new VisualElement();
  384. priceButtonContainer.style.flexDirection = FlexDirection.Row;
  385. priceButtonContainer.style.justifyContent = Justify.SpaceBetween;
  386. priceButtonContainer.style.alignItems = Align.Center;
  387. var costLabel = new Label(item.GetCostString());
  388. costLabel.AddToClassList("item-price");
  389. priceButtonContainer.Add(costLabel);
  390. // Purchase button
  391. var purchaseButton = new Button(() => PurchaseItem(item));
  392. purchaseButton.text = "Buy";
  393. purchaseButton.AddToClassList("buy-button");
  394. priceButtonContainer.Add(purchaseButton);
  395. itemContainer.Add(priceButtonContainer);
  396. // Check if player can afford the item
  397. bool canAfford = currentCustomer != null && CanCustomerAfford(item);
  398. purchaseButton.SetEnabled(canAfford);
  399. if (!canAfford)
  400. {
  401. purchaseButton.AddToClassList("purchase-button-disabled");
  402. }
  403. itemContainer.Add(purchaseButton);
  404. return itemContainer;
  405. }
  406. private string GetItemStatsString(Item item)
  407. {
  408. var statStrings = new List<string>();
  409. if (item is WeaponItem weapon)
  410. {
  411. statStrings.Add($"Damage: {weapon.minDamage}-{weapon.maxDamage}");
  412. if (weapon.range > 0)
  413. statStrings.Add($"Range: {weapon.range}");
  414. if (weapon.weaponModifier != 0)
  415. statStrings.Add($"Weapon Mod: {weapon.weaponModifier:+0;-0}");
  416. }
  417. else if (item is ArmorItem armor)
  418. {
  419. if (armor.armorClass > 0)
  420. statStrings.Add($"AC: +{armor.armorClass}");
  421. if (armor.strengthModifier != 0)
  422. statStrings.Add($"STR: {armor.strengthModifier:+0;-0}");
  423. if (armor.dexterityModifier != 0)
  424. statStrings.Add($"DEX: {armor.dexterityModifier:+0;-0}");
  425. if (armor.constitutionModifier != 0)
  426. statStrings.Add($"CON: {armor.constitutionModifier:+0;-0}");
  427. if (armor.wisdomModifier != 0)
  428. statStrings.Add($"WIS: {armor.wisdomModifier:+0;-0}");
  429. }
  430. else if (item is MiscellaneousItem misc && misc.isConsumable)
  431. {
  432. if (misc.healthDiceCount > 0)
  433. {
  434. string healthEffect = $"Heals {misc.healthDiceCount}d{misc.healthDiceType}";
  435. if (misc.healthBonus != 0)
  436. healthEffect += $"{misc.healthBonus:+0;-0}";
  437. statStrings.Add(healthEffect);
  438. }
  439. else if (misc.healthRestoreMin > 0 || misc.healthRestoreMax > 0)
  440. {
  441. statStrings.Add($"Heals {misc.healthRestoreMin}-{misc.healthRestoreMax}");
  442. }
  443. if (misc.manaDiceCount > 0)
  444. {
  445. string manaEffect = $"Restores {misc.manaDiceCount}d{misc.manaDiceType}";
  446. if (misc.manaBonus != 0)
  447. manaEffect += $"{misc.manaBonus:+0;-0}";
  448. statStrings.Add($"{manaEffect} mana");
  449. }
  450. else if (misc.manaRestoreMin > 0 || misc.manaRestoreMax > 0)
  451. {
  452. statStrings.Add($"Restores {misc.manaRestoreMin}-{misc.manaRestoreMax} mana");
  453. }
  454. }
  455. return statStrings.Count > 0 ? string.Join(", ", statStrings) : "";
  456. }
  457. private void PurchaseItem(Item item)
  458. {
  459. if (currentCustomer == null)
  460. {
  461. Debug.LogError("No customer set!");
  462. return;
  463. }
  464. // Check if customer can afford the item directly
  465. if (!CanCustomerAfford(item))
  466. {
  467. Debug.LogWarning($"Cannot afford {item.itemName}");
  468. return;
  469. }
  470. // Calculate and deduct the cost
  471. DeductItemCost(item);
  472. // Add item to customer's inventory (you'll need to implement this based on your inventory system)
  473. AddItemToCustomerInventory(item);
  474. // Refresh UI
  475. UpdatePlayerMoney();
  476. RefreshItemList();
  477. // Notify listeners that character data changed
  478. OnCharacterDataChanged?.Invoke(currentCustomer);
  479. Debug.Log($"Successfully purchased {item.itemName}");
  480. }
  481. private bool CanCustomerAfford(Item item)
  482. {
  483. if (currentCustomer == null) return false;
  484. int totalCopperCost = item.goldCost * 100 + item.silverCost * 10 + item.copperCost;
  485. int totalCopperAvailable = currentCustomer.gold * 100 + currentCustomer.silver * 10 + currentCustomer.copper;
  486. return totalCopperAvailable >= totalCopperCost;
  487. }
  488. private void DeductItemCost(Item item)
  489. {
  490. // Convert everything to copper for easier calculation
  491. int totalCopperCost = item.goldCost * 100 + item.silverCost * 10 + item.copperCost;
  492. int totalCopperAvailable = currentCustomer.gold * 100 + currentCustomer.silver * 10 + currentCustomer.copper;
  493. int remainingCopper = totalCopperAvailable - totalCopperCost;
  494. // Convert back to gold, silver, copper
  495. currentCustomer.gold = remainingCopper / 100;
  496. remainingCopper %= 100;
  497. currentCustomer.silver = remainingCopper / 10;
  498. currentCustomer.copper = remainingCopper % 10;
  499. Debug.Log($"Purchased {item.itemName} for {item.goldCost}g {item.silverCost}s {item.copperCost}c");
  500. }
  501. private void AddItemToCustomerInventory(Item item)
  502. {
  503. if (currentCustomer == null) return;
  504. // Initialize lists if they're null
  505. if (currentCustomer.weapons == null)
  506. currentCustomer.weapons = new System.Collections.Generic.List<string>();
  507. if (currentCustomer.armor == null)
  508. currentCustomer.armor = new System.Collections.Generic.List<string>();
  509. if (currentCustomer.miscItems == null)
  510. currentCustomer.miscItems = new System.Collections.Generic.List<string>();
  511. // Add item to appropriate inventory list based on type
  512. switch (item.itemType)
  513. {
  514. case ItemType.Weapon:
  515. currentCustomer.weapons.Add(item.itemName);
  516. break;
  517. case ItemType.Armor:
  518. currentCustomer.armor.Add(item.itemName);
  519. break;
  520. case ItemType.Miscellaneous:
  521. case ItemType.Consumable:
  522. case ItemType.Tool:
  523. case ItemType.Accessory:
  524. currentCustomer.miscItems.Add(item.itemName);
  525. break;
  526. default:
  527. currentCustomer.miscItems.Add(item.itemName);
  528. if (Application.isEditor) Debug.LogWarning($"Unknown item type for '{item.itemName}', added to misc items");
  529. break;
  530. }
  531. // Trigger UI update in MainTeamSelectScript if available
  532. TriggerInventoryUIUpdate();
  533. }
  534. private void TriggerInventoryUIUpdate()
  535. {
  536. // The OnCharacterDataChanged event is already invoked in PurchaseItem()
  537. // This should trigger any listeners to update their UI
  538. // MainTeamSelectScript should listen to this event to refresh inventory displays
  539. Debug.Log("Character inventory updated - OnCharacterDataChanged event will be triggered");
  540. }
  541. private void UpdatePlayerMoney()
  542. {
  543. if (playerMoney != null && currentCustomer != null)
  544. {
  545. playerMoney.text = $"{currentCustomer.gold}g {currentCustomer.silver}s {currentCustomer.copper}c";
  546. }
  547. }
  548. [ContextMenu("Reload Items")]
  549. public void ReloadItems()
  550. {
  551. LoadAllItems();
  552. if (shopContainer != null && shopContainer.style.display == DisplayStyle.Flex)
  553. {
  554. RefreshItemList();
  555. }
  556. }
  557. // Public methods to get items by category (for compatibility with old system)
  558. public List<Item> GetWeapons()
  559. {
  560. return availableItems.Where(item => item.itemType == ItemType.Weapon).ToList();
  561. }
  562. public List<Item> GetArmor()
  563. {
  564. return availableItems.Where(item => item.itemType == ItemType.Armor).ToList();
  565. }
  566. public List<Item> GetMiscItems()
  567. {
  568. return availableItems.Where(item =>
  569. item.itemType == ItemType.Miscellaneous ||
  570. item.itemType == ItemType.Consumable ||
  571. item.itemType == ItemType.Tool ||
  572. item.itemType == ItemType.Accessory).ToList();
  573. }
  574. public List<Item> GetAllItems()
  575. {
  576. return new List<Item>(availableItems);
  577. }
  578. [ContextMenu("Check Shop Setup")]
  579. public void CheckShopSetup()
  580. {
  581. Debug.Log("=== ItemShopManager Setup Check ===");
  582. // Check UIDocument
  583. var uiDoc = GetComponent<UIDocument>();
  584. if (uiDoc == null)
  585. {
  586. Debug.LogError("❌ No UIDocument component found on this GameObject!");
  587. Debug.LogError("➤ Add a UIDocument component to fix this.");
  588. return;
  589. }
  590. else
  591. {
  592. Debug.Log("✓ UIDocument component found");
  593. }
  594. // Check Visual Tree Asset
  595. if (uiDoc.visualTreeAsset == null)
  596. {
  597. Debug.LogError("❌ UIDocument has no Visual Tree Asset assigned!");
  598. Debug.LogError("➤ Assign ShopUI.uxml to the UIDocument component.");
  599. return;
  600. }
  601. else
  602. {
  603. Debug.Log($"✓ Visual Tree Asset assigned: {uiDoc.visualTreeAsset.name}");
  604. }
  605. // Check UI elements
  606. var root = uiDoc.rootVisualElement;
  607. var container = root?.Q<VisualElement>("ShopContainer");
  608. if (container == null)
  609. {
  610. Debug.LogError("❌ ShopContainer element not found in the UXML!");
  611. Debug.LogError("➤ Make sure you're using the correct ShopUI.uxml file.");
  612. return;
  613. }
  614. else
  615. {
  616. Debug.Log("✓ ShopContainer element found in UXML");
  617. }
  618. // Check items
  619. Debug.Log($"✓ {availableItems.Count} items loaded for shop");
  620. Debug.Log("=== Setup Check Complete - Shop should work! ===");
  621. }
  622. [ContextMenu("Force Initialize UI")]
  623. public void ForceInitializeUI()
  624. {
  625. uiDocument = GetComponent<UIDocument>();
  626. if (uiDocument != null && uiDocument.visualTreeAsset != null)
  627. {
  628. InitializeUI();
  629. Debug.Log("UI forcefully initialized");
  630. }
  631. else
  632. {
  633. Debug.LogError("Cannot initialize UI - missing UIDocument or Visual Tree Asset");
  634. }
  635. }
  636. [ContextMenu("Debug UI State")]
  637. public void DebugUIState()
  638. {
  639. Debug.Log("=== UI State Debug ===");
  640. if (uiDocument == null)
  641. {
  642. Debug.LogError("uiDocument is null");
  643. return;
  644. }
  645. Debug.Log($"UIDocument sorting order: {uiDocument.sortingOrder}");
  646. if (uiDocument.panelSettings != null)
  647. {
  648. Debug.Log($"Panel settings sorting order: {uiDocument.panelSettings.sortingOrder}");
  649. }
  650. else
  651. {
  652. Debug.LogWarning("Panel settings is null");
  653. }
  654. var root = uiDocument.rootVisualElement;
  655. Debug.Log($"Root element child count: {root.childCount}");
  656. if (shopContainer != null)
  657. {
  658. Debug.Log($"Shop container display: {shopContainer.style.display}");
  659. Debug.Log($"Shop container resolved display: {shopContainer.resolvedStyle.display}");
  660. Debug.Log($"Shop container visible: {shopContainer.visible}");
  661. Debug.Log($"Shop container opacity: {shopContainer.resolvedStyle.opacity}");
  662. Debug.Log($"Shop container position: {shopContainer.style.position}");
  663. Debug.Log($"Shop container worldBound: {shopContainer.worldBound}");
  664. }
  665. else
  666. {
  667. Debug.LogError("shopContainer is null");
  668. }
  669. // Check for other UIDocuments that might be covering this one
  670. var allUIDocuments = FindObjectsByType<UIDocument>(FindObjectsSortMode.None);
  671. Debug.Log($"Found {allUIDocuments.Length} UIDocuments in scene:");
  672. foreach (var doc in allUIDocuments)
  673. {
  674. var panelSort = doc.panelSettings?.sortingOrder ?? -999;
  675. Debug.Log($" - '{doc.gameObject.name}' sortingOrder: {doc.sortingOrder}, panelSettings: {panelSort}");
  676. }
  677. }
  678. [ContextMenu("Force Open Shop (Test)")]
  679. public void ForceOpenShopTest()
  680. {
  681. // Create a test character for debugging
  682. var testCharacter = new TeamCharacter();
  683. testCharacter.name = "Test Character";
  684. testCharacter.gold = 100;
  685. testCharacter.silver = 50;
  686. testCharacter.copper = 25;
  687. Debug.Log("Opening shop with test character...");
  688. OpenShop(testCharacter);
  689. }
  690. void EnsurePanelSettings()
  691. {
  692. if (uiDocument.panelSettings == null || uiDocument.sortingOrder <= 2)
  693. {
  694. // Try to find and reuse existing panel settings from other UI
  695. var existingUI = GameObject.Find("TravelUI")?.GetComponent<UIDocument>();
  696. if (existingUI?.panelSettings != null)
  697. {
  698. uiDocument.panelSettings = existingUI.panelSettings;
  699. Debug.Log("✓ ItemShopManager: Panel Settings assigned from TravelUI");
  700. }
  701. else
  702. {
  703. // Try to find from MainTeamSelectScript or other UI components
  704. var mainTeamSelect = FindFirstObjectByType<MainTeamSelectScript>();
  705. if (mainTeamSelect != null)
  706. {
  707. var mainUIDoc = mainTeamSelect.GetComponent<UIDocument>();
  708. if (mainUIDoc?.panelSettings != null)
  709. {
  710. uiDocument.panelSettings = mainUIDoc.panelSettings;
  711. Debug.Log("✓ ItemShopManager: Panel Settings assigned from MainTeamSelectScript");
  712. }
  713. }
  714. }
  715. // Set proper sorting order (> 2 as requested)
  716. uiDocument.sortingOrder = 5; // Higher than 2 to ensure shop displays on top
  717. if (uiDocument.panelSettings != null)
  718. {
  719. // Make sure panel settings also have a high sorting order
  720. uiDocument.panelSettings.sortingOrder = 5;
  721. Debug.Log($"✓ ItemShopManager: Sorting order set to {uiDocument.sortingOrder}");
  722. }
  723. else
  724. {
  725. Debug.LogWarning("⚠ ItemShopManager: Could not assign Panel Settings. Shop may not display properly.");
  726. }
  727. }
  728. }
  729. private void OnCustomerChanged(ChangeEvent<string> evt)
  730. {
  731. // When customer is changed from dropdown, find the corresponding TeamCharacter
  732. string selectedName = evt.newValue;
  733. // Skip if no valid selection or error states
  734. if (string.IsNullOrEmpty(selectedName) || selectedName == "No Customer" || selectedName.StartsWith("Error"))
  735. {
  736. Debug.Log("Customer dropdown selection is invalid, skipping");
  737. return;
  738. }
  739. // Try to find the character from different sources depending on the scene
  740. TeamCharacter selectedCharacter = FindCharacterByName(selectedName);
  741. if (selectedCharacter != null)
  742. {
  743. currentCustomer = selectedCharacter;
  744. UpdatePlayerMoney();
  745. Debug.Log($"Customer changed to: {selectedCharacter.name}");
  746. }
  747. else
  748. {
  749. Debug.LogWarning($"Could not find character with name: {selectedName}");
  750. }
  751. }
  752. private void UpdateCustomerDropdown()
  753. {
  754. if (customerDropdown == null)
  755. {
  756. Debug.LogWarning("CustomerDropdown is null, cannot update");
  757. return;
  758. }
  759. List<string> customerOptions = new List<string>();
  760. try
  761. {
  762. // Check what scene we're in and populate accordingly
  763. if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "MainTeamSelectScene" ||
  764. GameObject.Find("MainTeamSelectScript") != null)
  765. {
  766. // In MainTeamSelectScene - populate with team members
  767. var mainTeamSelect = FindFirstObjectByType<MainTeamSelectScript>();
  768. if (mainTeamSelect != null)
  769. {
  770. var configuredCharacters = mainTeamSelect.GetConfiguredCharacters();
  771. if (configuredCharacters != null)
  772. {
  773. foreach (var character in configuredCharacters)
  774. {
  775. if (character != null && !string.IsNullOrEmpty(character.name))
  776. {
  777. customerOptions.Add(character.name);
  778. }
  779. }
  780. }
  781. }
  782. // If no team members found, just add the current customer
  783. if (customerOptions.Count == 0 && currentCustomer != null && !string.IsNullOrEmpty(currentCustomer.name))
  784. {
  785. customerOptions.Add(currentCustomer.name);
  786. }
  787. }
  788. else
  789. {
  790. // In TownScene or other scenes - use GameStateManager or other sources
  791. if (GameStateManager.Instance?.savedTeam != null)
  792. {
  793. foreach (var character in GameStateManager.Instance.savedTeam)
  794. {
  795. if (character != null && !string.IsNullOrEmpty(character.name))
  796. {
  797. customerOptions.Add(character.name);
  798. }
  799. }
  800. }
  801. // Fallback to current customer
  802. if (customerOptions.Count == 0 && currentCustomer != null && !string.IsNullOrEmpty(currentCustomer.name))
  803. {
  804. customerOptions.Add(currentCustomer.name);
  805. }
  806. }
  807. // Ensure we have at least one option
  808. if (customerOptions.Count == 0)
  809. {
  810. customerOptions.Add("No Customer");
  811. }
  812. // Set the dropdown options
  813. customerDropdown.choices = customerOptions;
  814. // Set the current selection safely
  815. if (currentCustomer != null && !string.IsNullOrEmpty(currentCustomer.name) && customerOptions.Contains(currentCustomer.name))
  816. {
  817. customerDropdown.value = currentCustomer.name;
  818. }
  819. else if (customerOptions.Count > 0)
  820. {
  821. customerDropdown.value = customerOptions[0];
  822. }
  823. Debug.Log($"Customer dropdown populated with {customerOptions.Count} customers: {string.Join(", ", customerOptions)}");
  824. }
  825. catch (System.Exception ex)
  826. {
  827. Debug.LogError($"Error updating customer dropdown: {ex.Message}");
  828. // Fallback to safe state
  829. customerDropdown.choices = new List<string> { "Error - No Customer" };
  830. customerDropdown.value = "Error - No Customer";
  831. }
  832. }
  833. private TeamCharacter FindCharacterByName(string characterName)
  834. {
  835. // Try MainTeamSelectScript first
  836. var mainTeamSelect = FindFirstObjectByType<MainTeamSelectScript>();
  837. if (mainTeamSelect != null)
  838. {
  839. var configuredCharacters = mainTeamSelect.GetConfiguredCharacters();
  840. foreach (var character in configuredCharacters)
  841. {
  842. if (character != null && character.name == characterName)
  843. {
  844. return character;
  845. }
  846. }
  847. }
  848. // Try GameStateManager
  849. if (GameStateManager.Instance?.savedTeam != null)
  850. {
  851. foreach (var character in GameStateManager.Instance.savedTeam)
  852. {
  853. if (character != null && character.name == characterName)
  854. {
  855. return character;
  856. }
  857. }
  858. }
  859. return null;
  860. }
  861. }