using UnityEngine; using UnityEngine.Events; using System.Collections.Generic; /// /// Interaction requirement that allows slotting, swapping, or picking up items in a slot. /// [RequireComponent(typeof(Interactable))] [RequireComponent(typeof(Pickup))] public class SlotItemBehavior : InteractionRequirementBase { [Header("Slot State")] /// /// The item currently slotted in this slot. /// public PickupItemData currentlySlottedItem; /// /// The renderer for the slotted item's sprite. /// public SpriteRenderer slottedItemRenderer; private GameObject _cachedSlottedObject = null; // Helper for slotting an object, with option to skip destruction (for swap) private void SetSlottedObject(GameObject obj) { _cachedSlottedObject = obj; if (_cachedSlottedObject != null) { _cachedSlottedObject.SetActive(false); } } private void RemoveSlottedObject() { if (_cachedSlottedObject != null) { Destroy(_cachedSlottedObject); _cachedSlottedObject = null; } } private void CacheSlottedObject(GameObject obj) { // Only destroy if not swapping RemoveSlottedObject(); SetSlottedObject(obj); } private void RestoreSlottedObject(Vector3 position) { if (_cachedSlottedObject != null) { _cachedSlottedObject.transform.position = position; _cachedSlottedObject.transform.SetParent(null); _cachedSlottedObject.SetActive(true); _cachedSlottedObject = null; } } /// /// Attempts to interact with the slot, handling slotting, swapping, or picking up items. /// /// The follower attempting the interaction. /// True if the interaction was successful, false otherwise. public override bool TryInteract(FollowerController follower) { var heldItem = follower.CurrentlyHeldItem; var heldObj = follower.GetHeldPickupObject(); var pickup = GetComponent(); var slotItem = pickup != null ? pickup.itemData : null; var config = GameManager.Instance.GetSlotItemConfig(slotItem); var allowed = config?.allowedItems ?? new List(); var forbidden = config?.forbiddenItems ?? new List(); // CASE 1: No held item, slot has item -> pick up slotted item if (heldItem == null && _cachedSlottedObject != null) { follower.SetHeldItemFromObject(_cachedSlottedObject); RemoveSlottedObject(); currentlySlottedItem = null; UpdateSlottedSprite(); return true; } // CASE 2: Held item, slot has item -> swap if (heldItem != null && _cachedSlottedObject != null) { var followerHeldObj = heldObj; var followerHeldItem = heldItem; var slotObj = _cachedSlottedObject; var slotItemData = currentlySlottedItem; // 1. Slot the follower's held object (do NOT destroy the old one) SetSlottedObject(followerHeldObj); currentlySlottedItem = followerHeldItem; UpdateSlottedSprite(); // 2. Give the slot's object to the follower follower.SetHeldItemFromObject(slotObj); return true; } // CASE 3: Held item, slot empty -> slot the held item if (heldItem != null && _cachedSlottedObject == null) { if (forbidden.Contains(heldItem)) { DebugUIMessage.Show("Can't place that here."); return false; } CacheSlottedObject(heldObj); currentlySlottedItem = heldItem; UpdateSlottedSprite(); follower.ClearHeldItem(); if (allowed.Contains(heldItem)) { OnSuccess?.Invoke(); return true; } else { DebugUIMessage.Show("I'm not sure this works."); OnFailure?.Invoke(); return true; } } // CASE 4: No held item, slot empty -> show warning if (heldItem == null && _cachedSlottedObject == null) { DebugUIMessage.Show("This requires an item."); return false; } return false; } /// /// Updates the sprite and scale for the currently slotted item. /// private void UpdateSlottedSprite() { if (slottedItemRenderer != null && currentlySlottedItem != null && currentlySlottedItem.mapSprite != null) { slottedItemRenderer.sprite = currentlySlottedItem.mapSprite; // Scale sprite to desired height, preserve aspect ratio, compensate for parent scale float desiredHeight = GameManager.Instance.HeldIconDisplayHeight; var sprite = currentlySlottedItem.mapSprite; float spriteHeight = sprite.bounds.size.y; float spriteWidth = sprite.bounds.size.x; Vector3 parentScale = slottedItemRenderer.transform.parent != null ? slottedItemRenderer.transform.parent.localScale : Vector3.one; if (spriteHeight > 0f) { float uniformScale = desiredHeight / spriteHeight; float scale = uniformScale / Mathf.Max(parentScale.x, parentScale.y); slottedItemRenderer.transform.localScale = new Vector3(scale, scale, 1f); } } else if (slottedItemRenderer != null) { slottedItemRenderer.sprite = null; } } }