using System.Collections.Generic; using UnityEngine; namespace MedievalShopkeeper { public class Shelf : Interactable { [Header("Shelf Settings")] [Tooltip("The maximum amount of items this shelf can hold.")] [SerializeField] private int maxCapacity = 10; [Tooltip("Transforms where visual prefabs should be spawned. The array size visually dictates capacity layout (can be fewer than maxCapacity, just overlaps/stacks visually).")] [SerializeField] private Transform[] displaySpots; [Header("Current Status (Read-Only)")] [SerializeField] private ItemData assignedItem; [SerializeField] private int currentStock = 0; private List visualPrefabs = new List(); public ItemData AssignedItem => assignedItem; public int CurrentStock => currentStock; public override string InteractionPrompt { get { if (assignedItem != null) { return $"Restock {assignedItem.itemName} ({currentStock}/{maxCapacity})"; } return "Stock Shelf (Empty)"; } } public override void Interact(PlayerController player) { base.Interact(player); if (UIManager.Instance != null) { UIManager.Instance.OpenShelfMenu(this, player); } else { // Fallback to auto-stocking if no UI manager exists StockFromPlayer(player); } } public void StockFromPlayer(PlayerController player) { if (!player.IsCarryingItem) { Debug.Log("[Shelf] Player is not carrying any stock box."); return; } GameObject carriedObj = player.CurrentCarriedItem; StockBox stockBox = carriedObj.GetComponent(); if (stockBox == null) { Debug.LogWarning("[Shelf] Carried item is not a StockBox!"); return; } // Dynamically assign item if empty if (currentStock == 0) { assignedItem = stockBox.itemData; } // Check if items match if (assignedItem != stockBox.itemData) { Debug.Log($"[Shelf] Mismatch! Shelf holds {assignedItem.itemName}, but box contains {stockBox.itemData.itemName}."); return; } // Calculate how much to transfer int spaceAvailable = maxCapacity - currentStock; if (spaceAvailable <= 0) { Debug.Log("[Shelf] Shelf is already full!"); return; } int transferAmount = Mathf.Min(spaceAvailable, stockBox.quantity); // Transfer currentStock += transferAmount; stockBox.RemoveQuantity(transferAmount); Debug.Log($"[Shelf] Restocked {transferAmount}x {assignedItem.itemName}. Shelf is now at {currentStock}/{maxCapacity}."); UpdateVisuals(); // If box is empty, drop and destroy it if (stockBox.quantity <= 0) { GameObject dropped = player.DropCarriedItem(); if (dropped != null) Destroy(dropped); } } public void EmptyShelf() { if (currentStock <= 0 || assignedItem == null) { Debug.Log("[Shelf] Shelf is already empty."); return; } // Return items to virtual Shop Inventory if (ShopInventory.Instance != null) { ShopInventory.Instance.AddStock(assignedItem, currentStock); Debug.Log($"[Shelf] Emptied {currentStock}x {assignedItem.itemName} back to Shop Inventory."); } else { Debug.LogWarning("[Shelf] No ShopInventory found to return items to! Items lost."); } currentStock = 0; assignedItem = null; UpdateVisuals(); } public bool HasStock => currentStock > 0 && assignedItem != null; /// /// Called by NPCs when they want to take an item to put in their basket. /// public bool TryTakeItem(out ItemData purchasedItem) { purchasedItem = null; if (currentStock > 0 && assignedItem != null) { purchasedItem = assignedItem; currentStock--; if (currentStock == 0) { assignedItem = null; // Free up the shelf for a different item if desired } UpdateVisuals(); return true; } return false; } private void UpdateVisuals() { // Clear old visuals foreach (var vis in visualPrefabs) { if (vis != null) Destroy(vis); } visualPrefabs.Clear(); if (assignedItem == null || assignedItem.displayPrefab == null || displaySpots == null || displaySpots.Length == 0) return; // Spawn new visuals based on stock // We map the stock linearly across available display spots. int visualsToSpawn = Mathf.Min(currentStock, displaySpots.Length); for (int i = 0; i < visualsToSpawn; i++) { GameObject vis = Instantiate(assignedItem.displayPrefab, displaySpots[i].position, displaySpots[i].rotation, displaySpots[i]); vis.transform.localScale = assignedItem.displayScale; // Destroy any colliders on the visual so it doesn't block rays foreach(var col in vis.GetComponentsInChildren()) { Destroy(col); } visualPrefabs.Add(vis); } } } }