430 lines
14 KiB
C#
430 lines
14 KiB
C#
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;
|
|
|
|
// 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);
|
|
}
|
|
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);
|
|
|
|
activeShelf = null;
|
|
if (activeNPC != null)
|
|
{
|
|
activeNPC.ResumeMovement();
|
|
}
|
|
activeNPC = null;
|
|
activePlayer = null;
|
|
activeTill = null;
|
|
activeWorkbench = null;
|
|
}
|
|
|
|
// --- 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();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
// --- 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
|
|
}
|
|
}
|
|
|