using System; using System.Collections.Generic; using UnityEngine; using RR.Common.Controls; using RR.Common.Managers; using RR.Common.UI; using RR.Game2D.Behaviour; using RR.Game2D.Core.Managers; using ControlsBoxStatus = RR.Common.Controls.BoxStatus; namespace RR.Common.Prizes { /// /// Исполнитель приза «Витрина». /// Показывает модальное окно с выбором ячейки, затем открывает её /// через . Количество ячеек берётся из ComSystemManager. /// public class PrizeStandPrize : PrizeBase { public override PrizeType Type => PrizeType.PrizeStand; public override bool IsGiving => _isGiving; private readonly Func _resolveModal; private bool _isGiving; private PrizeStandModal _activeModal; /// Делегат для поиска модального окна в текущих сценах. public PrizeStandPrize(Func resolveModal) { _resolveModal = resolveModal; } public override void Execute(MonoBehaviour host, LevelPrizeConfig config) { if (_isGiving) { Debug.LogWarning("[PrizeStandPrize] Уже идёт выдача."); return; } _isGiving = true; ShowPrizeStandSelectionAsync(); } private async void ShowPrizeStandSelectionAsync() { try { // Отписываемся от предыдущего модального окна, если было if (_activeModal != null) _activeModal.OnBoxSelected -= OnBoxSelected; _activeModal = _resolveModal?.Invoke(); if (_activeModal == null) { Debug.LogError("[PrizeStandPrize] PrizeStandModal не найден на сцене."); _isGiving = false; InvokeResult(false); return; } _activeModal.OnBoxSelected += OnBoxSelected; PrizeStandController stand = ComSystemManager.GetPrizeStandController(); PrizeStandConnectionInfo connectionInfo = PrizeSystemManager.Instance != null ? PrizeSystemManager.Instance.GetPrizeStandConnectionInfo() : new PrizeStandConnectionInfo(stand != null, stand != null ? stand.GetBoxesCount() : 0); float gameTime = GameManager.Instance != null ? GameManager.Instance.GetPendingOrCurrentWinGameTime() : 0f; int finalScore = ScoreSystem.Instance != null ? ScoreSystem.Instance.GetDisplayScore(gameTime, true) : 0; PrizeStandSettings settings = PrizeSystemManager.Instance != null ? PrizeSystemManager.Instance.GetPrizeStandSettings() : new PrizeStandSettings(); Dictionary boxStatuses = new(); if (stand != null && connectionInfo.IsConnected) { boxStatuses = await stand.GetStatusesAsync(); } _activeModal.Show( BuildAvailability(settings, connectionInfo, finalScore, boxStatuses), connectionInfo.IsConnected, connectionInfo.ConnectedBoxesCount, gameTime, finalScore, true); } catch (Exception ex) { Debug.LogError($"[PrizeStandPrize] Не удалось подготовить витрину: {ex.Message}"); if (_activeModal != null) { _activeModal.OnBoxSelected -= OnBoxSelected; _activeModal = null; } _isGiving = false; InvokeResult(false); } } private async void OnBoxSelected(int boxNumber) { // Отписываемся сразу после выбора if (_activeModal != null) { _activeModal.OnBoxSelected -= OnBoxSelected; _activeModal = null; } if (boxNumber <= 0) { _isGiving = false; InvokeResult(false); return; } PrizeStandController stand = ComSystemManager.GetPrizeStandController(); if (stand == null) { Debug.LogError("[PrizeStandPrize] Витрина не подключена."); _isGiving = false; InvokeResult(false); return; } bool success = false; void OnResult(bool s, string m) { stand.OpeningFinished -= OnResult; success = s; if (!s) Debug.LogWarning($"[PrizeStandPrize] Ошибка: {m}"); } stand.OpeningFinished += OnResult; try { await stand.OpenBoxAsync(boxNumber); } catch (Exception ex) { Debug.LogError($"[PrizeStandPrize] Исключение: {ex.Message}"); stand.OpeningFinished -= OnResult; } _isGiving = false; InvokeResult(success); } private static IReadOnlyList BuildAvailability( PrizeStandSettings settings, PrizeStandConnectionInfo connectionInfo, int finalScore, IReadOnlyDictionary boxStatuses) { List result = new(); if (settings?.boxes == null) return result; foreach (PrizeStandBoxConfig box in settings.boxes) { if (box == null || box.boxNumber <= 0) continue; bool isConnectedBox = connectionInfo.IsConnected && (connectionInfo.ConnectedBoxesCount <= 0 || box.boxNumber <= connectionInfo.ConnectedBoxesCount); bool isUnlocked = finalScore >= box.requiredScore; ControlsBoxStatus status = ControlsBoxStatus.NotFound; if (boxStatuses != null && boxStatuses.TryGetValue(box.boxNumber, out ControlsBoxStatus foundStatus)) { status = foundStatus; } result.Add(new PrizeStandBoxAvailability( box.boxNumber, box.requiredScore, isUnlocked, isConnectedBox, status)); } return result; } } }