Additional Levels added. Mostly just base artwork so far.
This commit is contained in:
@@ -1,7 +1,295 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AYellowpaper.SerializedCollections;
|
||||
using BriarQueen.Data.Identifiers;
|
||||
using BriarQueen.Data.IO.Saves;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Managers.Hints.Data;
|
||||
using BriarQueen.Framework.Managers.Levels.Data;
|
||||
using BriarQueen.Framework.Services.Puzzles.Base;
|
||||
using BriarQueen.Game.Levels.ChapterOne.LaxleyHouse.FireplaceLockbox;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using MemoryPack;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace BriarQueen.Game.Levels.ChapterOne.LaxleyHouse
|
||||
{
|
||||
public class FireplaceLockbox
|
||||
[Serializable]
|
||||
[MemoryPackable]
|
||||
public partial struct FireplaceLockboxPuzzleState
|
||||
{
|
||||
|
||||
public int SolutionSlotOne;
|
||||
public int SolutionSlotTwo;
|
||||
public int SolutionSlotThree;
|
||||
|
||||
public int SlotOneValue;
|
||||
public int SlotTwoValue;
|
||||
public int SlotThreeValue;
|
||||
}
|
||||
|
||||
public class FireplaceLockboxBasePuzzle : BasePuzzle, IPuzzleStateful
|
||||
{
|
||||
private const int MinDigit = 1;
|
||||
private const int MaxDigit = 9;
|
||||
|
||||
public override string PuzzleID => PuzzleIdentifiers.AllPuzzles[PuzzleKey.FireplaceLockboxPuzzle];
|
||||
public override string LevelName => "Fireplace Lockbox";
|
||||
public override Dictionary<int, BaseHint> Hints { get; }
|
||||
|
||||
[Header("Components")]
|
||||
[SerializeField]
|
||||
[SerializedDictionary(keyName: "Lockbox Number", valueName: "Number Sprite")]
|
||||
private SerializedDictionary<int, Sprite> _numberSprites = new();
|
||||
|
||||
[Header("Puzzle Slots")]
|
||||
[SerializeField]
|
||||
private List<LockboxSlot> _lockboxSlots = new();
|
||||
|
||||
[Header("Level State")]
|
||||
[SerializeField]
|
||||
private Image _backgroundImage;
|
||||
|
||||
[SerializeField]
|
||||
private Sprite _lockBoxOpenSprite;
|
||||
|
||||
[SerializeField]
|
||||
private List<BaseItem> _lockboxItems = new();
|
||||
|
||||
private int _solutionSlotOne = -1;
|
||||
private int _solutionSlotTwo = -1;
|
||||
private int _solutionSlotThree = -1;
|
||||
|
||||
public bool IsCompleted { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
InitializeSlots();
|
||||
}
|
||||
|
||||
protected override async UniTask PostLoadInternal()
|
||||
{
|
||||
if (SaveManager.GetLevelFlag(LevelFlag.LaxleyLockboxOpened))
|
||||
{
|
||||
DisableSlots();
|
||||
await OpenLockbox();
|
||||
}
|
||||
}
|
||||
|
||||
public override async UniTask CompletePuzzle()
|
||||
{
|
||||
if (SaveManager.GetLevelFlag(LevelFlag.LaxleyLockboxOpened))
|
||||
return;
|
||||
|
||||
IsCompleted = true;
|
||||
|
||||
SaveManager.SetLevelFlag(LevelFlag.LaxleyLockboxOpened, true);
|
||||
SaveManager.SetPuzzleCompleted(PuzzleKey.FireplaceLockboxPuzzle, true);
|
||||
|
||||
DisableSlots();
|
||||
|
||||
EventCoordinator.Publish(new FadeEvent(false, 0.5f));
|
||||
AudioManager.Play(AudioNameIdentifiers.Get(SFXKey.LockboxOpening));
|
||||
|
||||
await OpenLockbox();
|
||||
|
||||
EventCoordinator.Publish(new FadeEvent(true, 0.5f));
|
||||
}
|
||||
|
||||
private async UniTask OpenLockbox()
|
||||
{
|
||||
if (_backgroundImage != null)
|
||||
_backgroundImage.sprite = _lockBoxOpenSprite;
|
||||
|
||||
await GenerateLockboxItems();
|
||||
}
|
||||
|
||||
private async UniTask GenerateLockboxItems()
|
||||
{
|
||||
foreach (var item in _lockboxItems)
|
||||
{
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
if (SaveManager.CurrentSave.CollectedItems.All(x => x.UniqueIdentifier != item.ItemData.UniqueID))
|
||||
{
|
||||
item.CanvasGroup.alpha = 1f;
|
||||
item.CanvasGroup.blocksRaycasts = true;
|
||||
item.CanvasGroup.interactable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await DestructionService.Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask<byte[]> CaptureState()
|
||||
{
|
||||
var state = new FireplaceLockboxPuzzleState
|
||||
{
|
||||
SolutionSlotOne = _solutionSlotOne,
|
||||
SolutionSlotTwo = _solutionSlotTwo,
|
||||
SolutionSlotThree = _solutionSlotThree,
|
||||
SlotOneValue = _lockboxSlots.Count > 0 ? _lockboxSlots[0].CurrentValue : MinDigit,
|
||||
SlotTwoValue = _lockboxSlots.Count > 1 ? _lockboxSlots[1].CurrentValue : MinDigit,
|
||||
SlotThreeValue = _lockboxSlots.Count > 2 ? _lockboxSlots[2].CurrentValue : MinDigit
|
||||
};
|
||||
|
||||
return UniTask.FromResult(MemoryPackSerializer.Serialize(state));
|
||||
}
|
||||
|
||||
public UniTask RestoreState(byte[] state)
|
||||
{
|
||||
if (state == null || state.Length == 0)
|
||||
{
|
||||
GenerateSolutionIfNeeded();
|
||||
ApplyRandomDefaultSlotValues();
|
||||
ApplySolutionToCompletionCheck();
|
||||
|
||||
if (SaveManager.GetLevelFlag(LevelFlag.LaxleyLockboxOpened))
|
||||
DisableSlots();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
var restored = MemoryPackSerializer.Deserialize<FireplaceLockboxPuzzleState>(state);
|
||||
|
||||
_solutionSlotOne = WrapDigit(restored.SolutionSlotOne);
|
||||
_solutionSlotTwo = WrapDigit(restored.SolutionSlotTwo);
|
||||
_solutionSlotThree = WrapDigit(restored.SolutionSlotThree);
|
||||
|
||||
if (_lockboxSlots.Count > 0)
|
||||
_lockboxSlots[0].ApplyValueImmediate(restored.SlotOneValue);
|
||||
|
||||
if (_lockboxSlots.Count > 1)
|
||||
_lockboxSlots[1].ApplyValueImmediate(restored.SlotTwoValue);
|
||||
|
||||
if (_lockboxSlots.Count > 2)
|
||||
_lockboxSlots[2].ApplyValueImmediate(restored.SlotThreeValue);
|
||||
|
||||
ApplySolutionToCompletionCheck();
|
||||
|
||||
if (SaveManager.GetLevelFlag(LevelFlag.LaxleyLockboxOpened))
|
||||
DisableSlots();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
private void InitializeSlots()
|
||||
{
|
||||
if (_lockboxSlots == null)
|
||||
return;
|
||||
|
||||
foreach (var slot in _lockboxSlots)
|
||||
{
|
||||
if (slot == null)
|
||||
continue;
|
||||
|
||||
slot.Initialize(GetNumberSprite, OnSlotValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableSlots()
|
||||
{
|
||||
if (_lockboxSlots == null)
|
||||
return;
|
||||
|
||||
foreach (var slot in _lockboxSlots)
|
||||
{
|
||||
if (slot == null)
|
||||
continue;
|
||||
|
||||
slot.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyRandomDefaultSlotValues()
|
||||
{
|
||||
if (_lockboxSlots.Count > 0)
|
||||
_lockboxSlots[0].ApplyValueImmediate(GetRandomDigit());
|
||||
|
||||
if (_lockboxSlots.Count > 1)
|
||||
_lockboxSlots[1].ApplyValueImmediate(GetRandomDigit());
|
||||
|
||||
if (_lockboxSlots.Count > 2)
|
||||
_lockboxSlots[2].ApplyValueImmediate(GetRandomDigit());
|
||||
}
|
||||
|
||||
private int GetRandomDigit()
|
||||
{
|
||||
return Random.Range(MinDigit, MaxDigit + 1);
|
||||
}
|
||||
|
||||
private Sprite GetNumberSprite(int value)
|
||||
{
|
||||
value = WrapDigit(value);
|
||||
return _numberSprites.TryGetValue(value, out var sprite) ? sprite : null;
|
||||
}
|
||||
|
||||
private void OnSlotValueChanged()
|
||||
{
|
||||
ApplySolutionToCompletionCheck();
|
||||
|
||||
if (!SaveManager.GetLevelFlag(LevelFlag.LaxleyLockboxOpened) && IsCurrentInputCorrect())
|
||||
CompletePuzzle().Forget();
|
||||
}
|
||||
|
||||
private void ApplySolutionToCompletionCheck()
|
||||
{
|
||||
IsCompleted = IsCurrentInputCorrect();
|
||||
}
|
||||
|
||||
private bool IsCurrentInputCorrect()
|
||||
{
|
||||
if (_lockboxSlots == null || _lockboxSlots.Count < 3)
|
||||
return false;
|
||||
|
||||
return _lockboxSlots[0].CurrentValue == _solutionSlotOne &&
|
||||
_lockboxSlots[1].CurrentValue == _solutionSlotTwo &&
|
||||
_lockboxSlots[2].CurrentValue == _solutionSlotThree;
|
||||
}
|
||||
|
||||
private void GenerateSolutionIfNeeded()
|
||||
{
|
||||
if (HasValidSolution())
|
||||
return;
|
||||
|
||||
GenerateSolutionVariation();
|
||||
}
|
||||
|
||||
private bool HasValidSolution()
|
||||
{
|
||||
return _solutionSlotOne is >= MinDigit and <= MaxDigit &&
|
||||
_solutionSlotTwo is >= MinDigit and <= MaxDigit &&
|
||||
_solutionSlotThree is >= MinDigit and <= MaxDigit;
|
||||
}
|
||||
|
||||
private void GenerateSolutionVariation()
|
||||
{
|
||||
int[] digits = { 8, 4, 7 };
|
||||
|
||||
for (int i = digits.Length - 1; i > 0; i--)
|
||||
{
|
||||
int swapIndex = Random.Range(0, i + 1);
|
||||
(digits[i], digits[swapIndex]) = (digits[swapIndex], digits[i]);
|
||||
}
|
||||
|
||||
_solutionSlotOne = digits[0];
|
||||
_solutionSlotTwo = digits[1];
|
||||
_solutionSlotThree = digits[2];
|
||||
}
|
||||
|
||||
private int WrapDigit(int value)
|
||||
{
|
||||
value %= MaxDigit;
|
||||
|
||||
if (value <= 0)
|
||||
value += MaxDigit;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user