From 6ceafddd00ee366162215f68e0613f4e031b59fb Mon Sep 17 00:00:00 2001 From: yastreb Date: Wed, 29 Apr 2026 14:20:17 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=D0=B0=20=D1=80=D0=B5=D0=B6=D0=B8?= =?UTF-8?q?=D0=BC=D0=B0=20=D0=B8=D0=B3=D1=80=D1=8B=20=D1=81=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D0=BE=D0=B9=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D1=81=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE,=20=D1=80=D0=B0=D1=81=D1=82=D1=83=D1=89=D0=B8=D1=85=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9=20=D0=B8=20=D1=80=D0=B8=D1=84?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Prefabs/UI/OptionPrefab.prefab | 2 +- Assets/Scripts/GameManager.cs | 73 ++++++++++++-- Assets/Scripts/Settings/SettingsData.cs | 4 + .../Scripts/UI/Panels/GameModeSelectPanel.cs | 98 +++++++++++++++++++ .../UI/Panels/GameModeSelectPanel.cs.meta | 3 + 5 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 Assets/Scripts/UI/Panels/GameModeSelectPanel.cs create mode 100644 Assets/Scripts/UI/Panels/GameModeSelectPanel.cs.meta diff --git a/Assets/Prefabs/UI/OptionPrefab.prefab b/Assets/Prefabs/UI/OptionPrefab.prefab index a424ab77..af5a6884 100644 --- a/Assets/Prefabs/UI/OptionPrefab.prefab +++ b/Assets/Prefabs/UI/OptionPrefab.prefab @@ -75,7 +75,7 @@ MonoBehaviour: m_fontColor32: serializedVersion: 2 rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_fontColor: {r: 0.9725491, g: 0.854902, b: 0.5686275, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs index ab024903..f7a1f399 100644 --- a/Assets/Scripts/GameManager.cs +++ b/Assets/Scripts/GameManager.cs @@ -731,7 +731,9 @@ public void DeclineInvite() public void StartPlayerGame() { // PvP всегда использует классический режим 10x10 + // Конфигурируем оба поля — это сбрасывает сохранённые рифы (если были в режиме "Рифы") playerField.Configure(10, 10); + enemyField.Configure(10, 10); PrepareNewGame(); Debug.Log("Начинаем игру с игроком"); gameMode = GameMode.PlayerVsPlayer; @@ -752,6 +754,62 @@ public void StartPlayerGame() enemyManager.SetEnemyPlayer(); } + private string _modeOverride = null; + /// Режим, применённый в текущей игре (определяется в ConfigureFields). + private string _effectiveMode = "Классика"; + + /// Вызывается кнопкой «Играть с ботом». + /// Если в настройках включён «Выбор режима игроком» — показывает панель выбора, + /// иначе сразу запускает игру с режимом из настроек. + public void TryStartBotGame() + { + bool playerChooses = SettingsManager.instance?.GetSettingValue("Выбор режима игроком") == "Вкл"; + if (playerChooses) + { + // Проверяем баланс ДО показа панели, чтобы не открывать её зря + bool isFreeMode = SettingsManager.instance?.GetSettingValue("Бесплатная игра") == "Вкл"; + if (!isFreeMode) + { + int price = CreditSystem.GetEffectiveBotPrice(isReplay: false); + int credits = CreditSystem.GetPlayerCredits(playerId); + if (credits < price) + { + uiManager?.ShowOverlay("InsufficientFunds", true, hideOtherOverlays: false); + return; + } + } + + uiManager.ShowOverlay("GameModeSelect", true, hideOtherOverlays: true); + SetInputMode(InputMode.UI); + } + else + { + // Баланс проверит сам StartBotGame через PayBotGame + StartBotGame(); + } + } + + /// Кнопка «Классика» на панели выбора режима. + public void StartBotClassic() + { + _modeOverride = "Классика"; + StartBotGame(); + } + + /// Кнопка «Растущие поля» на панели выбора режима. + public void StartBotGrowing() + { + _modeOverride = "Растущие поля"; + StartBotGame(); + } + + /// Кнопка «Рифы» на панели выбора режима. + public void StartBotReefs() + { + _modeOverride = "Рифы"; + StartBotGame(); + } + public void StartBotGame(bool isReplay = false) { // Сбрасываем скидку Виндисты — начинается новая игра @@ -798,7 +856,9 @@ public void StartBotGame(bool isReplay = false) /// private void ConfigureFields() { - string mode = SettingsManager.instance?.GetSettingValue("Режим игры") ?? "Классика"; + string mode = _modeOverride ?? SettingsManager.instance?.GetSettingValue("Режим игры") ?? "Классика"; + _modeOverride = null; // сбрасываем override + _effectiveMode = mode; // сохраняем для ApplyModeReefs int fieldSize = 10; int shipCount = 10; @@ -814,8 +874,8 @@ private void ConfigureFields() } else if (mode == "Рифы") { - fieldSize = 10; // поле всегда 10x10 - shipCount = data.shipCountGame2; // отдельное кол-во кораблей + fieldSize = 10; + shipCount = data.shipCountGame2; } } @@ -825,16 +885,11 @@ private void ConfigureFields() Debug.Log($"[GameManager] Режим игры: '{mode}', поле: {fieldSize}x{fieldSize}, кораблей: {shipCount}"); } - /// - /// Применяет случайные рифы для режима "Рифы". - /// Вызывается ПОСЛЕ PrepareNewGame() (после ClearPole), ДО расстановки кораблей. - /// private void ApplyModeReefs() { if (bossLevelConfig == null) return; - string mode = SettingsManager.instance?.GetSettingValue("Режим игры") ?? "Классика"; - if (mode != "Рифы") return; + if (_effectiveMode != "Рифы") return; var data = bossLevelConfig.GetLevel(currentBotLevel); playerField.ApplyRandomReefs(data.reefs); diff --git a/Assets/Scripts/Settings/SettingsData.cs b/Assets/Scripts/Settings/SettingsData.cs index 5c605b05..4fc7ea3a 100644 --- a/Assets/Scripts/Settings/SettingsData.cs +++ b/Assets/Scripts/Settings/SettingsData.cs @@ -86,6 +86,10 @@ public static List CreateBuiltinDefaults() settings.Add(new SettingOption(settingName: "Ðåæèì èãðû", options: new List() { "Êëàññèêà", "Ðàñòóùèå ïîëÿ", "Ðèôû" }, defaultIndex: 0)); + settings.Add(new SettingOption(settingName: "Âûáîð ðåæèìà èãðîêîì", + options: new List() { "Âêë", "Âûêë" }, + defaultIndex: 1, + type: SettingType.Svitcher)); settings.Add(new SettingOption(settingName: "Âûäà÷à ïðèçîâ ïðè èãðå ñ áîòîì", options: new List() { "Âûäàâàòü", "Íå âûäàâàòü" }, defaultIndex: 0, diff --git a/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs b/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs new file mode 100644 index 00000000..893515f8 --- /dev/null +++ b/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs @@ -0,0 +1,98 @@ +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +/// +/// Панель выбора режима игры. +/// Три кнопки — «Классика», «Растущие поля», «Рифы». +/// Навигация клавишами — через PlayerCursorUI (InputMode.UI). +/// +public class GameModeSelectPanel : MonoBehaviour +{ + [Header("Кнопки режимов (порядок: Классика, Растущие поля, Рифы)")] + [SerializeField] private Button buttonClassic; + [SerializeField] private Button buttonGrowing; + [SerializeField] private Button buttonReefs; + + [Header("Отображение")] + [SerializeField] private Image previewImage; + [SerializeField] private TMP_Text descriptionText; + + [Header("Картинки режимов (порядок: Классика, Растущие поля, Рифы)")] + [SerializeField] private Sprite spriteClassic; + [SerializeField] private Sprite spriteGrowing; + [SerializeField] private Sprite spriteReefs; + + [Header("Описания режимов")] + [SerializeField, TextArea(3, 6)] private string descClassic = "Классический режим 10×10. Стандартные правила морского боя."; + [SerializeField, TextArea(3, 6)] private string descGrowing = "Растущие поля — размер поля и количество кораблей увеличиваются с каждым уровнем."; + [SerializeField, TextArea(3, 6)] private string descReefs = "Рифы — на поле расставляются случайные рифы, меняя тактику боя."; + + private static readonly string[] ModeNames = { "Классика", "Растущие поля", "Рифы" }; + + private Button[] _buttons; + private Sprite[] _sprites; + private string[] _descriptions; + private int _selectedIndex; + + private void Awake() + { + _buttons = new[] { buttonClassic, buttonGrowing, buttonReefs }; + _sprites = new[] { spriteClassic, spriteGrowing, spriteReefs }; + _descriptions = new[] { descClassic, descGrowing, descReefs }; + + for (int i = 0; i < _buttons.Length; i++) + { + int idx = i; + if (_buttons[i] == null) continue; + + _buttons[i].onClick.AddListener(() => SelectMode(idx)); + + // При смене фокуса — обновляем превью и описание + var hl = _buttons[i].GetComponent(); + if (hl != null) + hl.onFocused = () => UpdatePreview(idx); + } + } + + private void OnEnable() + { + SyncFromSettings(); + } + + /// Обновляет только картинку и описание — без сохранения настройки и без подсветки. + private void UpdatePreview(int index) + { + if (previewImage != null) previewImage.sprite = _sprites [index]; + if (descriptionText != null) descriptionText.text = _descriptions[index]; + } + + public void SelectMode(int index) + { + if (index < 0 || index >= ModeNames.Length) return; + _selectedIndex = index; + SettingsManager.instance?.ChangeSetting("Режим игры", index); + RefreshUI(); + } + + private void SyncFromSettings() + { + string current = SettingsManager.instance?.GetSettingValue("Режим игры") ?? "Классика"; + int idx = System.Array.IndexOf(ModeNames, current); + _selectedIndex = idx >= 0 ? idx : 0; + RefreshUI(); + } + + private void RefreshUI() + { + UpdatePreview(_selectedIndex); + + for (int i = 0; i < _buttons.Length; i++) + { + if (_buttons[i] == null) continue; + var hl = _buttons[i].GetComponent(); + if (hl != null) + hl.SetHighlighted(i == _selectedIndex); + } + } +} diff --git a/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs.meta b/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs.meta new file mode 100644 index 00000000..77bc4fac --- /dev/null +++ b/Assets/Scripts/UI/Panels/GameModeSelectPanel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 234edf74d86242d08ba722398c50f340 +timeCreated: 1777026250 \ No newline at end of file