Files
MedievalShopkeeper/Assets/Scripts/UIManager.cs

430 lines
14 KiB
C#
Raw Normal View History

2026-09-03 16:35:05 +01:00
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace MedievalShopkeeper
{
public class UIManager : MonoBehaviour
{
public static UIManager Instance { get; private set; }
[Header("HUD Elements")]
[Tooltip("Text element for showing Time of Day (e.g. 08:00)")]
[SerializeField] private TextMeshProUGUI timeText;
[Tooltip("Text element for showing current money")]
[SerializeField] private TextMeshProUGUI moneyText;
[Tooltip("Text element for showing customer count")]
[SerializeField] private TextMeshProUGUI customersText;
[Tooltip("Text element for showing event alerts (e.g. Goblin Raid!)")]
[SerializeField] private TextMeshProUGUI alertText;
[Header("Context Menu Panels")]
[SerializeField] private GameObject shelfMenuPanel;
[SerializeField] private GameObject npcMenuPanel;
[SerializeField] private GameObject inventoryMenuPanel;
[SerializeField] private GameObject tillMenuPanel;
[SerializeField] private GameObject workbenchMenuPanel;
2026-09-03 16:35:05 +01:00
// Active context tracking
private Shelf activeShelf;
private CustomerNPC activeNPC;
private PlayerController activePlayer;
private ShopTill activeTill;
[Header("Inventory Test Fields")]
[Tooltip("Assign an ItemData here to test Buy/Sell/Discard buttons via the Inspector/UI until a full scrolling list is built.")]
public ItemData testInventoryItem;
public int testTransactionAmount = 5;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
// Hide all menus initially
CloseAllMenus();
if (alertText != null) alertText.gameObject.SetActive(false);
}
private void Start()
{
// Subscribe to GameManager events
if (GameManager.Instance != null)
{
GameManager.Instance.OnTimeChanged += UpdateTimeUI;
GameManager.Instance.OnMoneyChanged += UpdateMoneyUI;
GameManager.Instance.OnCustomerCountChanged += UpdateCustomersUI;
GameManager.Instance.OnRandomEventTriggered += ShowEventAlert;
// Initialize HUD with the starting values immediately
UpdateTimeUI(GameManager.Instance.CurrentHour, GameManager.Instance.CurrentMinute);
UpdateMoneyUI(GameManager.Instance.CurrentMoney);
UpdateCustomersUI(GameManager.Instance.CurrentCustomersInShop);
2026-09-03 16:35:05 +01:00
}
else
{
Debug.LogWarning("[UIManager] GameManager.Instance is missing! HUD will not update.");
}
}
private void OnDestroy()
{
if (GameManager.Instance != null)
{
GameManager.Instance.OnTimeChanged -= UpdateTimeUI;
GameManager.Instance.OnMoneyChanged -= UpdateMoneyUI;
GameManager.Instance.OnCustomerCountChanged -= UpdateCustomersUI;
GameManager.Instance.OnRandomEventTriggered -= ShowEventAlert;
}
}
#region HUD Updates
private void UpdateTimeUI(int hour, int minute)
{
if (timeText != null)
{
timeText.text = $"{hour:D2}:{minute:D2}";
}
}
private void UpdateMoneyUI(int money)
{
if (moneyText != null)
{
moneyText.text = $"{money} G";
}
}
private void UpdateCustomersUI(int customers)
{
if (customersText != null)
{
customersText.text = $"Customers: {customers}";
}
}
private void ShowEventAlert(GameEvent gameEvent)
{
if (alertText == null) return;
StopCoroutine(nameof(FadeAlertText));
StartCoroutine(FadeAlertText($"EVENT: {gameEvent}!"));
}
private IEnumerator FadeAlertText(string message)
{
alertText.text = message;
alertText.gameObject.SetActive(true);
alertText.alpha = 1f;
// Wait 3 seconds
yield return new WaitForSeconds(3f);
// Fade out
float fadeTime = 1.5f;
float t = 0;
while (t < fadeTime)
{
t += Time.deltaTime;
alertText.alpha = Mathf.Lerp(1f, 0f, t / fadeTime);
yield return null;
}
alertText.gameObject.SetActive(false);
}
#endregion
#region Context Menus
public void CloseAllMenus()
{
if (shelfMenuPanel != null) shelfMenuPanel.SetActive(false);
if (npcMenuPanel != null) npcMenuPanel.SetActive(false);
if (inventoryMenuPanel != null) inventoryMenuPanel.SetActive(false);
if (tillMenuPanel != null) tillMenuPanel.SetActive(false);
if (workbenchMenuPanel != null) workbenchMenuPanel.SetActive(false);
2026-09-03 16:35:05 +01:00
activeShelf = null;
if (activeNPC != null)
{
activeNPC.ResumeMovement();
}
2026-09-03 16:35:05 +01:00
activeNPC = null;
activePlayer = null;
activeTill = null;
activeWorkbench = null;
2026-09-03 16:35:05 +01:00
}
// --- SHELF MENU ---
public void OpenShelfMenu(Shelf shelf, PlayerController player)
{
CloseAllMenus();
activeShelf = shelf;
activePlayer = player;
if (shelfMenuPanel != null)
{
shelfMenuPanel.SetActive(true);
}
else
{
Debug.LogWarning("[UIManager] Shelf Menu Panel is not assigned!");
}
}
public void UI_StockShelf()
{
if (activeShelf != null && activePlayer != null)
{
activeShelf.StockFromPlayer(activePlayer);
}
CloseAllMenus();
}
public void UI_EmptyShelf()
{
if (activeShelf != null)
{
activeShelf.EmptyShelf();
}
CloseAllMenus();
}
public void UI_CheckShelf()
{
if (activeShelf != null)
{
string itemName = activeShelf.AssignedItem != null ? activeShelf.AssignedItem.itemName : "Empty";
Debug.Log($"[Shelf Status] Item: {itemName}, Stock: {activeShelf.CurrentStock}");
}
}
// --- NPC MENU ---
public void OpenNPCMenu(CustomerNPC npc, PlayerController player)
{
CloseAllMenus();
activeNPC = npc;
activePlayer = player;
if (activeNPC != null)
{
activeNPC.PauseMovement();
}
2026-09-03 16:35:05 +01:00
if (npcMenuPanel != null)
{
npcMenuPanel.SetActive(true);
}
else
{
Debug.LogWarning("[UIManager] NPC Menu Panel is not assigned!");
}
}
public void UI_TalkToNPC()
{
if (activeNPC != null)
{
activeNPC.TalkTo();
}
CloseAllMenus();
}
public void UI_KickOutNPC()
{
if (activeNPC != null)
{
activeNPC.KickOut();
}
CloseAllMenus();
}
public void UI_CheckNPC()
{
if (activeNPC != null)
{
Debug.Log($"[NPC Info] Name: {activeNPC.npcName}");
}
}
// --- TILL MENU ---
public void OpenTillMenu(ShopTill till, System.Collections.Generic.List<ItemData> basket)
{
CloseAllMenus();
activeTill = till;
if (tillMenuPanel != null)
{
tillMenuPanel.SetActive(true);
// Here is where you would populate a dynamic UI list of icons.
// Example debug output of what the UI should show:
string basketContents = "Customer Basket: ";
int total = 0;
foreach(var item in basket)
{
if (item != null)
{
basketContents += $"[{item.itemName} ({item.sellPrice}G)] ";
total += item.sellPrice;
}
}
Debug.Log($"[UIManager] Till Opened. {basketContents} | Total: {total}G");
}
else
{
Debug.LogWarning("[UIManager] Till Menu Panel is not assigned! Defaulting to auto-charge.");
// Fallback if no UI panel
if (activeTill != null) activeTill.ChargeCustomer();
}
}
public void UI_ChargeCustomer()
{
if (activeTill != null)
{
activeTill.ChargeCustomer();
}
CloseAllMenus();
}
private ShopWorkbench activeWorkbench;
private void Update()
{
PositionMenuOverObject(shelfMenuPanel, activeShelf != null ? activeShelf.transform : null);
PositionMenuOverObject(npcMenuPanel, activeNPC != null ? activeNPC.transform : null);
PositionMenuOverObject(tillMenuPanel, activeTill != null ? activeTill.transform : null);
PositionMenuOverObject(workbenchMenuPanel, activeWorkbench != null ? activeWorkbench.transform : null);
// Inventory doesn't usually hover over a specific object, but you could attach it to the player if you wanted.
}
private void PositionMenuOverObject(GameObject menuPanel, Transform target)
{
if (menuPanel != null && menuPanel.activeSelf && target != null && Camera.main != null)
{
// Float the menu slightly above the object's origin
Vector3 worldPos = target.position + Vector3.up * 2.5f;
Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
// Only show if the object is in front of the camera (z > 0)
if (screenPos.z > 0)
{
menuPanel.transform.position = screenPos;
}
}
}
// --- WORKBENCH MENU ---
public void OpenWorkbenchMenu(ShopWorkbench workbench)
{
CloseAllMenus();
activeWorkbench = workbench;
if (workbenchMenuPanel != null)
{
workbenchMenuPanel.SetActive(true);
}
else
{
Debug.LogWarning("[UIManager] Workbench Menu Panel is not assigned!");
}
}
public void UI_Workbench_MoveMode()
{
CloseAllMenus();
if (BuildManager.Instance != null) BuildManager.Instance.StartMoveMode();
}
public void UI_Workbench_SellMode()
{
CloseAllMenus();
if (BuildManager.Instance != null) BuildManager.Instance.StartSellMode();
}
public void UI_Workbench_RepairMode()
{
CloseAllMenus();
if (BuildManager.Instance != null) BuildManager.Instance.StartRepairMode();
}
public void UI_Workbench_CancelBuildMode()
{
if (BuildManager.Instance != null) BuildManager.Instance.CancelBuilding();
}
2026-09-03 16:35:05 +01:00
// --- INVENTORY MENU ---
public void OpenInventoryMenu(PlayerController player = null)
{
CloseAllMenus();
activePlayer = player;
if (inventoryMenuPanel != null)
{
inventoryMenuPanel.SetActive(true);
}
else
{
Debug.LogWarning("[UIManager] Inventory Menu Panel is not assigned!");
}
}
public void UI_BuyTestItem()
{
if (testInventoryItem != null && ShopInventory.Instance != null)
{
bool success = ShopInventory.Instance.BuyStock(testInventoryItem, testTransactionAmount);
if (success)
{
PlayerController targetPlayer = activePlayer != null ? activePlayer : FindObjectOfType<PlayerController>();
if (targetPlayer != null)
{
ShopInventory.Instance.WithdrawToPlayer(testInventoryItem, testTransactionAmount, targetPlayer);
CloseAllMenus();
}
}
}
}
public void UI_SellTestItem()
{
// Sell logic usually requires NPC interaction, but if selling back to supplier:
if (testInventoryItem != null && ShopInventory.Instance != null)
{
if (ShopInventory.Instance.RemoveStock(testInventoryItem, testTransactionAmount))
{
int totalSale = testInventoryItem.sellPrice * testTransactionAmount;
GameManager.Instance.AddMoney(totalSale);
Debug.Log($"[UIManager] Sold {testTransactionAmount}x {testInventoryItem.itemName} for {totalSale} G.");
}
}
}
public void UI_DiscardTestItem()
{
if (testInventoryItem != null && ShopInventory.Instance != null)
{
if (ShopInventory.Instance.RemoveStock(testInventoryItem, testTransactionAmount))
{
Debug.Log($"[UIManager] Discarded {testTransactionAmount}x {testInventoryItem.itemName}.");
}
}
}
#endregion
}
}