|
|
@@ -0,0 +1,620 @@
|
|
|
+using UnityEngine;
|
|
|
+using UnityEngine.UIElements;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// Beautiful UI popup for combat event encounters
|
|
|
+/// Shows enemy details and provides options to attack or run away
|
|
|
+/// Uses UXML template for cleaner UI structure
|
|
|
+/// </summary>
|
|
|
+public class CombatEventPopupUXML : MonoBehaviour
|
|
|
+{
|
|
|
+ [Header("UI References")]
|
|
|
+ public UIDocument uiDocument;
|
|
|
+ public VisualTreeAsset popupTemplate; // UXML template
|
|
|
+ public StyleSheet popupStyleSheet; // USS styles
|
|
|
+
|
|
|
+ [Header("Popup Settings")]
|
|
|
+ public float animationDuration = 0.3f;
|
|
|
+ public float backgroundBlurIntensity = 0.5f;
|
|
|
+
|
|
|
+ // Events
|
|
|
+ public System.Action<bool> OnCombatDecision; // true = attack, false = run away
|
|
|
+
|
|
|
+ // UI Elements (from UXML)
|
|
|
+ private VisualElement popupContainer;
|
|
|
+ private VisualElement backgroundOverlay;
|
|
|
+ private VisualElement popupPanel;
|
|
|
+ private Label eventTitleLabel;
|
|
|
+ private Label eventDescriptionLabel;
|
|
|
+ private VisualElement enemyListContainer;
|
|
|
+ private VisualElement enemyItemTemplate;
|
|
|
+ private Button attackButton;
|
|
|
+ private Button runAwayButton;
|
|
|
+
|
|
|
+ // Current combat data
|
|
|
+ private BattleEventData currentBattleData;
|
|
|
+ private TravelEventContext currentContext;
|
|
|
+ private bool isPopupActive = false;
|
|
|
+
|
|
|
+ void Awake()
|
|
|
+ {
|
|
|
+ // Find UI Document if not assigned
|
|
|
+ if (uiDocument == null)
|
|
|
+ uiDocument = GetComponent<UIDocument>();
|
|
|
+
|
|
|
+ if (uiDocument == null)
|
|
|
+ {
|
|
|
+ Debug.LogError("CombatEventPopupUXML: No UIDocument found! Please assign one.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ SetupUI();
|
|
|
+ }
|
|
|
+
|
|
|
+ void SetupUI()
|
|
|
+ {
|
|
|
+ var root = uiDocument.rootVisualElement;
|
|
|
+ Debug.Log($"🔧 SetupUI: Root element size: {root.resolvedStyle.width}x{root.resolvedStyle.height}");
|
|
|
+
|
|
|
+ // Load and instantiate UXML template
|
|
|
+ if (popupTemplate != null)
|
|
|
+ {
|
|
|
+ // Clone the template
|
|
|
+ var template = popupTemplate.Instantiate();
|
|
|
+ root.Add(template);
|
|
|
+ Debug.Log($"✅ UXML template instantiated and added to root");
|
|
|
+
|
|
|
+ // Apply style sheet
|
|
|
+ if (popupStyleSheet != null)
|
|
|
+ {
|
|
|
+ root.styleSheets.Add(popupStyleSheet);
|
|
|
+ Debug.Log($"✅ USS stylesheet applied");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.LogWarning("⚠️ No USS stylesheet assigned");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.LogWarning("No UXML template assigned, creating UI programmatically as fallback");
|
|
|
+ CreateUIFallback(root);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Cache UI element references
|
|
|
+ CacheUIElements(root);
|
|
|
+
|
|
|
+ // Setup event handlers
|
|
|
+ if (backgroundOverlay != null)
|
|
|
+ {
|
|
|
+ // Block all mouse events from reaching the map below
|
|
|
+ backgroundOverlay.RegisterCallback<ClickEvent>(OnBackgroundClick);
|
|
|
+ backgroundOverlay.RegisterCallback<MouseDownEvent>(OnBackgroundMouseDown);
|
|
|
+ backgroundOverlay.RegisterCallback<MouseUpEvent>(OnBackgroundMouseUp);
|
|
|
+ backgroundOverlay.RegisterCallback<MouseMoveEvent>(OnBackgroundMouseMove);
|
|
|
+ backgroundOverlay.RegisterCallback<WheelEvent>(OnBackgroundWheelEvent);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (attackButton != null)
|
|
|
+ attackButton.clicked += OnAttackClicked;
|
|
|
+
|
|
|
+ if (runAwayButton != null)
|
|
|
+ runAwayButton.clicked += OnRunAwayClicked;
|
|
|
+
|
|
|
+ // Initially hide the popup
|
|
|
+ HidePopup();
|
|
|
+ }
|
|
|
+
|
|
|
+ void CacheUIElements(VisualElement root)
|
|
|
+ {
|
|
|
+ // Cache references to UI elements by name/class
|
|
|
+ popupContainer = root.Q<VisualElement>("combat-event-popup");
|
|
|
+ backgroundOverlay = root.Q<VisualElement>("background-overlay");
|
|
|
+ popupPanel = root.Q<VisualElement>("popup-panel");
|
|
|
+ eventTitleLabel = root.Q<Label>("event-title");
|
|
|
+ eventDescriptionLabel = root.Q<Label>("event-description");
|
|
|
+ enemyListContainer = root.Q<VisualElement>("enemy-list");
|
|
|
+ enemyItemTemplate = root.Q<VisualElement>("enemy-item-template");
|
|
|
+ attackButton = root.Q<Button>("attack-button");
|
|
|
+ runAwayButton = root.Q<Button>("run-away-button");
|
|
|
+
|
|
|
+ // Debug what we found
|
|
|
+ Debug.Log($"🔍 UI Elements found:");
|
|
|
+ Debug.Log($" popupContainer: {(popupContainer != null ? "✅" : "❌")}");
|
|
|
+ Debug.Log($" backgroundOverlay: {(backgroundOverlay != null ? "✅" : "❌")}");
|
|
|
+ Debug.Log($" popupPanel: {(popupPanel != null ? "✅" : "❌")}");
|
|
|
+ Debug.Log($" eventTitleLabel: {(eventTitleLabel != null ? "✅" : "❌")}");
|
|
|
+ Debug.Log($" attackButton: {(attackButton != null ? "✅" : "❌")}");
|
|
|
+ Debug.Log($" runAwayButton: {(runAwayButton != null ? "✅" : "❌")}");
|
|
|
+
|
|
|
+ // Hide the template
|
|
|
+ if (enemyItemTemplate != null)
|
|
|
+ enemyItemTemplate.style.display = DisplayStyle.None;
|
|
|
+
|
|
|
+ // Debug missing elements
|
|
|
+ if (popupContainer == null) Debug.LogError("Could not find 'combat-event-popup' element");
|
|
|
+ if (attackButton == null) Debug.LogError("Could not find 'attack-button' element");
|
|
|
+ if (runAwayButton == null) Debug.LogError("Could not find 'run-away-button' element");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Fallback UI creation if UXML template is not available
|
|
|
+ /// </summary>
|
|
|
+ void CreateUIFallback(VisualElement root)
|
|
|
+ {
|
|
|
+ // Create basic popup structure programmatically
|
|
|
+ popupContainer = new VisualElement();
|
|
|
+ popupContainer.name = "combat-event-popup";
|
|
|
+ popupContainer.style.position = Position.Absolute;
|
|
|
+ popupContainer.style.top = 0;
|
|
|
+ popupContainer.style.left = 0;
|
|
|
+ popupContainer.style.right = 0;
|
|
|
+ popupContainer.style.bottom = 0;
|
|
|
+ popupContainer.style.justifyContent = Justify.Center;
|
|
|
+ popupContainer.style.alignItems = Align.Center;
|
|
|
+
|
|
|
+ backgroundOverlay = new VisualElement();
|
|
|
+ backgroundOverlay.name = "background-overlay";
|
|
|
+ backgroundOverlay.style.position = Position.Absolute;
|
|
|
+ backgroundOverlay.style.top = 0;
|
|
|
+ backgroundOverlay.style.left = 0;
|
|
|
+ backgroundOverlay.style.right = 0;
|
|
|
+ backgroundOverlay.style.bottom = 0;
|
|
|
+ backgroundOverlay.style.backgroundColor = new Color(0, 0, 0, 0.7f);
|
|
|
+
|
|
|
+ popupPanel = new VisualElement();
|
|
|
+ popupPanel.name = "popup-panel";
|
|
|
+ popupPanel.style.backgroundColor = new Color(0.15f, 0.15f, 0.2f, 0.95f);
|
|
|
+ popupPanel.style.borderTopLeftRadius = 10;
|
|
|
+ popupPanel.style.borderTopRightRadius = 10;
|
|
|
+ popupPanel.style.borderBottomLeftRadius = 10;
|
|
|
+ popupPanel.style.borderBottomRightRadius = 10;
|
|
|
+ popupPanel.style.minWidth = 400;
|
|
|
+ popupPanel.style.paddingTop = 20;
|
|
|
+ popupPanel.style.paddingBottom = 20;
|
|
|
+ popupPanel.style.paddingLeft = 20;
|
|
|
+ popupPanel.style.paddingRight = 20;
|
|
|
+
|
|
|
+ eventTitleLabel = new Label("*** COMBAT ENCOUNTER! ***");
|
|
|
+ eventTitleLabel.name = "event-title";
|
|
|
+ eventTitleLabel.style.fontSize = 24;
|
|
|
+ eventTitleLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
|
+
|
|
|
+ eventDescriptionLabel = new Label();
|
|
|
+ eventDescriptionLabel.name = "event-description";
|
|
|
+
|
|
|
+ enemyListContainer = new VisualElement();
|
|
|
+ enemyListContainer.name = "enemy-list";
|
|
|
+
|
|
|
+ var buttonContainer = new VisualElement();
|
|
|
+ buttonContainer.style.flexDirection = FlexDirection.Row;
|
|
|
+ buttonContainer.style.justifyContent = Justify.SpaceAround;
|
|
|
+ buttonContainer.style.marginTop = 20;
|
|
|
+
|
|
|
+ runAwayButton = new Button();
|
|
|
+ runAwayButton.name = "run-away-button";
|
|
|
+ runAwayButton.text = "[FLEE] RUN AWAY";
|
|
|
+
|
|
|
+ attackButton = new Button();
|
|
|
+ attackButton.name = "attack-button";
|
|
|
+ attackButton.text = "[FIGHT] ATTACK!";
|
|
|
+
|
|
|
+ // Assemble the UI
|
|
|
+ buttonContainer.Add(runAwayButton);
|
|
|
+ buttonContainer.Add(attackButton);
|
|
|
+
|
|
|
+ popupPanel.Add(eventTitleLabel);
|
|
|
+ popupPanel.Add(eventDescriptionLabel);
|
|
|
+ popupPanel.Add(enemyListContainer);
|
|
|
+ popupPanel.Add(buttonContainer);
|
|
|
+
|
|
|
+ popupContainer.Add(backgroundOverlay);
|
|
|
+ popupContainer.Add(popupPanel);
|
|
|
+ root.Add(popupContainer);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Show the combat encounter popup with battle data
|
|
|
+ /// </summary>
|
|
|
+ public void ShowCombatEncounter(BattleEventData battleData, TravelEventContext context, string description)
|
|
|
+ {
|
|
|
+ if (isPopupActive)
|
|
|
+ {
|
|
|
+ Debug.LogWarning("Combat popup is already active!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ currentBattleData = battleData;
|
|
|
+ currentContext = context;
|
|
|
+ isPopupActive = true;
|
|
|
+
|
|
|
+ Debug.Log($"🎭 Showing combat popup with {battleData.enemyCount} {battleData.enemyType}(s)");
|
|
|
+
|
|
|
+ // Update UI content
|
|
|
+ UpdatePopupContent(battleData, description);
|
|
|
+
|
|
|
+ // Show popup with animation
|
|
|
+ ShowPopup();
|
|
|
+ }
|
|
|
+
|
|
|
+ void UpdatePopupContent(BattleEventData battleData, string description)
|
|
|
+ {
|
|
|
+ // Update description
|
|
|
+ if (eventDescriptionLabel != null)
|
|
|
+ eventDescriptionLabel.text = description;
|
|
|
+
|
|
|
+ // Clear existing enemy items
|
|
|
+ if (enemyListContainer != null)
|
|
|
+ {
|
|
|
+ var existingItems = enemyListContainer.Children().Where(child =>
|
|
|
+ child.name != "enemy-item-template").ToList();
|
|
|
+
|
|
|
+ foreach (var item in existingItems)
|
|
|
+ {
|
|
|
+ enemyListContainer.Remove(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create enemy display items
|
|
|
+ CreateEnemyDisplays(battleData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void CreateEnemyDisplays(BattleEventData battleData)
|
|
|
+ {
|
|
|
+ if (battleData.enemyCharacterData == null)
|
|
|
+ {
|
|
|
+ Debug.LogWarning("No enemy character data available for display");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var enemyData = battleData.enemyCharacterData;
|
|
|
+
|
|
|
+ // Create enemy item element
|
|
|
+ VisualElement enemyItem;
|
|
|
+
|
|
|
+ if (enemyItemTemplate != null)
|
|
|
+ {
|
|
|
+ // Clone the template by creating a new instance from the UXML
|
|
|
+ enemyItem = CreateEnemyItemFromTemplate();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Create manually if no template
|
|
|
+ enemyItem = CreateEnemyItemFallback();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update enemy information
|
|
|
+ var nameLabel = enemyItem.Q<Label>("enemy-name");
|
|
|
+ var statsLabel = enemyItem.Q<Label>("enemy-stats");
|
|
|
+ var weaponLabel = enemyItem.Q<Label>("enemy-weapon");
|
|
|
+ var threatIndicator = enemyItem.Q<VisualElement>("threat-indicator");
|
|
|
+ var threatLabel = enemyItem.Q<Label>("threat-label");
|
|
|
+
|
|
|
+ if (nameLabel != null)
|
|
|
+ nameLabel.text = $"{battleData.enemyCount}x {enemyData.enemyName}";
|
|
|
+
|
|
|
+ if (statsLabel != null)
|
|
|
+ statsLabel.text = $"HP: {enemyData.maxHealth} | AC: {enemyData.armorClass} | Threat: {enemyData.threatLevel}";
|
|
|
+
|
|
|
+ if (weaponLabel != null && enemyData.preferredWeapon != null)
|
|
|
+ weaponLabel.text = $"[WEAPON] {enemyData.preferredWeapon.itemName}";
|
|
|
+
|
|
|
+ // Update threat indicator
|
|
|
+ if (threatIndicator != null && threatLabel != null)
|
|
|
+ {
|
|
|
+ threatLabel.text = $"T{enemyData.threatLevel}";
|
|
|
+
|
|
|
+ // Remove existing threat classes
|
|
|
+ threatIndicator.RemoveFromClassList("threat-low");
|
|
|
+ threatIndicator.RemoveFromClassList("threat-medium");
|
|
|
+ threatIndicator.RemoveFromClassList("threat-high");
|
|
|
+ threatIndicator.RemoveFromClassList("threat-extreme");
|
|
|
+
|
|
|
+ // Add appropriate threat class
|
|
|
+ if (enemyData.threatLevel <= 2)
|
|
|
+ threatIndicator.AddToClassList("threat-low");
|
|
|
+ else if (enemyData.threatLevel <= 4)
|
|
|
+ threatIndicator.AddToClassList("threat-medium");
|
|
|
+ else if (enemyData.threatLevel <= 6)
|
|
|
+ threatIndicator.AddToClassList("threat-high");
|
|
|
+ else
|
|
|
+ threatIndicator.AddToClassList("threat-extreme");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add hover effect
|
|
|
+ enemyItem.RegisterCallback<MouseEnterEvent>(evt =>
|
|
|
+ {
|
|
|
+ enemyItem.AddToClassList("enemy-item-hover");
|
|
|
+ });
|
|
|
+
|
|
|
+ enemyItem.RegisterCallback<MouseLeaveEvent>(evt =>
|
|
|
+ {
|
|
|
+ enemyItem.RemoveFromClassList("enemy-item-hover");
|
|
|
+ });
|
|
|
+
|
|
|
+ enemyListContainer.Add(enemyItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ VisualElement CreateEnemyItemFromTemplate()
|
|
|
+ {
|
|
|
+ // Create a new enemy item based on the template structure
|
|
|
+ var item = new VisualElement();
|
|
|
+ item.style.flexDirection = FlexDirection.Row;
|
|
|
+ item.style.justifyContent = Justify.SpaceBetween;
|
|
|
+ item.style.alignItems = Align.Center;
|
|
|
+ item.style.marginBottom = 8;
|
|
|
+ item.style.paddingTop = 8;
|
|
|
+ item.style.paddingBottom = 8;
|
|
|
+ item.style.paddingLeft = 10;
|
|
|
+ item.style.paddingRight = 10;
|
|
|
+ item.style.backgroundColor = new Color(0.2f, 0.2f, 0.25f, 0.6f);
|
|
|
+ item.style.borderTopLeftRadius = 4;
|
|
|
+ item.style.borderTopRightRadius = 4;
|
|
|
+ item.style.borderBottomLeftRadius = 4;
|
|
|
+ item.style.borderBottomRightRadius = 4;
|
|
|
+ item.AddToClassList("enemy-item");
|
|
|
+
|
|
|
+ // Enemy info container
|
|
|
+ var infoContainer = new VisualElement();
|
|
|
+ infoContainer.name = "enemy-info";
|
|
|
+ infoContainer.AddToClassList("enemy-info");
|
|
|
+ infoContainer.style.flexDirection = FlexDirection.Column;
|
|
|
+ infoContainer.style.flexGrow = 1;
|
|
|
+
|
|
|
+ // Enemy name label
|
|
|
+ var nameLabel = new Label();
|
|
|
+ nameLabel.name = "enemy-name";
|
|
|
+ nameLabel.AddToClassList("enemy-name");
|
|
|
+ nameLabel.style.fontSize = 16;
|
|
|
+ nameLabel.style.color = new Color(1f, 0.9f, 0.7f, 1f);
|
|
|
+
|
|
|
+ // Enemy stats label
|
|
|
+ var statsLabel = new Label();
|
|
|
+ statsLabel.name = "enemy-stats";
|
|
|
+ statsLabel.AddToClassList("enemy-stats");
|
|
|
+ statsLabel.style.fontSize = 12;
|
|
|
+ statsLabel.style.color = new Color(0.8f, 0.8f, 0.8f, 1f);
|
|
|
+
|
|
|
+ // Enemy weapon label
|
|
|
+ var weaponLabel = new Label();
|
|
|
+ weaponLabel.name = "enemy-weapon";
|
|
|
+ weaponLabel.AddToClassList("enemy-weapon");
|
|
|
+ weaponLabel.style.fontSize = 11;
|
|
|
+ weaponLabel.style.color = new Color(0.7f, 0.7f, 1f, 1f);
|
|
|
+
|
|
|
+ // Threat indicator
|
|
|
+ var threatIndicator = new VisualElement();
|
|
|
+ threatIndicator.name = "threat-indicator";
|
|
|
+ threatIndicator.AddToClassList("threat-indicator");
|
|
|
+ threatIndicator.style.width = 60;
|
|
|
+ threatIndicator.style.height = 20;
|
|
|
+ threatIndicator.style.borderTopLeftRadius = 10;
|
|
|
+ threatIndicator.style.borderTopRightRadius = 10;
|
|
|
+ threatIndicator.style.borderBottomLeftRadius = 10;
|
|
|
+ threatIndicator.style.borderBottomRightRadius = 10;
|
|
|
+ threatIndicator.style.justifyContent = Justify.Center;
|
|
|
+ threatIndicator.style.alignItems = Align.Center;
|
|
|
+ threatIndicator.style.backgroundColor = new Color(0.3f, 0.8f, 0.3f, 1f);
|
|
|
+
|
|
|
+ // Threat label
|
|
|
+ var threatLabel = new Label();
|
|
|
+ threatLabel.name = "threat-label";
|
|
|
+ threatLabel.AddToClassList("threat-label");
|
|
|
+ threatLabel.style.fontSize = 11;
|
|
|
+ threatLabel.style.color = Color.white;
|
|
|
+
|
|
|
+ // Assemble the structure
|
|
|
+ threatIndicator.Add(threatLabel);
|
|
|
+ infoContainer.Add(nameLabel);
|
|
|
+ infoContainer.Add(statsLabel);
|
|
|
+ infoContainer.Add(weaponLabel);
|
|
|
+ item.Add(infoContainer);
|
|
|
+ item.Add(threatIndicator);
|
|
|
+
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ VisualElement CreateEnemyItemFallback()
|
|
|
+ {
|
|
|
+ var item = new VisualElement();
|
|
|
+ item.style.flexDirection = FlexDirection.Row;
|
|
|
+ item.style.justifyContent = Justify.SpaceBetween;
|
|
|
+ item.style.alignItems = Align.Center;
|
|
|
+ item.style.marginBottom = 8;
|
|
|
+ item.style.paddingTop = 8;
|
|
|
+ item.style.paddingBottom = 8;
|
|
|
+ item.style.paddingLeft = 10;
|
|
|
+ item.style.paddingRight = 10;
|
|
|
+ item.style.backgroundColor = new Color(0.2f, 0.2f, 0.25f, 0.6f);
|
|
|
+ item.style.borderTopLeftRadius = 4;
|
|
|
+ item.style.borderTopRightRadius = 4;
|
|
|
+ item.style.borderBottomLeftRadius = 4;
|
|
|
+ item.style.borderBottomRightRadius = 4;
|
|
|
+
|
|
|
+ var infoContainer = new VisualElement();
|
|
|
+ infoContainer.name = "enemy-info";
|
|
|
+ infoContainer.style.flexDirection = FlexDirection.Column;
|
|
|
+ infoContainer.style.flexGrow = 1;
|
|
|
+
|
|
|
+ var nameLabel = new Label();
|
|
|
+ nameLabel.name = "enemy-name";
|
|
|
+ nameLabel.style.fontSize = 16;
|
|
|
+ nameLabel.style.color = new Color(1f, 0.9f, 0.7f, 1f);
|
|
|
+
|
|
|
+ var statsLabel = new Label();
|
|
|
+ statsLabel.name = "enemy-stats";
|
|
|
+ statsLabel.style.fontSize = 12;
|
|
|
+ statsLabel.style.color = new Color(0.8f, 0.8f, 0.8f, 1f);
|
|
|
+
|
|
|
+ var weaponLabel = new Label();
|
|
|
+ weaponLabel.name = "enemy-weapon";
|
|
|
+ weaponLabel.style.fontSize = 11;
|
|
|
+ weaponLabel.style.color = new Color(0.7f, 0.7f, 1f, 1f);
|
|
|
+
|
|
|
+ var threatIndicator = new VisualElement();
|
|
|
+ threatIndicator.name = "threat-indicator";
|
|
|
+ threatIndicator.style.width = 60;
|
|
|
+ threatIndicator.style.height = 20;
|
|
|
+ threatIndicator.style.borderTopLeftRadius = 10;
|
|
|
+ threatIndicator.style.borderTopRightRadius = 10;
|
|
|
+ threatIndicator.style.borderBottomLeftRadius = 10;
|
|
|
+ threatIndicator.style.borderBottomRightRadius = 10;
|
|
|
+ threatIndicator.style.justifyContent = Justify.Center;
|
|
|
+ threatIndicator.style.alignItems = Align.Center;
|
|
|
+ threatIndicator.style.backgroundColor = new Color(0.3f, 0.8f, 0.3f, 1f);
|
|
|
+
|
|
|
+ var threatLabel = new Label();
|
|
|
+ threatLabel.name = "threat-label";
|
|
|
+ threatLabel.style.fontSize = 11;
|
|
|
+ threatLabel.style.color = Color.white;
|
|
|
+
|
|
|
+ threatIndicator.Add(threatLabel);
|
|
|
+ infoContainer.Add(nameLabel);
|
|
|
+ infoContainer.Add(statsLabel);
|
|
|
+ infoContainer.Add(weaponLabel);
|
|
|
+ item.Add(infoContainer);
|
|
|
+ item.Add(threatIndicator);
|
|
|
+
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ void ShowPopup()
|
|
|
+ {
|
|
|
+ if (popupContainer != null)
|
|
|
+ {
|
|
|
+ Debug.Log($"🎭 ShowPopup: Setting display to Flex, current display: {popupContainer.style.display}");
|
|
|
+ popupContainer.style.display = DisplayStyle.Flex;
|
|
|
+
|
|
|
+ // Add animation classes
|
|
|
+ popupContainer.RemoveFromClassList("popup-hidden");
|
|
|
+ popupContainer.RemoveFromClassList("popup-exit");
|
|
|
+ popupContainer.AddToClassList("popup-enter");
|
|
|
+
|
|
|
+ // Check if UI Document is active and panel settings are configured
|
|
|
+ if (uiDocument != null && uiDocument.panelSettings != null)
|
|
|
+ {
|
|
|
+ Debug.Log($"✅ UIDocument active: {uiDocument.enabled}, Panel Settings: {uiDocument.panelSettings.name}");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.LogError("❌ UIDocument or Panel Settings not configured properly!");
|
|
|
+ }
|
|
|
+
|
|
|
+ Debug.Log("✅ Combat popup displayed");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.LogError("❌ Cannot show popup - popupContainer is null!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public void HidePopup()
|
|
|
+ {
|
|
|
+ if (popupContainer != null)
|
|
|
+ {
|
|
|
+ // Add exit animation
|
|
|
+ popupContainer.RemoveFromClassList("popup-enter");
|
|
|
+ popupContainer.AddToClassList("popup-exit");
|
|
|
+
|
|
|
+ // Hide after animation
|
|
|
+ this.ExecuteAfterDelay(() =>
|
|
|
+ {
|
|
|
+ popupContainer.style.display = DisplayStyle.None;
|
|
|
+ popupContainer.AddToClassList("popup-hidden");
|
|
|
+ }, animationDuration);
|
|
|
+
|
|
|
+ isPopupActive = false;
|
|
|
+ Debug.Log("✅ Combat popup hidden");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnBackgroundClick(ClickEvent evt)
|
|
|
+ {
|
|
|
+ // Block the click event from reaching elements below
|
|
|
+ evt.StopPropagation();
|
|
|
+
|
|
|
+ // Optionally allow closing popup by clicking background
|
|
|
+ // Uncomment if you want this behavior:
|
|
|
+ // OnRunAwayClicked();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnBackgroundMouseDown(MouseDownEvent evt)
|
|
|
+ {
|
|
|
+ // Block mouse down events from reaching the map below
|
|
|
+ evt.StopPropagation();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnBackgroundMouseUp(MouseUpEvent evt)
|
|
|
+ {
|
|
|
+ // Block mouse up events from reaching the map below
|
|
|
+ evt.StopPropagation();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnBackgroundMouseMove(MouseMoveEvent evt)
|
|
|
+ {
|
|
|
+ // Block mouse move events from reaching the map below
|
|
|
+ evt.StopPropagation();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnBackgroundWheelEvent(WheelEvent evt)
|
|
|
+ {
|
|
|
+ // Block wheel/scroll events from reaching the map below
|
|
|
+ evt.StopPropagation();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnAttackClicked()
|
|
|
+ {
|
|
|
+ Debug.Log("🗡️ Player chose to ATTACK!");
|
|
|
+ HidePopup();
|
|
|
+ OnCombatDecision?.Invoke(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnRunAwayClicked()
|
|
|
+ {
|
|
|
+ Debug.Log("🏃 Player chose to RUN AWAY!");
|
|
|
+ HidePopup();
|
|
|
+ OnCombatDecision?.Invoke(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Check if a screen position is within the UI bounds to block map interaction
|
|
|
+ /// </summary>
|
|
|
+ public bool IsPointWithinUI(Vector2 screenPosition)
|
|
|
+ {
|
|
|
+ if (!isPopupActive || popupContainer == null || uiDocument == null)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Convert screen position to panel-relative position
|
|
|
+ Vector2 panelPosition = RuntimePanelUtils.ScreenToPanel(uiDocument.rootVisualElement.panel, screenPosition);
|
|
|
+
|
|
|
+ // Check if the position is within the popup container bounds
|
|
|
+ bool withinBounds = popupContainer.worldBound.Contains(panelPosition);
|
|
|
+
|
|
|
+ return withinBounds;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Public getters for external access
|
|
|
+ /// </summary>
|
|
|
+ public bool IsVisible => isPopupActive;
|
|
|
+}
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// Extension method for delayed execution
|
|
|
+/// </summary>
|
|
|
+public static class MonoBehaviourExtensions
|
|
|
+{
|
|
|
+ public static void ExecuteAfterDelay(this MonoBehaviour mono, System.Action action, float delay)
|
|
|
+ {
|
|
|
+ mono.StartCoroutine(ExecuteAfterDelayCoroutine(action, delay));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static System.Collections.IEnumerator ExecuteAfterDelayCoroutine(System.Action action, float delay)
|
|
|
+ {
|
|
|
+ yield return new WaitForSeconds(delay);
|
|
|
+ action?.Invoke();
|
|
|
+ }
|
|
|
+}
|