Files

213 lines
6.8 KiB
C#

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 isBroken { get; private set; }
public bool HasStock => !isBroken && 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 (HasStock)
{
purchasedItem = assignedItem;
currentStock--;
if (currentStock <= 0)
{
assignedItem = null;
}
UpdateVisuals();
return true;
}
return false;
}
public void BreakShelf()
{
if (isBroken) return;
isBroken = true;
currentStock = 0;
assignedItem = null;
Debug.Log($"[Shelf] The {gameObject.name} was smashed by a Raider!");
UpdateVisuals();
}
public void RepairShelf()
{
if (!isBroken) return;
isBroken = false;
Debug.Log($"[Shelf] The {gameObject.name} was repaired!");
}
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;
for (int i = 0; i < currentStock; i++)
{
int spotIndex = i % displaySpots.Length;
int stackIndex = i / displaySpots.Length; // 0 for front row, 1 for back row, etc.
Transform spot = displaySpots[spotIndex];
GameObject vis = Instantiate(assignedItem.displayPrefab, spot.position, spot.rotation, spot);
// Shift subsequent rows backwards/upwards.
// Z is usually backward, Y is upward. You can adjust this offset.
vis.transform.localPosition += new Vector3(0, stackIndex * 0.15f, stackIndex * -0.2f);
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);
}
}
}
}