| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System;
- /// <summary>
- /// UI Toolkit-based item selection UI for battle
- /// </summary>
- public class BattleItemSelector : MonoBehaviour
- {
- [Header("UI References")]
- public UIDocument uiDocument;
- [Header("Settings")]
- public int maxItemsToShow = 10;
- private Character currentCharacter;
- private VisualElement rootElement;
- private VisualElement container;
- private VisualElement itemList;
- private Label titleLabel;
- private Label characterLabel;
- private VisualElement noItemsContainer;
- private Button cancelButton;
- private Button closeButton;
- // Events
- public event Action<string, int> OnItemSelected;
- public event Action OnSelectionCancelled;
- void Awake()
- {
- if (uiDocument == null)
- uiDocument = GetComponent<UIDocument>();
- if (uiDocument == null)
- {
- // Create UIDocument if it doesn't exist
- uiDocument = gameObject.AddComponent<UIDocument>();
- }
- }
- void Start()
- {
- InitializeUI();
- SetVisible(false);
- }
- void Update()
- {
- if (container != null && container.style.display == DisplayStyle.Flex)
- {
- if (Input.GetKeyDown(KeyCode.Escape))
- {
- OnSelectionCancelled?.Invoke();
- HideSelection();
- }
- }
- }
- private void InitializeUI()
- {
- // Load UXML and USS
- var visualTreeAsset = Resources.Load<VisualTreeAsset>("UI/ItemSelectionUI");
- var styleSheet = Resources.Load<StyleSheet>("UI/ItemSelectionUI");
- Debug.Log($"🔍 Loading UXML: {(visualTreeAsset != null ? "✅ Found" : "❌ Not Found")}");
- Debug.Log($"🔍 Loading USS: {(styleSheet != null ? "✅ Found" : "❌ Not Found")}");
- // Try simple version if main version fails
- if (visualTreeAsset == null)
- {
- Debug.LogWarning("Main UXML failed, trying simple version...");
- visualTreeAsset = Resources.Load<VisualTreeAsset>("UI/ItemSelectionUI_Simple");
- Debug.Log($"🔍 Loading Simple UXML: {(visualTreeAsset != null ? "✅ Found" : "❌ Not Found")}");
- }
- if (visualTreeAsset == null)
- {
- Debug.LogError("Could not load any ItemSelectionUI.uxml from Resources/UI/");
- CreateFallbackUI();
- return;
- }
- rootElement = uiDocument.rootVisualElement;
- rootElement.Clear();
- // Clone the visual tree
- var clonedTree = visualTreeAsset.CloneTree();
- rootElement.Add(clonedTree);
- // Apply styles
- if (styleSheet != null)
- {
- rootElement.styleSheets.Add(styleSheet);
- }
- // Get UI elements
- container = rootElement.Q<VisualElement>("ItemSelectionContainer");
- itemList = rootElement.Q<VisualElement>("ItemList");
- titleLabel = rootElement.Q<Label>("TitleLabel");
- characterLabel = rootElement.Q<Label>("CharacterLabel");
- noItemsContainer = rootElement.Q<VisualElement>("NoItemsContainer");
- cancelButton = rootElement.Q<Button>("CancelButton");
- closeButton = rootElement.Q<Button>("CloseButton");
- // Debug element finding
- Debug.Log($"🔍 Elements found:");
- Debug.Log($" - container: {(container != null ? "✅" : "❌")}");
- Debug.Log($" - itemList: {(itemList != null ? "✅" : "❌")}");
- Debug.Log($" - titleLabel: {(titleLabel != null ? "✅" : "❌")}");
- Debug.Log($" - characterLabel: {(characterLabel != null ? "✅" : "❌")}");
- Debug.Log($" - noItemsContainer: {(noItemsContainer != null ? "✅" : "❌")}");
- Debug.Log($" - cancelButton: {(cancelButton != null ? "✅" : "❌")}");
- Debug.Log($" - closeButton: {(closeButton != null ? "✅" : "❌")}");
- // Setup event handlers
- if (cancelButton != null)
- {
- cancelButton.clicked += () =>
- {
- OnSelectionCancelled?.Invoke();
- HideSelection();
- };
- }
- if (closeButton != null)
- {
- closeButton.clicked += () =>
- {
- OnSelectionCancelled?.Invoke();
- HideSelection();
- };
- }
- Debug.Log("✅ BattleItemSelector initialized with UI Toolkit");
- }
- private void CreateFallbackUI()
- {
- Debug.LogWarning("Creating fallback BattleItemSelector UI");
- rootElement = uiDocument.rootVisualElement;
- rootElement.Clear();
- // Create basic container
- container = new VisualElement();
- container.name = "ItemSelectionContainer";
- container.style.position = Position.Absolute;
- container.style.top = 0;
- container.style.left = 0;
- container.style.right = 0;
- container.style.bottom = 0;
- container.style.backgroundColor = new Color(0, 0, 0, 0.7f);
- container.style.alignItems = Align.Center;
- container.style.justifyContent = Justify.Center;
- // Create modal
- var modal = new VisualElement();
- modal.style.backgroundColor = new Color(0.18f, 0.18f, 0.18f, 1f);
- modal.style.borderTopWidth = modal.style.borderBottomWidth = modal.style.borderLeftWidth = modal.style.borderRightWidth = 2;
- modal.style.borderTopColor = modal.style.borderBottomColor = modal.style.borderLeftColor = modal.style.borderRightColor = Color.gray;
- modal.style.borderTopLeftRadius = modal.style.borderTopRightRadius = modal.style.borderBottomLeftRadius = modal.style.borderBottomRightRadius = 8;
- modal.style.width = 400;
- modal.style.height = 500;
- modal.style.paddingTop = modal.style.paddingBottom = modal.style.paddingLeft = modal.style.paddingRight = 15;
- // Title
- titleLabel = new Label("Select Item");
- titleLabel.style.fontSize = 18;
- titleLabel.style.color = Color.white;
- titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
- titleLabel.style.marginBottom = 10;
- titleLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
- // Character label
- characterLabel = new Label();
- characterLabel.style.fontSize = 16;
- characterLabel.style.color = new Color(1f, 0.86f, 0.39f);
- characterLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
- characterLabel.style.marginBottom = 15;
- characterLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
- // Item list
- var scrollView = new ScrollView();
- scrollView.style.flexGrow = 1;
- scrollView.style.marginBottom = 15;
- itemList = new VisualElement();
- scrollView.Add(itemList);
- Debug.Log("🔧 Fallback UI: itemList created successfully");
- // No items message
- noItemsContainer = new VisualElement();
- noItemsContainer.style.alignItems = Align.Center;
- noItemsContainer.style.justifyContent = Justify.Center;
- noItemsContainer.style.flexGrow = 1;
- noItemsContainer.style.display = DisplayStyle.None;
- var noItemsLabel = new Label("No usable items available");
- noItemsLabel.style.color = new Color(0.6f, 0.6f, 0.6f);
- noItemsContainer.Add(noItemsLabel);
- // Cancel button
- cancelButton = new Button(() =>
- {
- OnSelectionCancelled?.Invoke();
- HideSelection();
- });
- cancelButton.text = "Cancel";
- cancelButton.style.paddingTop = cancelButton.style.paddingBottom = 8;
- cancelButton.style.paddingLeft = cancelButton.style.paddingRight = 16;
- // Assemble UI
- modal.Add(titleLabel);
- modal.Add(characterLabel);
- modal.Add(scrollView);
- modal.Add(noItemsContainer);
- modal.Add(cancelButton);
- container.Add(modal);
- rootElement.Add(container);
- }
- public void ShowItemSelection(Character character)
- {
- Debug.Log($"📦 ShowItemSelection called for {character.CharacterName}");
- Debug.Log($"📦 UI State - itemList: {(itemList != null ? "✅" : "❌")}, container: {(container != null ? "✅" : "❌")}");
- if (itemList == null)
- {
- Debug.LogError("❌ itemList is null - reinitializing UI");
- InitializeUI();
- }
- currentCharacter = character;
- if (characterLabel != null)
- characterLabel.text = $"{character.CharacterName}";
- if (titleLabel != null)
- titleLabel.text = "Select Item";
- PopulateItemList();
- SetVisible(true);
- Debug.Log($"📦 Item selection shown for {character.CharacterName}");
- }
- public void HideSelection()
- {
- SetVisible(false);
- ClearItemList();
- currentCharacter = null;
- Debug.Log("📦 Item selection hidden");
- }
- private void SetVisible(bool visible)
- {
- if (container != null)
- {
- container.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
- }
- }
- private void PopulateItemList()
- {
- Debug.Log($"📦 PopulateItemList called - itemList null: {itemList == null}");
- ClearItemList();
- var items = GetCharacterItems();
- Debug.Log($"📦 Found {items.Count} items to display");
- if (items.Count == 0)
- {
- if (noItemsContainer != null)
- noItemsContainer.style.display = DisplayStyle.Flex;
- return;
- }
- if (noItemsContainer != null)
- noItemsContainer.style.display = DisplayStyle.None;
- for (int i = 0; i < items.Count && i < maxItemsToShow; i++)
- {
- CreateItemButton(items[i], i);
- }
- }
- private void CreateItemButton(ItemData item, int index)
- {
- // Safety check to prevent NullReferenceException
- if (itemList == null)
- {
- Debug.LogError("❌ itemList is null! UI initialization may have failed.");
- return;
- }
- var button = new Button();
- button.AddToClassList("item-button");
- // Item name with quantity
- string itemText = item.quantity > 1 ? $"{item.name} x{item.quantity}" : item.name;
- var nameLabel = new Label(itemText);
- nameLabel.AddToClassList("item-name");
- // Item description
- var descLabel = new Label(item.description);
- descLabel.AddToClassList("item-description");
- button.Add(nameLabel);
- button.Add(descLabel);
- // Only allow selection if item is usable and quantity > 0
- if (item.isUsable && item.quantity > 0)
- {
- button.clicked += () =>
- {
- OnItemSelected?.Invoke(item.name, index);
- HideSelection();
- };
- }
- else
- {
- button.SetEnabled(false);
- nameLabel.style.color = Color.gray;
- descLabel.style.color = Color.gray;
- }
- itemList.Add(button);
- }
- private void ClearItemList()
- {
- if (itemList != null)
- {
- itemList.Clear();
- }
- }
- private List<ItemData> GetCharacterItems()
- {
- if (currentCharacter == null)
- {
- Debug.LogWarning("📦 GetCharacterItems: currentCharacter is null");
- return new List<ItemData>();
- }
- var items = new List<ItemData>();
- // Method 1: Try to get items from Inventory component (ScriptableObject-based system)
- var inventory = currentCharacter.GetComponent<Inventory>();
- if (inventory != null)
- {
- Debug.Log($"📦 Found Inventory component on {currentCharacter.CharacterName}");
- // Get misc/consumable items from inventory
- foreach (var slot in inventory.Miscellaneous)
- {
- if (slot.item is MiscellaneousItem miscItem && miscItem.isConsumable)
- {
- items.Add(new ItemData
- {
- name = miscItem.itemName,
- description = miscItem.GetEffectDescription(),
- quantity = slot.quantity,
- isUsable = true
- });
- }
- }
- Debug.Log($"📦 Found {items.Count} consumable items in Inventory component");
- return items;
- }
- // Method 2: Try to get items from CombatDataTransfer session data
- if (CombatDataTransfer.HasValidSession())
- {
- var session = CombatDataTransfer.GetCurrentSession();
- var characterData = session.playerTeam.Find(p => p.characterName == currentCharacter.CharacterName ||
- currentCharacter.CharacterName.StartsWith(p.characterName));
- if (characterData != null && characterData.miscItems != null)
- {
- Debug.Log($"📦 Found {characterData.miscItems.Count} misc items in CombatDataTransfer for {currentCharacter.CharacterName}");
- foreach (var itemName in characterData.miscItems)
- {
- // Try to find the actual Item asset to get proper description
- var itemAsset = FindItemAsset(itemName);
- if (itemAsset is MiscellaneousItem miscItem && miscItem.isConsumable)
- {
- items.Add(new ItemData
- {
- name = miscItem.itemName,
- description = miscItem.GetEffectDescription(),
- quantity = 1, // Default quantity for string-based inventory
- isUsable = true
- });
- }
- else
- {
- // Fallback for items without ScriptableObject assets
- string description = GetFallbackItemDescription(itemName);
- items.Add(new ItemData
- {
- name = itemName,
- description = description,
- quantity = 1,
- isUsable = true
- });
- }
- }
- return items;
- }
- }
- // Method 3: Fallback - try to access string-based inventory directly (if exposed)
- Debug.LogWarning($"📦 No inventory data found for {currentCharacter.CharacterName}. Using empty inventory.");
- return items; // Return empty list
- }
- /// <summary>
- /// Try to find an Item ScriptableObject asset by name
- /// </summary>
- private Item FindItemAsset(string itemName)
- {
- // Try to find in Resources folder first
- var item = Resources.Load<Item>($"Items/{itemName}");
- if (item != null) return item;
- // Try to find using Resources.LoadAll as fallback
- var allItems = Resources.LoadAll<Item>("Items");
- foreach (var itemAsset in allItems)
- {
- if (itemAsset.itemName == itemName)
- return itemAsset;
- }
- return null;
- }
- /// <summary>
- /// Get a fallback description for items that don't have ScriptableObject assets
- /// </summary>
- private string GetFallbackItemDescription(string itemName)
- {
- // Basic descriptions for common item names
- switch (itemName.ToLower())
- {
- case "health potion":
- case "healing potion":
- return "Restores health";
- case "mana potion":
- case "magic potion":
- return "Restores mana";
- case "antidote":
- return "Cures poison";
- case "strength elixir":
- return "Temporarily increases strength";
- case "rope":
- case "hemp rope":
- return "Useful utility item";
- case "torch":
- return "Provides light";
- default:
- return "A useful item";
- }
- }
- [System.Serializable]
- public class ItemData
- {
- public string name;
- public string description;
- public int quantity = 1;
- public bool isUsable = true;
- }
- void OnDestroy()
- {
- OnItemSelected = null;
- OnSelectionCancelled = null;
- }
- }
|