Files
modular-vr/Assets/Station46/Modules/Terminal/Scripts/Terminal.cs
2023-05-16 15:01:06 +02:00

161 lines
5.4 KiB
C#

using System.Collections.Generic;
using System.Linq;
using EscapeRoomEngine.Engine.Runtime.Modules;
using EscapeRoomEngine.Engine.Runtime.Modules.State;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using JetBrains.Annotations;
using NaughtyAttributes;
using Station46.Modules.Hover_Sphere.Scripts;
using Station46.Modules.Symbols.Scripts;
using Station46.Scripts;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
namespace Station46.Modules.Terminal.Scripts
{
/// <summary>
/// The main component for the terminal module.
/// </summary>
[RequireComponent(typeof(Animator))]
public class Terminal : CyclicStepPuzzle
{
private static readonly int LightFlash = Animator.StringToHash("Light Flash");
[BoxGroup("Internal")] [Required]
public Emission terminalLight;
[BoxGroup("Internal")]
[ValidateInput("SymbolCount", "Must have same amount of symbols and slots.")]
public List<SymbolButton> symbols;
[BoxGroup("Internal")]
public List<Transform> symbolSlots;
[BoxGroup("Internal")]
public AudioSource wrongAudioSource;
private IOption<Symbol> _activeSymbol;
private Animator _animator;
private Ball _ball;
private void Awake()
{
_animator = GetComponent<Animator>();
List<SymbolButton> symbolInstances = new(symbols.Count);
symbolInstances.AddRange(symbols.Select((t, i) => Instantiate(t, symbolSlots[i], false)));
symbols = symbolInstances;
}
protected override void Start()
{
base.Start();
PuzzleEvent += (_, type) =>
{
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (type)
{
case PuzzleEventType.Restarted:
_ball.Active = true;
terminalLight.color = EscapeRoomEngine.Engine.Runtime.Engine.Theme.puzzleColor.hdr;
symbols.ForEach(symbol => symbol.Enable());
break;
case PuzzleEventType.Solved:
_ball.Active = false;
terminalLight.color = EscapeRoomEngine.Engine.Runtime.Engine.Theme.solvedColor.hdr;
symbols.ForEach(symbol => symbol.Disable());
break;
case PuzzleEventType.WrongInput:
_animator.SetTrigger(LightFlash);
wrongAudioSource.Play();
break;
}
};
symbols.ForEach(symbol =>
{
symbol.ButtonEvent += (_, type) =>
{
if (type == ButtonEventType.Pressed)
{
PressedSymbol(symbol.symbolNumber);
}
};
});
_ball.ring.symbols.ForEach(symbol =>
{
symbol.SymbolEvent += type =>
_activeSymbol = type == SymbolEventType.Activated ? Some<Symbol>.Of(symbol) : None<Symbol>.New();
});
}
public override void SetModule(Module module)
{
base.SetModule(module);
// The terminal requires a related symbol ball module
var firstRelatedModule = Module.relatedModules[0];
if (firstRelatedModule.State is Ball ball)
{
_ball = ball;
}
else
{
throw new EngineException("Terminal was not assigned a related Ball.");
}
TurnOnLights();
}
[UsedImplicitly] // required in animation
internal void TurnOnLights()
{
terminalLight.active = true;
_ball.StatusLight = true;
}
[UsedImplicitly] // required in animation
internal void TurnOffLights()
{
terminalLight.active = false;
_ball.StatusLight = false;
}
private void PressedSymbol(int number)
{
if (!Solved)
{
Logger.Log($"Pressed symbol {number} on {this}", LogType.PuzzleDetail);
_activeSymbol.Match(some: symbol =>
{
if (number == symbol.symbolNumber)
{
CheckStep(symbol.symbolPosition);
}
else
{
WrongInput();
}
}, none: WrongInput);
}
}
#region Debug Buttons
[UsedImplicitly]
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void PressSymbol0() => PressedSymbol(0);
[UsedImplicitly]
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void PressSymbol1() => PressedSymbol(1);
[UsedImplicitly]
[Button(enabledMode: EButtonEnableMode.Playmode)]
public void PressSymbol2() => PressedSymbol(2);
#endregion
[UsedImplicitly] // used for field validation
private bool SymbolCount(List<SymbolButton> list) => list.Count == symbolSlots.Count;
}
}