using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.UI; public class GeneralUI : MonoBehaviour { public static GeneralUI Instance; [Header("UI Components")] [SerializeField] private TextMeshProUGUI playeName; // Reference to the name text in the player UI [SerializeField] private TextMeshProUGUI playerLevel; // Reference to the level indicator in the player UI [SerializeField] private Image playerSprite; // Reference to the sprite image for the player [SerializeField] private TextMeshProUGUI healthTextPlaceOne; // Text reference to the first health value place [SerializeField] private TextMeshProUGUI healthTextPlaceTwo; // Text reference to the second health value place [SerializeField] private Slider healthSlider; // Reference to the health slider object that will slide the health bar down as the player is damaged [SerializeField] private TextMeshProUGUI manaTextPlaceOne; // Text reference to the first mana value place [SerializeField] private TextMeshProUGUI manaTextPlaceTwo; // Text reference to the second mana value place [SerializeField] private Slider manaSlider; // Reference to the mana slider object that will slide the mana bar down as the player uses mana [SerializeField] private Transform modifierField; // Transform field for the modifiers [SerializeField] private GameObject modifierPrefab; // Reference to the modifier prefab object [SerializeField] private GameObject inventoryButton; // Reference to the inventory button object within the general UI [SerializeField] private Canvas inventoryCanvas; // The canvas that will serve as the inventory management for the player [SerializeField] private GameObject diceRoller; // Reference to the dice roller object that will [Header("Party Handling UI")] [SerializeField] private Transform partyTransform; // Reference to the transform that will contain the party UI icons on the left [SerializeField] private GameObject partyGuiPrefab; // Reference to the prefab that will hold the party information private GameObject playerObject; private Player playerComponent; private List<GameObject> allyIcons; private List<GameObject> minionIcons; private readonly Color DisabledColor = new Color(.65f, .65f, .65f, 1f); private bool allDiceRolled; private bool? canRollForDamage; private bool isFinalAttack; private void Awake() { Instance = this; allyIcons = new List<GameObject>(); allDiceRolled = true; } /// <summary> /// Sets the information for each of the components within the UI scene /// </summary> public void SetInformation(bool setup = true) { playerObject ??= GameManager.Instance.GetPlayerObject(); playerComponent ??= playerObject.GetComponent<Player>(); playeName.text = playerComponent.GetName(); playerLevel.text = playerComponent.GetLevel().ToString(); SetHPAndMPStats(); if (setup) { manaSlider.maxValue = playerComponent.RetrieveMaxMana(); manaSlider.value = playerComponent.RetrieveMaxMana(); healthSlider.maxValue = playerComponent.RetrieveMaxHealth(); healthSlider.value = playerComponent.RetrieveMaxHealth(); } else { manaSlider.maxValue = playerComponent.RetrieveMaxMana(); manaSlider.value = playerComponent.RetrieveMana(); healthSlider.maxValue = playerComponent.RetrieveMaxHealth(); healthSlider.value = playerComponent.RetrieveHealth(); } } /// <summary> /// Method that takes into account a player setting before indicating the hp and mp stats /// </summary> private void SetHPAndMPStats() { if (!Globals.CurMaxPositionSwitch) // Enabled should be CUR / MAX { healthTextPlaceOne.text = playerComponent.RetrieveHealth().ToString(); healthTextPlaceTwo.text = playerComponent.RetrieveMaxHealth().ToString(); manaTextPlaceOne.text = playerComponent.RetrieveMana().ToString(); manaTextPlaceTwo.text = playerComponent.RetrieveMaxMana().ToString(); } else // Disabled should be MAX / CUR { healthTextPlaceOne.text = playerComponent.RetrieveMaxHealth().ToString(); healthTextPlaceTwo.text = playerComponent.RetrieveHealth().ToString(); manaTextPlaceOne.text = playerComponent.RetrieveMaxMana().ToString(); manaTextPlaceTwo.text = playerComponent.RetrieveMana().ToString(); } } /// <summary> /// Updates the health, mana, and armor within the general UI screen based on the current player condition /// </summary> /// <param name="playerCondition">Reference to the current state of the player</param> public void UpdateHealthAndMana(Player playerCondition) { int maxHP = playerCondition.RetrieveMaxHealth(); int maxMP = playerCondition.RetrieveMaxMana(); int curHP = playerCondition.RetrieveHealth(); int curMP = playerCondition.RetrieveMana(); playerLevel.text = playerCondition.GetLevel().ToString(); healthSlider.maxValue = maxHP; manaSlider.maxValue = maxMP; healthSlider.value = curHP; manaSlider.value = curMP; SetHPAndMPStats(); } public void EnableEventLayout() { //ResetUI(); // TODO ---> Needs further work and implementation List<GameObject> buttons = new List<GameObject>(); int number = 2; for (int i = 1; i <= number; i++) { //buttons.Add(Instantiate(normalButton, choice_Panel)); TextMeshProUGUI retainer = buttons[i - 1].GetComponentInChildren<TextMeshProUGUI>(); switch (i) { case 1: { retainer.text = "Choice 1"; break; } case 2: { retainer.text = "Choice 2"; break; } } } } /// <summary> /// Indicates modifiers within the horizontal row layout /// First deletes any that are already present and re-applies their images and descriptions to prevent duplicates /// </summary> /// <param name="player"></param> public void UpdateModifiers(Player player) { foreach (Transform item in modifierField) Destroy(item.gameObject); foreach (KeyValuePair<Modifier, int> modifier in player.GatherModList()) { GameObject modImage = Instantiate(modifierPrefab, modifierField); modImage.GetComponent<Image>().sprite = modifier.Key.ModSprite; modImage.GetComponent<ModifierHelper>().InjectModifier(modifier.Key, modifier.Value); } } /// <summary> /// Opens the inventory screen and deactivates the inventory button since the screen is open, waking it up /// </summary> public void OpenInventoryScreen() { inventoryCanvas.enabled = true; DeactivateInventoryButton(); GetComponent<InventoryManipulator>().WakeUp(); } /// <summary> /// Closes the inventory screen and reactivates the inventory button since the screen is closed /// </summary> public void CloseInventoryScreen() { inventoryCanvas.enabled = false; ReactivateInventoryButton(); GetComponent<InventoryManipulator>().Sleep(); } /// <summary> /// Deactivates the inventory button to not be able to be clicked during scenes, parts in battle, etc. /// </summary> public void DeactivateInventoryButton() { inventoryButton.GetComponent<Button>().interactable = false; inventoryButton.GetComponent<Image>().color = DisabledColor; } /// <summary> /// Reactivates the inventory button to be able to be clicked for inventory management, such as in the end of encounters /// </summary> public void ReactivateInventoryButton() { inventoryButton.GetComponent<Button>().interactable = true; inventoryButton.GetComponent<Image>().color = Color.white; } public List<GameObject> GetAllyIconGUIs() => allyIcons; public void GenerateGUIs(GameObject[] allyObjects) { foreach (GameObject ally in allyObjects) { GameObject allyIcon = Instantiate(partyGuiPrefab, partyTransform); allyIcons.Add(allyIcon); allyIcon.GetComponent<PartyMemberGUI>().CallCreateGUI(ally.GetComponent<Ally>()); ally.GetComponent<Ally>().InjectGUI(allyIcon.GetComponent<PartyMemberGUI>()); } } public void UpdateGUIs(GameObject[] allyObjects) { foreach (GameObject allyObject in allyObjects) { try { allyObject.GetComponent<Ally>().GetGUI().UpdateStats(allyObject.GetComponent<Ally>()); } catch { continue; } } } /// <summary> /// Creates a temporary GUI for the minion summoned by an ally or player /// </summary> /// <param name="minionComp">The minion Ally component</param> public void CreateTempGUI(Ally minionComp) { // Creates new GUI and initializes the minion list if not already initialized GameObject minionIcon = Instantiate(partyGuiPrefab, partyTransform); minionIcons ??= new List<GameObject>(); minionIcons.Add(minionIcon); // Sets up the connections within the Party Member GUI and the Ally component minionIcon.GetComponent<PartyMemberGUI>().CallCreateGUI(minionComp); minionComp.InjectGUI(minionIcon.GetComponent<PartyMemberGUI>()); } /// <summary> /// Eliminates all the temporary GUIs since the minions will have been destroyed at the end of battle /// </summary> public void EliminateTempGUIs() { // If the minions list wasn't intiialized, simply return since that indicates no minions were made if (minionIcons is null) return; int length = minionIcons.Count; // Destroy all Minion GUIs for (int i = 0; i < length; ++i) { // Destroy the GUI and then break out GameObject minionGUI = minionIcons[0]; minionIcons.Remove(minionGUI); Destroy(minionGUI); } } /// <summary> /// Eliminates a specific GUI based on the ally component injected /// This is for when a minion has been fully defeated /// </summary> /// <param name="minionComp">The ally component to be searched for in the list</param> public void EliminateMinionGUI(Ally minionComp) { for (int i = 0; i < minionIcons.Count; ++i) { // Check for instance ID equality for the entities if (minionIcons[i].GetComponent<PartyMemberGUI>().GetAllyInfo().GetUniqueID() == minionComp.GetUniqueID()) { // Destroy the GUI and then break out GameObject minionGUI = minionIcons[i]; minionIcons.Remove(minionGUI); Destroy(minionGUI); break; } } } public async void RollToHit(bool rollingForDamage, bool hasCrit, SortedDictionary<int, (int, Dice)> diceToRoll, Entity attacker, Entity target, int toHitValue, int armorValue, SortedDictionary<int, (int, Dice)> damageRolls, Dictionary<string, (List<string>, List<object>)> triggers, bool isFinalAttack) { allDiceRolled = false; canRollForDamage = rollingForDamage; EnemyUI.Instance.SwitchMemberTurnText(false); diceRoller.SetActive(true); DiceRollerGUI rollerInstance = diceRoller.GetComponentInChildren<DiceRollerGUI>(); this.isFinalAttack = isFinalAttack; rollerInstance.InjectNecessaryInfo(hasCrit, attacker, target, toHitValue, armorValue, damageRolls, triggers); rollerInstance.InjectToHitModifiers(); rollerInstance.StartDiceRoller(diceToRoll, true); while (allDiceRolled is false) await Task.Yield(); await Task.CompletedTask; } public async Task RollForDamage(SortedDictionary<int, (int, Dice)> diceToRoll, int baseDamage, int totalDamage, Dictionary<int, (List<SpellSO.Element>, List<WeaponSO.Type>)> typeCollection) { allDiceRolled = false; canRollForDamage = null; EnemyUI.Instance.SwitchMemberTurnText(false); diceRoller.SetActive(true); DiceRollerGUI rollerInstance = diceRoller.GetComponentInChildren<DiceRollerGUI>(); rollerInstance.InjectDamageModifiers(baseDamage, totalDamage, typeCollection); rollerInstance.StartDiceRoller(diceToRoll, false); while (allDiceRolled is false) await Task.Yield(); await Task.CompletedTask; } public void DiceAllRolled(Entity attacker, Entity target, int toHitValue, int armorValue, SortedDictionary<int, (int, Dice)> damageRolls, Dictionary<string, (List<string>, List<object>)> triggers) { allDiceRolled = true; diceRoller.SetActive(false); BattleHandler.Instance.CalculateDamage(diceRoller.GetComponent<DiceRollerGUI>().wasCrit, canRollForDamage, attacker, target, toHitValue, armorValue, damageRolls, triggers, isFinalAttack); } public void SwitchCurMaxPositions() { SetHPAndMPStats(); GetComponent<InventoryManipulator>().SwitchCurMaxText(); if (partyTransform.childCount > 0) { foreach (Transform child in partyTransform) child.gameObject.GetComponent<PartyMemberGUI>().SwitchHPandMPStats(); } } }