| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Linq;
- public class ItemShopManager : MonoBehaviour
- {
- [Header("Shop Settings")]
- public string shopName = "General Store";
- [Header("Shop Items (ScriptableObjects)")]
- [SerializeField] private List<Item> availableItems = new List<Item>();
- private UIDocument uiDocument;
- private TeamCharacter currentCustomer;
- // Callback for when character data changes
- public System.Action<TeamCharacter> OnCharacterDataChanged;
- // UI Elements
- private VisualElement shopContainer;
- private TextField searchField;
- private DropdownField categoryFilter;
- private ScrollView itemList;
- private Label shopTitle;
- private Label playerMoney;
- private Button closeButton;
- // Current filter state
- private string currentCategory = "All";
- private string currentSearchTerm = "";
- void Awake()
- {
- // Load all Item ScriptableObjects from Resources
- LoadAllItems();
- }
- void Start()
- {
- // Initialize UI in Start() to ensure UIDocument is ready
- uiDocument = GetComponent<UIDocument>();
- if (uiDocument == null)
- {
- Debug.LogError("ItemShopManager requires a UIDocument component");
- return;
- }
- if (uiDocument.visualTreeAsset == null)
- {
- Debug.LogError("ItemShopManager: UIDocument needs a Visual Tree Asset assigned! Please assign ShopUI.uxml");
- return;
- }
- InitializeUI();
- }
- void LoadAllItems()
- {
- availableItems.Clear();
- // Load all Item ScriptableObjects from Resources/Items folder and subfolders
- Item[] allItems = Resources.LoadAll<Item>("Items");
- if (allItems.Length == 0)
- {
- Debug.LogWarning("No Item ScriptableObjects found in Resources/Items folder. Creating some default items...");
- CreateDefaultItems();
- }
- else
- {
- availableItems.AddRange(allItems);
- Debug.Log($"Loaded {allItems.Length} items from Resources/Items folder");
- }
- // Also check for items in the direct Resources folder
- Item[] directItems = Resources.LoadAll<Item>("");
- foreach (Item item in directItems)
- {
- if (!availableItems.Contains(item))
- {
- availableItems.Add(item);
- }
- }
- Debug.Log($"Total items available in shop: {availableItems.Count}");
- foreach (Item item in availableItems)
- {
- Debug.Log($"- {item.itemName} ({item.itemType})");
- }
- }
- void CreateDefaultItems()
- {
- // Create some default items if none are found
- // These will be temporary runtime items, but you should create proper ScriptableObject assets
- // Note: This creates runtime instances, not asset files
- var simpleSword = ScriptableObject.CreateInstance<WeaponItem>();
- simpleSword.itemName = "Simple Sword";
- simpleSword.description = "A basic sword for beginners.";
- simpleSword.itemType = ItemType.Weapon;
- simpleSword.goldCost = 10;
- simpleSword.minDamage = 1;
- simpleSword.maxDamage = 6;
- simpleSword.weaponType = WeaponType.Sword;
- simpleSword.searchTags = new string[] { "sword", "melee", "blade", "basic" };
- availableItems.Add(simpleSword);
- var simpleBow = ScriptableObject.CreateInstance<WeaponItem>();
- simpleBow.itemName = "Simple Bow";
- simpleBow.description = "A basic bow for shooting arrows.";
- simpleBow.itemType = ItemType.Weapon;
- simpleBow.goldCost = 15;
- simpleBow.minDamage = 1;
- simpleBow.maxDamage = 4;
- simpleBow.range = 150;
- simpleBow.weaponType = WeaponType.Bow;
- simpleBow.searchTags = new string[] { "bow", "ranged", "arrow", "basic" };
- availableItems.Add(simpleBow);
- var leatherArmor = ScriptableObject.CreateInstance<ArmorItem>();
- leatherArmor.itemName = "Leather Armor";
- leatherArmor.description = "Basic leather protection.";
- leatherArmor.itemType = ItemType.Armor;
- leatherArmor.goldCost = 12;
- leatherArmor.armorClass = 1;
- leatherArmor.armorType = ArmorType.Light;
- leatherArmor.armorSlot = ArmorSlot.Chest;
- leatherArmor.searchTags = new string[] { "leather", "armor", "chest", "light" };
- availableItems.Add(leatherArmor);
- var healthPotion = ScriptableObject.CreateInstance<MiscellaneousItem>();
- healthPotion.itemName = "Health Potion";
- healthPotion.description = "Restores health when consumed.";
- healthPotion.itemType = ItemType.Consumable;
- healthPotion.goldCost = 3;
- healthPotion.isConsumable = true;
- healthPotion.healthDiceCount = 1;
- healthPotion.healthDiceType = 6;
- healthPotion.healthBonus = 1;
- healthPotion.searchTags = new string[] { "potion", "health", "healing", "consumable" };
- availableItems.Add(healthPotion);
- Debug.Log("Created default runtime items since no ScriptableObject assets were found.");
- }
- void InitializeUI()
- {
- var root = uiDocument.rootVisualElement;
- Debug.Log("ItemShopManager: Initializing UI elements...");
- shopContainer = root.Q<VisualElement>("ShopContainer");
- searchField = root.Q<TextField>("SearchField");
- categoryFilter = root.Q<DropdownField>("CategoryFilter");
- itemList = root.Q<ScrollView>("ItemList");
- shopTitle = root.Q<Label>("ShopTitle");
- playerMoney = root.Q<Label>("PlayerMoney");
- closeButton = root.Q<Button>("CloseButton");
- // Debug which elements were found
- Debug.Log($"ShopContainer found: {shopContainer != null}");
- Debug.Log($"SearchField found: {searchField != null}");
- Debug.Log($"CategoryFilter found: {categoryFilter != null}");
- Debug.Log($"ItemList found: {itemList != null}");
- Debug.Log($"ShopTitle found: {shopTitle != null}");
- Debug.Log($"PlayerMoney found: {playerMoney != null}");
- Debug.Log($"CloseButton found: {closeButton != null}");
- // Setup category filter
- if (categoryFilter != null)
- {
- categoryFilter.choices = new List<string> { "All", "Weapons", "Armor", "Consumables", "Tools", "Accessories", "Miscellaneous" };
- categoryFilter.value = "All";
- categoryFilter.RegisterValueChangedCallback(OnCategoryChanged);
- }
- // Setup search field
- if (searchField != null)
- {
- searchField.RegisterValueChangedCallback(OnSearchChanged);
- }
- // Setup close button
- if (closeButton != null)
- {
- closeButton.clicked += CloseShop;
- }
- // Hide shop initially
- if (shopContainer != null)
- {
- shopContainer.style.display = DisplayStyle.None;
- Debug.Log("ItemShopManager: Shop initially hidden");
- }
- }
- public void OpenShop(TeamCharacter customer)
- {
- if (customer == null)
- {
- Debug.LogError("Cannot open shop: customer is null");
- return;
- }
- Debug.Log($"ItemShopManager: Opening shop for {customer.name}");
- // Ensure UIDocument is initialized
- if (uiDocument == null)
- {
- uiDocument = GetComponent<UIDocument>();
- }
- if (uiDocument == null)
- {
- Debug.LogError("ItemShopManager: UIDocument component not found! Please add a UIDocument component to this GameObject.");
- Debug.LogError($"GameObject name: {gameObject.name}");
- return;
- }
- if (uiDocument.visualTreeAsset == null)
- {
- Debug.LogError("ItemShopManager: UIDocument needs a Visual Tree Asset assigned! Please assign ShopUI.uxml");
- return;
- }
- // Ensure UI is initialized
- if (shopContainer == null)
- {
- Debug.Log("ItemShopManager: UI not initialized, initializing now...");
- InitializeUI();
- }
- if (shopContainer == null)
- {
- Debug.LogError("ItemShopManager: shopContainer is null! Make sure ShopUI.uxml is assigned to the UIDocument and contains a 'ShopContainer' element.");
- return;
- }
- currentCustomer = customer;
- // Update UI
- if (shopTitle != null)
- {
- shopTitle.text = shopName;
- }
- UpdatePlayerMoney();
- RefreshItemList();
- // Show shop
- if (shopContainer != null)
- {
- shopContainer.style.display = DisplayStyle.Flex;
- Debug.Log("ItemShopManager: Shop container visibility set to Flex");
- // Additional debugging
- Debug.Log($"Shop container style.display: {shopContainer.style.display}");
- Debug.Log($"Shop container resolvedStyle.display: {shopContainer.resolvedStyle.display}");
- Debug.Log($"Shop container visible: {shopContainer.visible}");
- Debug.Log($"Shop container position: {shopContainer.style.position}");
- Debug.Log($"Shop container width: {shopContainer.resolvedStyle.width}");
- Debug.Log($"Shop container height: {shopContainer.resolvedStyle.height}");
- }
- Debug.Log($"Opened {shopName} for {customer.name}");
- }
- public void CloseShop()
- {
- if (shopContainer != null)
- {
- shopContainer.style.display = DisplayStyle.None;
- }
- currentCustomer = null;
- Debug.Log("Closed shop");
- }
- private void OnCategoryChanged(ChangeEvent<string> evt)
- {
- currentCategory = evt.newValue;
- RefreshItemList();
- }
- private void OnSearchChanged(ChangeEvent<string> evt)
- {
- currentSearchTerm = evt.newValue;
- RefreshItemList();
- }
- private void RefreshItemList()
- {
- if (itemList == null) return;
- itemList.Clear();
- var filteredItems = GetFilteredItems();
- foreach (var item in filteredItems)
- {
- var itemElement = CreateItemElement(item);
- itemList.Add(itemElement);
- }
- }
- private List<Item> GetFilteredItems()
- {
- var filteredItems = new List<Item>(availableItems);
- // Apply category filter
- if (currentCategory != "All")
- {
- ItemType filterType;
- switch (currentCategory)
- {
- case "Weapons":
- filterType = ItemType.Weapon;
- break;
- case "Armor":
- filterType = ItemType.Armor;
- break;
- case "Consumables":
- filterType = ItemType.Consumable;
- break;
- case "Tools":
- filterType = ItemType.Tool;
- break;
- case "Accessories":
- filterType = ItemType.Accessory;
- break;
- case "Miscellaneous":
- filterType = ItemType.Miscellaneous;
- break;
- default:
- filterType = ItemType.Miscellaneous;
- break;
- }
- filteredItems = filteredItems.Where(item => item.itemType == filterType).ToList();
- }
- // Apply search filter
- if (!string.IsNullOrEmpty(currentSearchTerm))
- {
- filteredItems = filteredItems.Where(item => item.MatchesSearch(currentSearchTerm)).ToList();
- }
- return filteredItems;
- }
- private VisualElement CreateItemElement(Item item)
- {
- var itemContainer = new VisualElement();
- itemContainer.AddToClassList("shop-item");
- // Item header with name and cost
- var header = new VisualElement();
- header.AddToClassList("item-header");
- header.style.flexDirection = FlexDirection.Row;
- header.style.justifyContent = Justify.SpaceBetween;
- var nameLabel = new Label(item.itemName);
- nameLabel.AddToClassList("item-name");
- header.Add(nameLabel);
- var costLabel = new Label(item.GetCostString());
- costLabel.AddToClassList("item-cost");
- header.Add(costLabel);
- itemContainer.Add(header);
- // Item description
- var descriptionLabel = new Label(item.description);
- descriptionLabel.AddToClassList("item-description");
- descriptionLabel.style.whiteSpace = WhiteSpace.Normal;
- itemContainer.Add(descriptionLabel);
- // Item stats (if applicable)
- string statsString = GetItemStatsString(item);
- if (!string.IsNullOrEmpty(statsString))
- {
- var statsLabel = new Label(statsString);
- statsLabel.AddToClassList("item-stats");
- itemContainer.Add(statsLabel);
- }
- // Purchase button
- var purchaseButton = new Button(() => PurchaseItem(item));
- purchaseButton.text = "Buy";
- purchaseButton.AddToClassList("purchase-button");
- // Check if player can afford the item
- bool canAfford = currentCustomer != null && CanCustomerAfford(item);
- purchaseButton.SetEnabled(canAfford);
- if (!canAfford)
- {
- purchaseButton.AddToClassList("purchase-button-disabled");
- }
- itemContainer.Add(purchaseButton);
- return itemContainer;
- }
- private string GetItemStatsString(Item item)
- {
- var statStrings = new List<string>();
- if (item is WeaponItem weapon)
- {
- statStrings.Add($"Damage: {weapon.minDamage}-{weapon.maxDamage}");
- if (weapon.range > 0)
- statStrings.Add($"Range: {weapon.range}");
- if (weapon.weaponModifier != 0)
- statStrings.Add($"Weapon Mod: {weapon.weaponModifier:+0;-0}");
- }
- else if (item is ArmorItem armor)
- {
- if (armor.armorClass > 0)
- statStrings.Add($"AC: +{armor.armorClass}");
- if (armor.strengthModifier != 0)
- statStrings.Add($"STR: {armor.strengthModifier:+0;-0}");
- if (armor.dexterityModifier != 0)
- statStrings.Add($"DEX: {armor.dexterityModifier:+0;-0}");
- if (armor.constitutionModifier != 0)
- statStrings.Add($"CON: {armor.constitutionModifier:+0;-0}");
- if (armor.wisdomModifier != 0)
- statStrings.Add($"WIS: {armor.wisdomModifier:+0;-0}");
- }
- else if (item is MiscellaneousItem misc && misc.isConsumable)
- {
- if (misc.healthDiceCount > 0)
- {
- string healthEffect = $"Heals {misc.healthDiceCount}d{misc.healthDiceType}";
- if (misc.healthBonus != 0)
- healthEffect += $"{misc.healthBonus:+0;-0}";
- statStrings.Add(healthEffect);
- }
- else if (misc.healthRestoreMin > 0 || misc.healthRestoreMax > 0)
- {
- statStrings.Add($"Heals {misc.healthRestoreMin}-{misc.healthRestoreMax}");
- }
- if (misc.manaDiceCount > 0)
- {
- string manaEffect = $"Restores {misc.manaDiceCount}d{misc.manaDiceType}";
- if (misc.manaBonus != 0)
- manaEffect += $"{misc.manaBonus:+0;-0}";
- statStrings.Add($"{manaEffect} mana");
- }
- else if (misc.manaRestoreMin > 0 || misc.manaRestoreMax > 0)
- {
- statStrings.Add($"Restores {misc.manaRestoreMin}-{misc.manaRestoreMax} mana");
- }
- }
- return statStrings.Count > 0 ? string.Join(", ", statStrings) : "";
- }
- private void PurchaseItem(Item item)
- {
- if (currentCustomer == null)
- {
- Debug.LogError("No customer set!");
- return;
- }
- // Check if customer can afford the item directly
- if (!CanCustomerAfford(item))
- {
- Debug.LogWarning($"Cannot afford {item.itemName}");
- return;
- }
- // Calculate and deduct the cost
- DeductItemCost(item);
- // Add item to customer's inventory (you'll need to implement this based on your inventory system)
- AddItemToCustomerInventory(item);
- // Refresh UI
- UpdatePlayerMoney();
- RefreshItemList();
- // Notify listeners that character data changed
- OnCharacterDataChanged?.Invoke(currentCustomer);
- Debug.Log($"Successfully purchased {item.itemName}");
- }
- private bool CanCustomerAfford(Item item)
- {
- if (currentCustomer == null) return false;
- int totalCopperCost = item.goldCost * 100 + item.silverCost * 10 + item.copperCost;
- int totalCopperAvailable = currentCustomer.gold * 100 + currentCustomer.silver * 10 + currentCustomer.copper;
- return totalCopperAvailable >= totalCopperCost;
- }
- private void DeductItemCost(Item item)
- {
- // Convert everything to copper for easier calculation
- int totalCopperCost = item.goldCost * 100 + item.silverCost * 10 + item.copperCost;
- int totalCopperAvailable = currentCustomer.gold * 100 + currentCustomer.silver * 10 + currentCustomer.copper;
- int remainingCopper = totalCopperAvailable - totalCopperCost;
- // Convert back to gold, silver, copper
- currentCustomer.gold = remainingCopper / 100;
- remainingCopper %= 100;
- currentCustomer.silver = remainingCopper / 10;
- currentCustomer.copper = remainingCopper % 10;
- Debug.Log($"Purchased {item.itemName} for {item.goldCost}g {item.silverCost}s {item.copperCost}c");
- }
- private void AddItemToCustomerInventory(Item item)
- {
- // This method needs to be implemented based on your inventory system
- // For now, let's just log what would happen
- Debug.Log($"Would add {item.itemName} to {currentCustomer.name}'s inventory");
- // If you have an inventory system, add the item here
- // For example:
- // currentCustomer.inventory.AddItem(item);
- }
- private void UpdatePlayerMoney()
- {
- if (playerMoney != null && currentCustomer != null)
- {
- playerMoney.text = $"{currentCustomer.gold}g {currentCustomer.silver}s {currentCustomer.copper}c";
- }
- }
- [ContextMenu("Reload Items")]
- public void ReloadItems()
- {
- LoadAllItems();
- if (shopContainer != null && shopContainer.style.display == DisplayStyle.Flex)
- {
- RefreshItemList();
- }
- }
- // Public methods to get items by category (for compatibility with old system)
- public List<Item> GetWeapons()
- {
- return availableItems.Where(item => item.itemType == ItemType.Weapon).ToList();
- }
- public List<Item> GetArmor()
- {
- return availableItems.Where(item => item.itemType == ItemType.Armor).ToList();
- }
- public List<Item> GetMiscItems()
- {
- return availableItems.Where(item =>
- item.itemType == ItemType.Miscellaneous ||
- item.itemType == ItemType.Consumable ||
- item.itemType == ItemType.Tool ||
- item.itemType == ItemType.Accessory).ToList();
- }
- public List<Item> GetAllItems()
- {
- return new List<Item>(availableItems);
- }
- [ContextMenu("Check Shop Setup")]
- public void CheckShopSetup()
- {
- Debug.Log("=== ItemShopManager Setup Check ===");
- // Check UIDocument
- var uiDoc = GetComponent<UIDocument>();
- if (uiDoc == null)
- {
- Debug.LogError("❌ No UIDocument component found on this GameObject!");
- Debug.LogError("➤ Add a UIDocument component to fix this.");
- return;
- }
- else
- {
- Debug.Log("✓ UIDocument component found");
- }
- // Check Visual Tree Asset
- if (uiDoc.visualTreeAsset == null)
- {
- Debug.LogError("❌ UIDocument has no Visual Tree Asset assigned!");
- Debug.LogError("➤ Assign ShopUI.uxml to the UIDocument component.");
- return;
- }
- else
- {
- Debug.Log($"✓ Visual Tree Asset assigned: {uiDoc.visualTreeAsset.name}");
- }
- // Check UI elements
- var root = uiDoc.rootVisualElement;
- var container = root?.Q<VisualElement>("ShopContainer");
- if (container == null)
- {
- Debug.LogError("❌ ShopContainer element not found in the UXML!");
- Debug.LogError("➤ Make sure you're using the correct ShopUI.uxml file.");
- return;
- }
- else
- {
- Debug.Log("✓ ShopContainer element found in UXML");
- }
- // Check items
- Debug.Log($"✓ {availableItems.Count} items loaded for shop");
- Debug.Log("=== Setup Check Complete - Shop should work! ===");
- }
- [ContextMenu("Force Initialize UI")]
- public void ForceInitializeUI()
- {
- uiDocument = GetComponent<UIDocument>();
- if (uiDocument != null && uiDocument.visualTreeAsset != null)
- {
- InitializeUI();
- Debug.Log("UI forcefully initialized");
- }
- else
- {
- Debug.LogError("Cannot initialize UI - missing UIDocument or Visual Tree Asset");
- }
- }
- [ContextMenu("Debug UI State")]
- public void DebugUIState()
- {
- Debug.Log("=== UI State Debug ===");
- if (uiDocument == null)
- {
- Debug.LogError("uiDocument is null");
- return;
- }
- Debug.Log($"UIDocument sorting order: {uiDocument.sortingOrder}");
- if (uiDocument.panelSettings != null)
- {
- Debug.Log($"Panel settings sorting order: {uiDocument.panelSettings.sortingOrder}");
- }
- else
- {
- Debug.LogWarning("Panel settings is null");
- }
- var root = uiDocument.rootVisualElement;
- Debug.Log($"Root element child count: {root.childCount}");
- if (shopContainer != null)
- {
- Debug.Log($"Shop container display: {shopContainer.style.display}");
- Debug.Log($"Shop container resolved display: {shopContainer.resolvedStyle.display}");
- Debug.Log($"Shop container visible: {shopContainer.visible}");
- Debug.Log($"Shop container opacity: {shopContainer.resolvedStyle.opacity}");
- Debug.Log($"Shop container position: {shopContainer.style.position}");
- Debug.Log($"Shop container worldBound: {shopContainer.worldBound}");
- }
- else
- {
- Debug.LogError("shopContainer is null");
- }
- // Check for other UIDocuments that might be covering this one
- var allUIDocuments = FindObjectsByType<UIDocument>(FindObjectsSortMode.None);
- Debug.Log($"Found {allUIDocuments.Length} UIDocuments in scene:");
- foreach (var doc in allUIDocuments)
- {
- var panelSort = doc.panelSettings?.sortingOrder ?? -999;
- Debug.Log($" - '{doc.gameObject.name}' sortingOrder: {doc.sortingOrder}, panelSettings: {panelSort}");
- }
- }
- [ContextMenu("Force Open Shop (Test)")]
- public void ForceOpenShopTest()
- {
- // Create a test character for debugging
- var testCharacter = new TeamCharacter();
- testCharacter.name = "Test Character";
- testCharacter.gold = 100;
- testCharacter.silver = 50;
- testCharacter.copper = 25;
- Debug.Log("Opening shop with test character...");
- OpenShop(testCharacter);
- }
- }
|