using UnityEngine; using System.Collections.Generic; using System.Linq; public class ShopInventory : MonoBehaviour { public static ShopInventory Instance; public GameObject inventoryUIPanel; // Reference to the inventory UI panel public Transform spawnLocation; // Assign delivery location in Inspector [Header("Item Data Assets")] public List itemDataAssets; // Assign in Inspector private Dictionary itemDatabase = new(); private Dictionary itemStock = new(); // Track stock per item private bool isInventoryOpen = false; public bool IsInventoryOpen => isInventoryOpen; void Awake() { Instance = this; InitializeInventory(); if (inventoryUIPanel != null) inventoryUIPanel.SetActive(false); } void InitializeInventory() { itemDatabase.Clear(); itemStock.Clear(); foreach (var data in itemDataAssets) { if (data != null && !itemDatabase.ContainsKey(data.itemName)) { itemDatabase[data.itemName] = data; itemStock[data.itemName] = 0; // Default starting stock Debug.Log($"📦 Added item to inventory: {data.itemName} - £{data.price:0.00}"); } } } // --- Public API for UI and AI --- public List GetItemNames() => new List(itemDatabase.Keys); public ShopItemData GetItemData(string itemName) => itemDatabase.ContainsKey(itemName) ? itemDatabase[itemName] : null; public int GetStock(string itemName) => itemStock.ContainsKey(itemName) ? itemStock[itemName] : 0; // --- UI Control --- public void OpenInventory() { if (isInventoryOpen) return; isInventoryOpen = true; if (inventoryUIPanel != null) inventoryUIPanel.SetActive(true); Debug.Log("📦 Opening shop inventory..."); ShopkeeperUIController.Instance?.ShowInventory(itemDatabase); LockCursor(false); // Unlock cursor for UI } public void CloseInventory() { if (!isInventoryOpen) return; isInventoryOpen = false; if (inventoryUIPanel != null) inventoryUIPanel.SetActive(false); Debug.Log("📦 Closing shop inventory..."); ShopkeeperUIController.Instance?.HideInventory(); LockCursor(true); // Lock cursor for gameplay } void LockCursor(bool locked) { Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None; Cursor.visible = !locked; } // --- Stock and Price Management --- public void RestockItem(string itemName, int amount) { if (!itemDatabase.ContainsKey(itemName)) { Debug.LogWarning($"Item {itemName} not found in inventory."); return; } var item = itemDatabase[itemName]; float totalCost = item.price * amount; if (FinanceManager.Instance == null || FinanceManager.Instance.SpendMoney(totalCost)) { itemStock[itemName] += amount; GeneralUIController.Instance?.ShowMessage($"📦 Stock Updated: +{amount} {itemName}"); SpawnItems(itemName, amount); } } public void SetItemPrice(string itemName, float price) { if (itemDatabase.ContainsKey(itemName)) { itemDatabase[itemName].price = price; Debug.Log($"Set price of {itemName} to £{price:0.00}"); } else { Debug.LogWarning($"Item {itemName} not found in inventory."); } } // --- Spawning Items --- void SpawnItems(string itemName, int amount) { var data = itemDatabase[itemName]; int packSize = Mathf.Max(1, data.packSize); if (amount < packSize || data.cratePrefab == null) { // Spawn individual items for (int i = 0; i < amount; i++) { SpawnSingleItem(data, spawnLocation.position + Vector3.up * 2f); } } else { int numCrates = amount / packSize; int leftovers = amount % packSize; for (int c = 0; c < numCrates; c++) { // Spawn crate (make sure crate prefab has a Rigidbody and is NOT kinematic) GameObject crate = Instantiate(data.cratePrefab, spawnLocation.position + Vector3.up * 2f, Quaternion.identity); crate.name = $"{itemName}_Crate"; // Arrange items in a grid inside the crate, using localPosition int gridCols = Mathf.CeilToInt(Mathf.Sqrt(packSize)); for (int i = 0; i < packSize; i++) { int row = i / gridCols; int col = i % gridCols; Vector3 offset = new Vector3(col * 0.5f, 0.2f, row * 0.3f); // Y offset to place items above crate floor GameObject item = SpawnSingleItem(data, Vector3.zero); // Spawn at origin, we'll set localPosition item.transform.SetParent(crate.transform); item.transform.localPosition = offset; // Make item kinematic so it stays in place until crate is opened Rigidbody rb = item.GetComponent(); if (rb != null) rb.isKinematic = true; } } // Spawn any leftovers as individuals for (int i = 0; i < leftovers; i++) { SpawnSingleItem(data, spawnLocation.position + Vector3.up * 2f); } } } GameObject SpawnSingleItem(ShopItemData data, Vector3 position) { GameObject newItem = Instantiate(data.prefab, position, Quaternion.identity); newItem.name = data.itemName; Rigidbody rb = newItem.GetComponent(); if (rb == null) rb = newItem.AddComponent(); Collider col = newItem.GetComponent(); if (col != null && col.sharedMaterial == null) { PhysicsMaterial bounceMat = new PhysicsMaterial("CartoonBounce"); bounceMat.bounciness = 0.2f; bounceMat.bounceCombine = PhysicsMaterialCombine.Maximum; bounceMat.frictionCombine = PhysicsMaterialCombine.Minimum; col.sharedMaterial = bounceMat; } rb.AddForce(new Vector3(Random.Range(-1f, 1f), 0, Random.Range(-1f, 1f)) * 2f, ForceMode.Impulse); var shopItem = newItem.GetComponent(); if (shopItem != null) shopItem.data = data; return newItem; } }