canto/Assets/Scripts/Interaction/Gate.cs
2025-08-14 19:11:32 -04:00

121 lines
3.2 KiB
C#

using System;
using KitsuneCafe.ItemSystem;
using KitsuneCafe.Sys;
using KitsuneCafe.Sys.Attributes;
using UnityEngine;
using UnityEngine.Events;
namespace KitsuneCafe.Interaction
{
using Result = IInteractable.Result;
public class Gate : MonoBehaviour, IInteractable
{
public enum Requirement
{
None,
Key,
Switch
}
[SerializeField]
private bool isOpen;
[SerializeField]
private bool isLocked;
[SerializeField, ShowIf("isLocked")]
private Requirement requirement;
[SerializeField, ShowIf("requirement", Requirement.Key)]
private Item key;
[SerializeField, ShowIf("requirement", Requirement.Key)]
private bool consumeKey;
[SerializeField]
private UnityEvent opened = default;
[SerializeField]
private UnityEvent closed = default;
public bool IsInteractable => true;
public bool IsOpen => isOpen;
public bool IsLocked => isLocked;
public IResult<Unit, InteractionError> Interact(IInteractor interactor)
{
return isOpen switch
{
true => TryClose(interactor),
false => TryOpen(interactor),
};
}
private IResult<Unit, InteractionError> TryClose(IInteractor interactor)
{
if (!isOpen)
{
return Result.Ok();
}
return ForceClosed();
}
private IResult<Unit, InteractionError> TryOpen(IInteractor interactor)
{
return requirement switch
{
_ when isOpen => Result.Ok(),
_ when !isLocked => ForceOpen(),
Requirement.None => Result.Err(InteractionErrorCode.Locked),
Requirement.Key => TryOpenWithKey(interactor),
Requirement.Switch => Result.Err(InteractionErrorCode.RequiresSwitch),
var x => throw new ArgumentException($"{gameObject.name} requested invalid requirement type {x}")
};
}
private IResult<Unit, InteractionError> TryOpenWithKey(IInteractor interactor)
{
if (interactor.TryGetComponent<IInventory<InventoryItem>>(out var inventory) && inventory.Has(key))
{
if (consumeKey)
{
inventory.Remove(key);
}
isLocked = false;
ForceOpen();
return Result.Ok();
}
else
{
return Result.Err(InteractionErrorCode.MissingItem);
}
}
public void ForceClosedAndForget()
{
isOpen = false;
closed.Invoke();
}
public IResult<Unit, InteractionError> ForceClosed()
{
ForceClosedAndForget();
return Result.Ok();
}
public void ForceOpenAndForget()
{
isOpen = true;
opened.Invoke();
}
public IResult<Unit, InteractionError> ForceOpen()
{
ForceOpenAndForget();
return Result.Ok();
}
}
}