Files
HeadlessHazard/Assets/Code/Scripts/Interaction/ButtonSequenceDoorPuzzle.cs
2026-03-30 18:01:33 +02:00

190 lines
4.8 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Events;
public class ButtonSequenceDoorPuzzle : MonoBehaviour
{
[Header("References")]
[Tooltip("All available buttons for this puzzle.")]
[SerializeField] private WallInteractButton[] buttons;
[Tooltip("Door to open when the sequence is correct.")]
[SerializeField] private SlidingDoor targetDoor;
[Tooltip("Optional blocks controlled by this puzzle (reset with SetOff on start/wrong input).")]
[SerializeField] private TestBlock[] puzzleBlocks;
[Header("Sequence")]
[Tooltip("Button indices (from the buttons array) that must be pressed in order. Example: 2,0,3")]
[SerializeField] private int[] requiredSequence = { 0, 1, 2 };
[Tooltip("If true, wrong input resets progress back to 0.")]
[SerializeField] private bool resetOnWrongPress = true;
[Tooltip("If true, puzzle can only be solved once.")]
[SerializeField] private bool lockAfterSolved = true;
[Header("Debug")]
[SerializeField] private bool enableDebugLogs = true;
private int m_progress;
private bool m_isSolved;
private UnityAction[] m_cachedListeners;
private void OnEnable()
{
SetAllBlocksOff();
RegisterAllButtons();
}
private void OnDisable()
{
UnregisterAllButtons();
}
private void RegisterAllButtons()
{
if (buttons == null)
return;
m_cachedListeners = new UnityAction[buttons.Length];
for (int i = 0; i < buttons.Length; i++)
{
WallInteractButton button = buttons[i];
if (button == null)
continue;
int buttonIndex = i;
UnityAction action = () => OnButtonPressed(buttonIndex);
m_cachedListeners[i] = action;
button.OnInteract.AddListener(action);
}
}
private void UnregisterAllButtons()
{
if (buttons == null)
return;
for (int i = 0; i < buttons.Length; i++)
{
WallInteractButton button = buttons[i];
if (button == null)
continue;
if (m_cachedListeners != null && i < m_cachedListeners.Length && m_cachedListeners[i] != null)
button.OnInteract.RemoveListener(m_cachedListeners[i]);
}
m_cachedListeners = null;
m_progress = 0;
}
private void OnButtonPressed(int buttonIndex)
{
Log($"Button pressed: index {buttonIndex}");
if (m_isSolved && lockAfterSolved)
{
Log("Puzzle already solved and locked.");
return;
}
if (!IsSequenceValid())
{
Log("Invalid sequence configuration.");
return;
}
int expectedIndex = requiredSequence[m_progress];
Log($"Expected button index: {expectedIndex} (step {m_progress + 1}/{requiredSequence.Length})");
if (buttonIndex == expectedIndex)
{
m_progress++;
Log($"Correct input. Progress: {m_progress}/{requiredSequence.Length}");
if (m_progress >= requiredSequence.Length)
{
SolvePuzzle();
}
return;
}
if (resetOnWrongPress)
{
Log("Wrong input. Resetting sequence and turning puzzle blocks OFF.");
m_progress = 0;
SetAllBlocksOff();
return;
}
Log("Wrong input, but resetOnWrongPress is disabled.");
}
private bool IsSequenceValid()
{
if (requiredSequence == null || requiredSequence.Length == 0)
return false;
if (buttons == null || buttons.Length == 0)
return false;
for (int i = 0; i < requiredSequence.Length; i++)
{
int index = requiredSequence[i];
if (index < 0 || index >= buttons.Length)
return false;
}
return true;
}
private void SolvePuzzle()
{
m_isSolved = true;
m_progress = 0;
Log("Sequence completed. Opening door.");
if (targetDoor != null)
targetDoor.Open();
}
private void SetAllBlocksOff()
{
if (puzzleBlocks == null)
return;
for (int i = 0; i < puzzleBlocks.Length; i++)
{
if (puzzleBlocks[i] == null)
continue;
puzzleBlocks[i].SetOff();
}
}
private void Log(string message)
{
if (!enableDebugLogs)
return;
Debug.Log($"[{nameof(ButtonSequenceDoorPuzzle)}] {message}", this);
}
#if UNITY_EDITOR
private void OnValidate()
{
if (requiredSequence == null)
return;
for (int i = 0; i < requiredSequence.Length; i++)
{
requiredSequence[i] = Math.Max(0, requiredSequence[i]);
}
}
#endif
}