Files
AppleHillsProduction/Assets/Scripts/Interactions/ItemSlot.cs

179 lines
7.2 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using System; // for Action<T>
namespace Interactions
{
// New enum describing possible states for the slotted item
public enum ItemSlotState
{
None,
Correct,
Incorrect,
Forbidden
}
/// <summary>
/// Interaction requirement that allows slotting, swapping, or picking up items in a slot.
/// </summary>
[RequireComponent(typeof(Interactable))]
public class ItemSlot : Pickup
{
// Tracks the current state of the slotted item
private ItemSlotState _currentState = ItemSlotState.None;
/// <summary>
/// Read-only access to the current slotted item state.
/// </summary>
public ItemSlotState CurrentSlottedState => _currentState;
public UnityEvent onItemSlotted;
public UnityEvent onItemSlotRemoved;
public UnityEvent onCorrectItemSlotted;
// Native C# event alternative to the UnityEvent for code-only subscribers
public event Action<PickupItemData, PickupItemData> OnCorrectItemSlotted;
public UnityEvent onIncorrectItemSlotted;
public UnityEvent onForbiddenItemSlotted;
private PickupItemData _currentlySlottedItemData;
public SpriteRenderer slottedItemRenderer;
private GameObject _currentlySlottedItemObject = null;
public GameObject GetSlottedObject()
{
return _currentlySlottedItemObject;
}
public void SetSlottedObject(GameObject obj)
{
_currentlySlottedItemObject = obj;
if (_currentlySlottedItemObject != null)
{
_currentlySlottedItemObject.SetActive(false);
}
}
protected override void OnCharacterArrived()
{
var heldItemData = FollowerController.CurrentlyHeldItemData;
var heldItemObj = FollowerController.GetHeldPickupObject();
var config = GameManager.Instance.GetSlotItemConfig(itemData);
var forbidden = config?.forbiddenItems ?? new List<PickupItemData>();
// Held item, slot empty -> try to slot item
if (heldItemData != null && _currentlySlottedItemObject == null)
{
// First check for forbidden items at the very start so we don't continue unnecessarily
if (PickupItemData.ListContainsEquivalent(forbidden, heldItemData))
{
DebugUIMessage.Show("Can't place that here.", Color.red);
onForbiddenItemSlotted?.Invoke();
_currentState = ItemSlotState.Forbidden;
Interactable.BroadcastInteractionComplete(false);
return;
}
SlotItem(heldItemObj, heldItemData, true);
return;
}
// Either pickup or swap items
if ((heldItemData == null && _currentlySlottedItemObject != null)
|| (heldItemData != null && _currentlySlottedItemObject != null))
{
FollowerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false);
onItemSlotRemoved?.Invoke();
_currentState = ItemSlotState.None;
SlotItem(heldItemObj, heldItemData, _currentlySlottedItemObject == null);
return;
}
// No held item, slot empty -> show warning
if (heldItemData == null && _currentlySlottedItemObject == null)
{
DebugUIMessage.Show("This requires an item.", Color.red);
return;
}
}
/// <summary>
/// Updates the sprite and scale for the currently slotted item.
/// </summary>
private void UpdateSlottedSprite()
{
if (slottedItemRenderer != null && _currentlySlottedItemData != null && _currentlySlottedItemData.mapSprite != null)
{
slottedItemRenderer.sprite = _currentlySlottedItemData.mapSprite;
// Scale sprite to desired height, preserve aspect ratio, compensate for parent scale
float desiredHeight = GameManager.Instance.HeldIconDisplayHeight;
var sprite = _currentlySlottedItemData.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;
}
}
public void SlotItem(GameObject itemToSlot, PickupItemData itemToSlotData, bool clearFollowerHeldItem = true)
{
if (itemToSlot == null)
{
_currentlySlottedItemObject = null;
_currentlySlottedItemData = null;
// Clear state when no item is slotted
_currentState = ItemSlotState.None;
}
else
{
itemToSlot.SetActive(false);
itemToSlot.transform.SetParent(null);
SetSlottedObject(itemToSlot);
_currentlySlottedItemData = itemToSlotData;
}
if (clearFollowerHeldItem)
{
FollowerController.ClearHeldItem();
}
UpdateSlottedSprite();
// Once an item is slotted, we know it is not forbidden, so we can skip that check, but now check if it was
// the correct item we're looking for
var config = GameManager.Instance.GetSlotItemConfig(itemData);
var allowed = config?.allowedItems ?? new List<PickupItemData>();
if (PickupItemData.ListContainsEquivalent(allowed, itemToSlotData))
{
if (itemToSlot != null)
{
DebugUIMessage.Show("You correctly slotted " + itemToSlotData.itemName + " into: " + itemData.itemName, Color.green);
onCorrectItemSlotted?.Invoke();
OnCorrectItemSlotted?.Invoke(itemData, _currentlySlottedItemData);
_currentState = ItemSlotState.Correct;
}
Interactable.BroadcastInteractionComplete(true);
}
else
{
if (itemToSlot != null)
{
DebugUIMessage.Show("I'm not sure this works.", Color.yellow);
onIncorrectItemSlotted?.Invoke();
_currentState = ItemSlotState.Incorrect;
}
Interactable.BroadcastInteractionComplete(false);
}
}
}
}