Files
MedievalShopkeeper/Assets/Scripts/Shelf.cs

187 lines
6.1 KiB
C#
Raw Normal View History

2026-09-03 16:35:05 +01:00
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<GameObject> visualPrefabs = new List<GameObject>();
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<StockBox>();
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;
/// <summary>
/// Called by NPCs when they want to take an item to put in their basket.
/// </summary>
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<Collider>())
{
Destroy(col);
}
visualPrefabs.Add(vis);
}
}
}
}