using CharacterSystem; using PrizeSystem; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public enum GameMode { pve, pvp } public class GameManager : MonoBehaviour { public static event Action OnGameStarted; public static event Action OnGameFinished; public event Action OnRoundStarted; public PlayerStatsService StatsService; public int botsAmount = 5; [Header("General")] public static GameManager Instance; public GameObject AdminPanel, NumberPanel; public TimerManager timerManager; public RulesController rulesController; public ChipPointer chipPointer; [Header("Menu")] public GameMode gameMode; [HideInInspector] public Team currentPlayer = Team.Player2; [Header("Scores")] public int player1score = 0, player2score = 0, vsBotScore = 0; private bool increaseVsBotTimer = false; public int vsBotMoves; public float vsBotThinkTime; [HideInInspector] public CheckResult lastResult; [Header("Gameplay")] public GameObject player1Chip; public GameObject player2Chip; public GameObject botChip; public Chip chipPrefab; [HideInInspector] public Chip currentChip; public bool canReturnToMenu = false; //todo: разобраться нафига эта переменная [Header("Панели ввода")] public TextInput nameInput; public Leaderboard leaderboard; public GameObject CharactersConfigurator; [Header("Переходы")] [SerializeField] private MenuGameplayTransit menuGameplayTransit; [SerializeField] private BackToMenuController _backToMenu; [SerializeField] TurnManager turnManager; [SerializeField] private FieldCleaner _fieldCleaner; public EndGameHandler endGameHandler; public TurnTracker turnTracker; public GameObject setPasswordPanel; //public EnterPasswordPanel enterPasswordPanel; public VitrinaPanel vitrinaPanel; public QrPanel qrPanel; public TakeOrRiskPanel takeOrRiskPanel; private const int PvpWinningScore = 5; private const int VictoryNameLength = 10; private bool _isLeavingGameplay; private int _paidEntryAmount; private bool _canRefundEntry; private bool _returnToMenuAfterPrize; public void Initialize() { if (Instance == null) { Instance = this; } ComWrapper.PaymentReceived += ProcessDifficultyCounter; ProcessDifficultyCounter(); SettingsManager.OnSettingsChanged+=ProcessDifficultyCounter; StatsService = new(); StatsService.Initialize(); timerManager.TimerEnded -= turnManager.HandleTimerEnded; timerManager.TimerEnded += turnManager.HandleTimerEnded; StartCoroutine(AddBotRecordEvery2Days());// добавлять каждые 2 дня запись //stateMachine.ChangeState(new MenuState()); } public void TryEnterGame(GameMode mode) { int entryPrice = PaymentSystem.GetModePrice(mode); if (!PaymentSystem.TryPayForMode(mode)) return; _paidEntryAmount = PaymentSystem.Freeplay ? 0 : entryPrice; _canRefundEntry = true; SetMode(mode); _isLeavingGameplay = false; if (mode == GameMode.pvp) { ResetPvpScores(); CharactersController.I.SuspendForPvp(); } if (mode == GameMode.pve) CharactersController.I.ApplyFirstCharacterColorsToBoard(); else Board.Instance.ApplyPvpColors(); menuGameplayTransit.GameplayOpened += OnGameplayOpened; menuGameplayTransit.GotoGameplay(); ControlsPerformer.Instance.SetControlable(null); } void OnGameplayOpened() { menuGameplayTransit.GameplayOpened -= OnGameplayOpened; turnTracker.ResetTracking(); _backToMenu.Show(); OnGameStarted?.Invoke(gameMode); if (gameMode == GameMode.pve) { _fieldCleaner.Clear(); CharactersController.I.StartSession(StartRound); } else { if (DualAvatarController.Instance != null) DualAvatarController.Instance.ShowCharacters(StartRound); else StartRound(); } } private void OnApplicationQuit() { ComWrapper.Shutdown(); ComNativeWrapper.Serial_CloseAll(); } private void Update() { if (increaseVsBotTimer) vsBotThinkTime += Time.deltaTime; } private void OnDestroy() { if (timerManager != null && turnManager != null) timerManager.TimerEnded -= turnManager.HandleTimerEnded; if (nameInput != null) nameInput.OnComplete -= HandleVictoryNameEntered; UnsubscribeFromPrizePanels(); } public void GotoMenu() { if (_isLeavingGameplay) return; RefundEntryIfAvailable(); _isLeavingGameplay = true; CancelPrizeFlow(); VitrinaView.Instance?.Deactivate(); ControlsPerformer.Instance.SetControlable(null); timerManager.HideBars(); VideoUtility.CrossFadeToMenu(); turnManager.CancelPlayerPreparation(); _fieldCleaner.Clear(); if (gameMode == GameMode.pve) { CharactersController.I.ReturnToMenu(); } else { DualAvatarController.Instance?.HideCharacters(); CharactersController.I.PreloadMenuCharacter(); } OnGameFinished?.Invoke(gameMode); menuGameplayTransit.GotoMenu(); } public void StartVsBotTimer() => increaseVsBotTimer = true; public void StopVsBotTimer() => increaseVsBotTimer = false; public void SwitchPlayer() { currentPlayer = currentPlayer == Team.Player1 ? Team.Player2 : Team.Player1; } public void SetMode(GameMode mode) => gameMode = mode; public void EnableEarlyMenuExit() => _backToMenu.EnableExit(); public void DisableEarlyMenuExit() { _paidEntryAmount = 0; _canRefundEntry = false; _backToMenu.Hide(); } public void PerformRevenge() => ContinueAfterPveLoss(); public void PerformDrawRevenge() => ContinueAfterPveDraw(); public void ContinueAfterPveWin() { if (CharactersController.HasActiveCharacter) CharactersController.CurrentCharacter.difficultyModule.IncreaseDifficulty(); int nextCharacterIndex = CharactersController.CharacterIndex + 1; if (nextCharacterIndex >= CharactersController.CharactersAmount) { GotoMenu(); return; } StartPveRound(nextCharacterIndex); } public bool TryStartPvePrizeFlow() { if (gameMode != GameMode.pve || !SettingsManager.GetBool(SettingKey.PRIZING) || !CharactersController.HasActiveCharacter) return false; if (!CharactersController.I.TryFetchCurrentPrizes(out List configuredPrizes)) return false; List availablePrizes = GetAvailablePrizes(configuredPrizes); if (availablePrizes.Count == 0) return false; bool isLastBot = CharactersController.CharacterIndex >= CharactersController.CharactersAmount - 1; bool takeOrRiskEnabled = SettingsManager.GetBool(SettingKey.TAKE_OR_RISK); bool continueAvailable = takeOrRiskEnabled && !isLastBot; _returnToMenuAfterPrize = continueAvailable; if (availablePrizes.Count > 1 || continueAvailable) { SubscribeToPrizePanels(); takeOrRiskPanel.Open(availablePrizes, continueAvailable, GetNextBotPrize()); } else { StartPrizeIssue(availablePrizes[0]); } return true; } public void ShowFinalVictoryNameInput() { ControlsPerformer.Instance.SetControlable(null); nameInput.OnComplete -= HandleVictoryNameEntered; nameInput.OnComplete += HandleVictoryNameEntered; nameInput.SetDestroyOnComplete(false); nameInput.gameObject.SetActive(true); nameInput.Initialize(VictoryNameLength, Alphabets.RUS_AND_DIGITS); ControlsPerformer.Instance.SetControlable(nameInput); } public void ContinueAfterPveLoss() { if (CharactersController.HasActiveCharacter) CharactersController.CurrentCharacter.difficultyModule.DecreaseDifficulty(); int previousCharacterIndex = Mathf.Max(CharactersController.CharacterIndex - 1, 0); StartPveRound(previousCharacterIndex); } public void ContinueAfterPveDraw() => StartPveRound(CharactersController.CharacterIndex); public void ContinueAfterPvpRound() { _fieldCleaner.Clear(); StartRound(); } public void RestartPvpMatch() { ResetPvpScores(); ContinueAfterPvpRound(); } public void IncreaseScore(Team player) { if (player == Team.Player1) player1score += 1; else player2score += 1; timerManager.RefreshPvpScores(); } public bool HasPvpMatchWinner(Team player) => player == Team.Player1 ? player1score >= PvpWinningScore : player2score >= PvpWinningScore; public void ProcessDifficultyCounter()//вызывается каждый раз, когда приходит COIN с платы или обновились настройки { string previous = PlayerPrefs.GetString("PreviousBaseBotDifficulty", "Прохождение"); string difficultyType = SettingsManager.GetString(SettingKey.DIFFICULTY_MODE); //Инициализация if (!PlayerPrefs.HasKey("PulsesToResetDifficulty")) PlayerPrefs.SetInt("PulsesToResetDifficulty", 100); //если переход с повышенной на обычную - сброс счетчика if (previous == "Заработок" && difficultyType != previous) { PaymentSystem.ResetPulsesCounter(); } PlayerPrefs.SetString("PreviousBaseBotDifficulty", difficultyType); if (difficultyType == "Заработок") { int pulses = PaymentSystem.PulsesCounter; int pulsesToResetDifficulty = PlayerPrefs.GetInt("PulsesToResetDifficulty", 10); //todo: разобраться //if (pulses >= pulsesToResetDifficulty) //{ // PaymentSystem.ResetPulsesCounter(); //Setting difficultySetting = SettingsManager.Container.TryGetSetting(SettingKeys.DIFFICULTY_MODE); // difficultySetting.StringValue = "Прохождение"; // SettingsManager.OnSettingsChanged?.Invoke(); // SettingsManager.SaveContainerToFile(); // AdminPanel.GetComponent().RefreshViews(); // print("Сложность сброшена"); //} } } public void PrepareRound(Team firstPlayer) { currentPlayer = firstPlayer; timerManager.SetupTimers(gameMode); if (gameMode == GameMode.pve) { timerManager.SetActiveTimer(Team.Player1); } VitrinaView.Instance.ActivateIfNeed(); DetermineNextTurn(switchPlayer: false); } public void DetermineNextTurn(bool switchPlayer = true) { if (switchPlayer) SwitchPlayer(); //spawnChip(); if (gameMode == GameMode.pvp)//переключаем таймеры только в pvp { timerManager.SetActiveTimer(currentPlayer); LightSystem.Player(currentPlayer); } } public void ResetGameSession() { vsBotThinkTime = 0; StopVsBotTimer(); vsBotMoves = 0; //movesAndTimeCounter.SetVisibility(false); CharactersController.I.ReturnToMenu(); CharactersController.I.SetAllCharactersPrizeAvailable(); DualAvatarController.Instance?.HideCharacters(); player1score = 0; player2score = 0; vsBotScore = 0; VitrinaView.Instance.Deactivate(); canReturnToMenu = true; } private void StartPveRound(int characterIndex) { _fieldCleaner.Clear(); CharactersController.I.ShowCharacter(characterIndex, StartRound); } private void StartRound() { turnManager.StartGame(gameMode); PrepareRound(Team.Player1); OnRoundStarted?.Invoke(); } private static List GetAvailablePrizes(IEnumerable prizes) { List result = new(); if (prizes == null) return result; foreach (Prize prize in prizes) { if (prize != null && prize is not EmptyPrize) result.Add(prize); } return result; } private Prize GetNextBotPrize() { int nextIndex = CharactersController.CharacterIndex + 1; if (nextIndex >= CharactersController.CharactersAmount) return null; List nextPrizes = GetAvailablePrizes(CharactersController.I.GetPrizes(nextIndex)); return nextPrizes.Count > 0 ? nextPrizes[0] : null; } private void SubscribeToPrizePanels() { UnsubscribeFromPrizePanels(); takeOrRiskPanel.PrizeSelected += StartPrizeIssue; takeOrRiskPanel.ContinueSelected += HandlePrizeSkipped; qrPanel.OnComplete += HandlePrizeIssueFinished; vitrinaPanel.OnComplete += HandleVitrinaIssueFinished; } private void UnsubscribeFromPrizePanels() { if (takeOrRiskPanel != null) { takeOrRiskPanel.PrizeSelected -= StartPrizeIssue; takeOrRiskPanel.ContinueSelected -= HandlePrizeSkipped; } if (qrPanel != null) qrPanel.OnComplete -= HandlePrizeIssueFinished; if (vitrinaPanel != null) vitrinaPanel.OnComplete -= HandleVitrinaIssueFinished; PrizeSystemManager.PrizeIssueFinished -= HandleCountablePrizeIssueFinished; } private void StartPrizeIssue(Prize prize) { SubscribeToPrizePanels(); if (prize is CountablePrize) { PrizeSystemManager.PrizeIssueFinished -= HandleCountablePrizeIssueFinished; PrizeSystemManager.PrizeIssueFinished += HandleCountablePrizeIssueFinished; PrizeSystemManager.GivePrize(prize); } else if (prize is QrPrize) { qrPanel.gameObject.SetActive(true); qrPanel.Initialize(prize); } else if (prize is VitrinaPrize vitrinaPrize) { vitrinaPanel.gameObject.SetActive(true); vitrinaPanel.Initialize(vitrinaPrize.Boxes); } else { HandlePrizeIssueFinished(); } } private void HandlePrizeSkipped() { _returnToMenuAfterPrize = false; UnsubscribeFromPrizePanels(); ContinueAfterPveWin(); } private void HandleCountablePrizeIssueFinished(bool success) { PrizeSystemManager.PrizeIssueFinished -= HandleCountablePrizeIssueFinished; HandlePrizeIssueFinished(); } private void HandleVitrinaIssueFinished(bool success) => HandlePrizeIssueFinished(); private void HandlePrizeIssueFinished() { UnsubscribeFromPrizePanels(); if (_returnToMenuAfterPrize) { GotoMenu(); return; } bool isLastBot = CharactersController.CharacterIndex >= CharactersController.CharactersAmount - 1; if (isLastBot) ShowFinalVictoryNameInput(); else ContinueAfterPveWin(); } private void CancelPrizeFlow() { UnsubscribeFromPrizePanels(); if (takeOrRiskPanel != null) takeOrRiskPanel.gameObject.SetActive(false); if (qrPanel != null) qrPanel.gameObject.SetActive(false); if (vitrinaPanel != null) vitrinaPanel.gameObject.SetActive(false); } private void RefundEntryIfAvailable() { if (!_canRefundEntry) return; PaymentSystem.ReturnCredits(_paidEntryAmount); _paidEntryAmount = 0; _canRefundEntry = false; } private void ResetPvpScores() { player1score = 0; player2score = 0; timerManager.RefreshPvpScores(); } private void HandleVictoryNameEntered(string playerName) { nameInput.OnComplete -= HandleVictoryNameEntered; ControlsPerformer.Instance.SetControlable(null); StatsService.AddRecord(playerName, TurnTracker.Timer, TurnTracker.Moves); nameInput.gameObject.SetActive(false); GotoMenu(); } public void upgradeFeeshkaDifficulty() { string difficultyMode = SettingsManager.GetString(SettingKey.DIFFICULTY_MODE); //todo: разобраться //if (difficultyMode == "Прохождение") //{ // PaymentSystem.ResetPulsesCounter(); // Setting difficultySetting = SettingsManager.Container.TryGetSetting(SettingKeys.DIFFICULTY_MODE); // difficultySetting.StringValue = "Заработок"; // SettingsManager.OnSettingsChanged?.Invoke(); // SettingsManager.SaveContainerToFile(); // GameManager.instance.AdminPanel.GetComponent().RefreshViews(); // print("Сложность повышена"); //} } IEnumerator AddBotRecordEvery2Days() { while (true) { yield return new WaitForSeconds(3600f); // ✅ Проверка каждый час double lastRecordTime = PlayerPrefs.GetFloat("LastBotRecord", 0); double currentTime = (DateTime.UtcNow - new System.DateTime(1970, 1, 1)).TotalSeconds; if (currentTime - lastRecordTime >= 172800f) { StatsService.AddDailyRecord(); PlayerPrefs.SetFloat("LastBotRecord", (float)currentTime); PlayerPrefs.Save(); } } } }