1003 lines
30 KiB
C#
1003 lines
30 KiB
C#
using System;
|
||
using System.Collections;
|
||
using UnityEngine;
|
||
|
||
public class GameManager : MonoBehaviour
|
||
{
|
||
public static event System.Action<int, int> OnInviteSent;
|
||
public static event System.Action <int, bool, GameMode> OnReady;
|
||
public event System.Action<InputMode> OnInputModeChanged;
|
||
|
||
private IBotAI bot;
|
||
public Transform shipPlacementCameraPosition;
|
||
public Transform mainMenuCameraPosition;
|
||
public Transform gameplayCameraPosition;
|
||
|
||
public bool isReady = false; // Готов ли игрок (расставил ли корабли)
|
||
public GameManager opponentManager; // Противник (если есть)
|
||
|
||
|
||
public CannonBattery battery;
|
||
public CannonBattery enemyBattery;
|
||
|
||
public GameState currentState;
|
||
public UIManager uiManager;
|
||
|
||
public GamePole playerField;
|
||
public GamePole enemyField;
|
||
|
||
public GameObject targetCursorPrefab;
|
||
private GameObject targetCursorInstance;
|
||
|
||
public bool isPlayerTurn = false;
|
||
|
||
public int playerShips = 0;
|
||
public int enemyShips = 0;
|
||
|
||
public int playerId = 1; // 1 - первый игрок, 2 - второй игрок и т.д.
|
||
|
||
public Camera playerCamera;
|
||
public Transform cameraPivot;
|
||
|
||
public int currentBotLevel = 0;
|
||
|
||
public EnemyManager enemyManager;
|
||
public FortInitializer fortInitializer;
|
||
|
||
|
||
[Header("Время бездействия")]
|
||
[SerializeField] float inactionTimer = 360f;
|
||
[SerializeField] float mainMenuVideoIdleDelay = 30f;
|
||
public float timerBackToMenu = 0;
|
||
private bool idleVideoRequested;
|
||
[SerializeField] private ShipPlacementTimer shipPlacementTimer;
|
||
private bool autoStartBattlePending;
|
||
|
||
[Header("Таймер бездействия в бою")]
|
||
[SerializeField] private float battleIdleTimeout = 45f;
|
||
private float battleIdleTimer = 0f;
|
||
private bool battlePauseShown = false;
|
||
|
||
public enum InputMode
|
||
{
|
||
UI,
|
||
Settings,
|
||
ShipPlacement,
|
||
Battle
|
||
}
|
||
|
||
private bool paidFroFriend = false;
|
||
|
||
|
||
public InputMode currentInputMode = InputMode.UI;
|
||
|
||
[Header("Настройки бота")]
|
||
public bool useManualDifficulty = false;
|
||
public BotDifficulty manualDifficulty = BotDifficulty.Level1;
|
||
|
||
|
||
public enum BotDifficulty
|
||
{
|
||
Level1,
|
||
Level2,
|
||
Level3,
|
||
Level4,
|
||
Level5,
|
||
Level6,
|
||
}
|
||
|
||
public GameMode gameMode = GameMode.PlayerVsBot;
|
||
public BotDifficulty botDifficulty = BotDifficulty.Level1;
|
||
|
||
|
||
public float cameraMoveDuration = 1.0f; // Время перемещения в секундах
|
||
|
||
void Start()
|
||
{
|
||
var player = GetComponentInParent<Player>();
|
||
if (player != null)
|
||
playerId = player.PlayerId;
|
||
|
||
SetState(GameState.MainMenu);
|
||
}
|
||
private void Update()
|
||
{
|
||
timerBackToMenu += Time.deltaTime;
|
||
|
||
bool idleVideoPlaying = IdleMainMenuVideoController.Instance != null &&
|
||
IdleMainMenuVideoController.Instance.IsPlaying();
|
||
|
||
if (currentState == GameState.MainMenu)
|
||
{
|
||
if (!idleVideoPlaying && timerBackToMenu >= mainMenuVideoIdleDelay)
|
||
{
|
||
IdleMainMenuVideoController.Instance?.TryStartVideo();
|
||
idleVideoRequested = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
idleVideoRequested = false;
|
||
|
||
if (timerBackToMenu >= inactionTimer)
|
||
{
|
||
ReturnToMainMenu();
|
||
timerBackToMenu = 0;
|
||
}
|
||
}
|
||
|
||
// --- Таймер бездействия во время боя ---
|
||
if (currentState == GameState.Playing && !battlePauseShown)
|
||
{
|
||
battleIdleTimer += Time.deltaTime;
|
||
if (battleIdleTimer >= battleIdleTimeout)
|
||
{
|
||
ShowBattlePause();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
In.ButtonEvent += ResetTimer;
|
||
if (shipPlacementTimer != null)
|
||
shipPlacementTimer.TimerExpired += HandleShipPlacementTimeout;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
In.ButtonEvent -= ResetTimer;
|
||
if (shipPlacementTimer != null)
|
||
shipPlacementTimer.TimerExpired -= HandleShipPlacementTimeout;
|
||
}
|
||
|
||
private void ResetTimer()
|
||
{
|
||
ResetIdleTimer();
|
||
IdleMainMenuVideoController.Instance?.StopVideo();
|
||
}
|
||
|
||
public void ResetIdleTimer()
|
||
{
|
||
timerBackToMenu = 0;
|
||
idleVideoRequested = false;
|
||
}
|
||
|
||
// ===== Таймер бездействия в бою =====
|
||
|
||
public void ResetBattleIdleTimer()
|
||
{
|
||
battleIdleTimer = 0f;
|
||
}
|
||
|
||
public void ShowBattlePause()
|
||
{
|
||
if (battlePauseShown) return;
|
||
battlePauseShown = true;
|
||
SetInputMode(InputMode.UI);
|
||
uiManager.ShowOverlay("BattlePause", true, hideOtherOverlays: true);
|
||
}
|
||
|
||
public void HideBattlePause()
|
||
{
|
||
if (!battlePauseShown) return;
|
||
battlePauseShown = false;
|
||
battleIdleTimer = 0f;
|
||
uiManager.ShowOverlay("BattlePause", false);
|
||
// Восстанавливаем режим ввода: если ход игрока — Battle, иначе UI
|
||
SetInputMode(isPlayerTurn ? InputMode.Battle : InputMode.UI);
|
||
}
|
||
|
||
|
||
|
||
|
||
void SetPlayerReady(bool ready)
|
||
{
|
||
isReady = ready;
|
||
if (gameMode == GameMode.PlayerVsBot)
|
||
{
|
||
uiManager.SetupPlayButtons(ready);
|
||
}
|
||
else
|
||
{
|
||
var rez = isReady & opponentManager.isReady;
|
||
uiManager.SetupPlayButtons(rez);
|
||
opponentManager.uiManager.SetupPlayButtons(rez);
|
||
}
|
||
|
||
OnReady?.Invoke(playerId, ready, gameMode);
|
||
TryStartBattleAfterPlacementTimeout();
|
||
|
||
}
|
||
public void AddShipPlayer()
|
||
{
|
||
playerShips++;
|
||
if (playerShips == 10)
|
||
{
|
||
SetPlayerReady(true);
|
||
}
|
||
}
|
||
public void SetInputMode(InputMode newMode)
|
||
{
|
||
currentInputMode = newMode;
|
||
OnInputModeChanged?.Invoke(newMode);
|
||
|
||
if (newMode == InputMode.ShipPlacement && targetCursorInstance == null)
|
||
InitTargetCursor(true);
|
||
}
|
||
|
||
|
||
public void ShipDestroyed(bool isPlayer)
|
||
{
|
||
if (isPlayer)
|
||
{
|
||
enemyManager.TriggerEventReaction(DialogueEventType.PlayerShipDestroyed);
|
||
playerShips--;
|
||
}
|
||
else
|
||
{
|
||
enemyManager.TriggerEventReaction(DialogueEventType.BotShipDestroyed);
|
||
enemyShips--;
|
||
}
|
||
CheckVictoryCondition();
|
||
}
|
||
|
||
private void CheckVictoryCondition()
|
||
{
|
||
BlinkController.StartBlinkATimes(playerId,5,0.2f);
|
||
BlinkController.StartBlinkCTimes(5,0.2f);
|
||
|
||
if (playerShips <= 0)
|
||
{
|
||
Debug.Log("Игрок проиграл!");
|
||
BlinkController.LEDRedAll(playerId); // Красный LED при поражении (статический)
|
||
enemyManager.TriggerEndGameReaction(false);
|
||
EndGame();
|
||
}
|
||
else if (enemyShips <= 0)
|
||
{
|
||
Debug.Log("Игрок победил!");
|
||
BlinkController.SetLEDBaseCustomColor(playerId, 255, 215, 0); // Устанавливаем золотой как базовый
|
||
enemyManager.TriggerEndGameReaction(true);
|
||
EndGame();
|
||
}
|
||
}
|
||
|
||
public void ProcessShotResult(bool hit, bool isPlayer, bool wasShipDestroyed = false)
|
||
{
|
||
if (wasShipDestroyed)
|
||
{
|
||
BlinkController.StartBlinkATimes(playerId,3,0.2f);
|
||
|
||
// Мигание LED 3 раза при потоплении
|
||
if (!isPlayer)
|
||
{
|
||
// Бот потопил корабль игрока - красный 3 раза
|
||
BlinkController.BlinkLEDRed(playerId, 3, 0.4f);
|
||
}
|
||
else
|
||
{
|
||
// Игрок потопил корабль противника - зеленый 3 раза
|
||
BlinkController.BlinkLEDGreen(playerId, 3, 0.4f);
|
||
}
|
||
|
||
ShipDestroyed(!isPlayer);
|
||
return;
|
||
}
|
||
|
||
if (!isPlayer)
|
||
{
|
||
if (hit)
|
||
{
|
||
BlinkController.StartBlinkATimes(playerId,1);
|
||
BlinkController.BlinkLEDRed(playerId, 1, 0.6f);
|
||
enemyManager.TriggerEventReaction(DialogueEventType.BotHit);
|
||
}
|
||
else
|
||
{
|
||
SoundManager.Instance.PlayMiss(playerId);
|
||
enemyManager.TriggerEventReaction(DialogueEventType.BotMiss);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (hit)
|
||
{
|
||
BlinkController.StartBlinkATimes(playerId,1);
|
||
BlinkController.BlinkLEDGreen(playerId, 1, 0.6f);
|
||
enemyManager.TriggerEventReaction(DialogueEventType.PlayerHit);
|
||
}
|
||
else
|
||
{
|
||
SoundManager.Instance.PlayMiss(playerId);
|
||
enemyManager.TriggerEventReaction(DialogueEventType.PlayerMiss);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
public void SetState(GameState newState)
|
||
{
|
||
currentState = newState;
|
||
|
||
// Сброс таймера бездействия в бою при выходе из боя
|
||
if (newState != GameState.Playing)
|
||
{
|
||
battleIdleTimer = 0f;
|
||
battlePauseShown = false;
|
||
}
|
||
|
||
if (newState != GameState.ShipPlacement)
|
||
{
|
||
autoStartBattlePending = false;
|
||
shipPlacementTimer?.StopTimer();
|
||
}
|
||
|
||
// UI: просто показываем панель по имени state (без switch)
|
||
uiManager.ShowById(newState.ToString());
|
||
|
||
// LED подсветка в зависимости от состояния
|
||
if (newState == GameState.MainMenu)
|
||
{
|
||
// В главном меню: канал 1 - волна, канал 2 - радуга
|
||
BlinkController.LEDWave(1, playerId); // Канал 1 -> волна (команда 8111)
|
||
BlinkController.LEDRainbow(2, playerId); // Канал 2 -> радуга (команда 8209)
|
||
}
|
||
|
||
// Камера — оставляем switch только для 3 точек
|
||
switch (newState)
|
||
{
|
||
case GameState.MainMenu:
|
||
MoveCameraTo(mainMenuCameraPosition);
|
||
break;
|
||
|
||
case GameState.ShipPlacement:
|
||
MoveCameraTo(shipPlacementCameraPosition);
|
||
break;
|
||
|
||
case GameState.Playing:
|
||
MoveCameraTo(gameplayCameraPosition);
|
||
break;
|
||
}
|
||
}
|
||
|
||
public void StartShipPlacementCountdown()
|
||
{
|
||
autoStartBattlePending = false;
|
||
shipPlacementTimer?.StartTimer();
|
||
}
|
||
|
||
|
||
private BotDifficulty GetDifficultyFromLevel()
|
||
{
|
||
if (useManualDifficulty)
|
||
{
|
||
return manualDifficulty;
|
||
}
|
||
int level = Mathf.Clamp(currentBotLevel, 0, 4);
|
||
Debug.Log("шанс на победу : " + DifficultyManager.GetChance());
|
||
|
||
if (level == 4) // дошел до 5го уровня
|
||
{
|
||
// Система шанса на победу
|
||
if (DifficultyManager.GetChance() <= 0)
|
||
{
|
||
Debug.Log("Шанс на победу сработал!");
|
||
DifficultyManager.ResetChance();
|
||
return BotDifficulty.Level5; // даем шанс победить
|
||
}
|
||
else
|
||
{
|
||
DifficultyManager.DecreaseChance();
|
||
return BotDifficulty.Level6; // почти непобедимый
|
||
}
|
||
}
|
||
|
||
return (BotDifficulty)level;
|
||
}
|
||
|
||
|
||
public void PrepareForBattle()
|
||
{
|
||
if (playerShips != 10)
|
||
{
|
||
playerField.ArrangeShip();
|
||
playerShips = 10;
|
||
}
|
||
|
||
if (targetCursorInstance != null)
|
||
{
|
||
Destroy(targetCursorInstance);
|
||
targetCursorInstance = null;
|
||
}
|
||
SetInputMode(InputMode.Battle);
|
||
InitTargetCursor();
|
||
|
||
// Устанавливаем синий цвет LED при входе в бой
|
||
BlinkController.SetLEDBaseColor(playerId, 5); // 5 = синий
|
||
}
|
||
|
||
|
||
|
||
public void StartBattle()
|
||
{
|
||
Debug.Log("Игровой этап начат");
|
||
|
||
autoStartBattlePending = false;
|
||
shipPlacementTimer?.StopTimer();
|
||
|
||
if (gameMode == GameMode.PlayerVsPlayer)
|
||
{
|
||
if (!isReady || opponentManager == null || !opponentManager.isReady)
|
||
{
|
||
Debug.Log("Ожидаем готовности оппонента...");
|
||
return;
|
||
}
|
||
PrepareForBattle();
|
||
|
||
opponentManager.PrepareForBattle();
|
||
|
||
|
||
SetState(GameState.Playing);
|
||
opponentManager.SetState(GameState.Playing);
|
||
|
||
// копируем корабли на поля
|
||
if (!enemyField.IsReady)
|
||
{
|
||
enemyField.CopyShipsFrom(opponentManager.playerField, true);
|
||
enemyShips = 10;
|
||
}
|
||
|
||
if (!opponentManager.enemyField.IsReady)
|
||
{
|
||
opponentManager.enemyField.CopyShipsFrom(playerField, true);
|
||
opponentManager.enemyShips = 10;
|
||
}
|
||
|
||
paidFroFriend = false;
|
||
opponentManager.paidFroFriend = false;
|
||
|
||
opponentManager.uiManager.ShowTimer(false);
|
||
|
||
isReady = false;
|
||
opponentManager.isReady = false;
|
||
}
|
||
else // бот
|
||
{
|
||
PrepareForBattle();
|
||
enemyShips = 10;
|
||
enemyField.ArrangeShip(true);
|
||
|
||
SetState(GameState.Playing);
|
||
}
|
||
|
||
StartPlayerTurn();
|
||
}
|
||
|
||
|
||
|
||
public void InitTargetCursor(bool isPlacingShips = false)
|
||
{
|
||
if (targetCursorInstance != null)
|
||
return;
|
||
targetCursorInstance = Instantiate(targetCursorPrefab);
|
||
TargetCursor cursorScript = targetCursorInstance.GetComponent<TargetCursor>();
|
||
cursorScript.Initialize(this, playerId, isPlacingShips);
|
||
targetCursorInstance.SetActive(isPlacingShips); // по дефолту скрыт
|
||
}
|
||
|
||
public void EndGame()
|
||
{
|
||
SetInputMode(InputMode.UI);
|
||
autoStartBattlePending = false;
|
||
shipPlacementTimer?.StopTimer();
|
||
StartCoroutine(EndGameSequence());
|
||
}
|
||
|
||
private IEnumerator EndGameSequence()
|
||
{
|
||
bool isWin = enemyShips <= 0;
|
||
bool isBotGame = (gameMode == GameMode.PlayerVsBot);
|
||
|
||
// Задержка перед показом GameOver экрана
|
||
yield return new WaitForSeconds(0.5f);
|
||
|
||
uiManager.ShowGameOverMenu(isWin, isBotGame);
|
||
|
||
if (gameMode == GameMode.PlayerVsBot)
|
||
{
|
||
if (isWin)
|
||
{
|
||
Prize priz = PrizeSerializer.GetPrizes()[currentBotLevel];
|
||
Debug.Log("Приз :"+ priz);
|
||
|
||
// Повышаем уровень бота ПЕРЕД выдачей приза
|
||
if (currentBotLevel <= 4)
|
||
currentBotLevel++;
|
||
else
|
||
DifficultyManager.DecreaseChance();
|
||
|
||
// Задержка перед показом панели призов
|
||
yield return new WaitForSeconds(1.5f);
|
||
|
||
if (priz.PrizeType == PrizeType.Special)
|
||
{
|
||
bool settingEnabled = SettingsManager.instance.GetSettingValue("Выдача призов при игре с ботом") == "Выдавать";
|
||
|
||
if (settingEnabled)
|
||
{
|
||
uiManager.ShowOverlayAnimated("QRCode", 0f);
|
||
yield break;
|
||
}
|
||
}
|
||
if (priz.PrizeType == PrizeType.Showcase)
|
||
{
|
||
bool settingEnabled = SettingsManager.instance.GetSettingValue("Выдача призов при игре с ботом") == "Выдавать";
|
||
|
||
if (settingEnabled)
|
||
{
|
||
uiManager.ShowOverlayAnimated("PrizeSelection", 0f);
|
||
yield break;
|
||
}
|
||
}
|
||
|
||
if (priz.PrizeType == PrizeType.None) yield break;
|
||
|
||
uiManager.ShowOverlayAnimated("PrizeReminder", 0f);
|
||
PrizeSystem.GivePrize(priz, playerId);
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============= buttons ==========================================================================
|
||
|
||
public void OnReplayPressed() // по идеее функции разные так как нужна проверка на баланс $
|
||
{
|
||
if (gameMode == GameMode.PlayerVsBot)
|
||
{
|
||
StartBotGame();
|
||
}
|
||
else
|
||
{
|
||
if (CreditSystem.GetPlayerCredits(opponentManager.playerId) > 0)
|
||
{
|
||
CreditSystem.Pay(1, playerId);
|
||
CreditSystem.Pay(1, opponentManager.playerId);
|
||
}
|
||
else
|
||
{
|
||
paidFroFriend = true;
|
||
CreditSystem.Pay(2, playerId);
|
||
}
|
||
opponentManager.StartPlayerGame();
|
||
StartPlayerGame();
|
||
}
|
||
}
|
||
|
||
public void OnContinuePressed()
|
||
{
|
||
if (gameMode == GameMode.PlayerVsBot)
|
||
{
|
||
// Возврат кредита за победу только в платном режиме
|
||
bool isFreeMode = SettingsManager.instance.GetSettingValue("Бесплатная игра") == "Вкл";
|
||
if (!isFreeMode)
|
||
{
|
||
CreditSystem.AddCredit(1, playerId);
|
||
}
|
||
StartBotGame();
|
||
}
|
||
}
|
||
|
||
public void MenuGame(bool endGame = false)
|
||
{
|
||
// Возврат кредитов при выходе (если не завершилась игра)
|
||
// НЕ возвращаем если включена бесплатная игра
|
||
bool isFreeMode = SettingsManager.instance.GetSettingValue("Бесплатная игра") == "Вкл";
|
||
|
||
if (!endGame && !isFreeMode)
|
||
{
|
||
if (gameMode == GameMode.PlayerVsPlayer)
|
||
{
|
||
if (paidFroFriend) CreditSystem.AddCredit(2, playerId);
|
||
else if(opponentManager.paidFroFriend) CreditSystem.AddCredit(2, opponentManager.playerId);
|
||
else
|
||
{
|
||
CreditSystem.AddCredit(1, playerId);
|
||
CreditSystem.AddCredit(1, opponentManager.playerId);
|
||
}
|
||
opponentManager.ReturnToMainMenu();
|
||
}
|
||
else
|
||
{
|
||
if(currentBotLevel == 0) CreditSystem.AddCredit(1, playerId); // Возврат одному игроку если тот не играл
|
||
}
|
||
}
|
||
if (gameMode == GameMode.PlayerVsPlayer)opponentManager.ReturnToMainMenu();
|
||
|
||
|
||
ReturnToMainMenu();
|
||
}
|
||
|
||
public void ClearPole()
|
||
{
|
||
if (playerField != null)
|
||
{
|
||
playerField.ClearPole();
|
||
playerShips = 0;
|
||
SetPlayerReady(false);
|
||
Debug.Log("Поле очищено");
|
||
}
|
||
}
|
||
|
||
public void ArrangeGame()
|
||
{
|
||
if (playerField != null)
|
||
{
|
||
playerField.ArrangeShip();
|
||
playerShips = 10;
|
||
SetPlayerReady(true);
|
||
Debug.Log("Поле очищено и корабли расставлены заново");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("GamePole не назначен в GameManager");
|
||
}
|
||
}
|
||
|
||
public void OnPlayVsPlayerClicked(int playerId) // мистр кастыль
|
||
{
|
||
|
||
int opponentId = playerId == 1 ? 2 : 1;
|
||
|
||
OnInviteSent?.Invoke(playerId, opponentId);
|
||
|
||
}
|
||
|
||
public void AcceptInvite()
|
||
{
|
||
if (CreditSystem.GetPlayerCredits(playerId) > 0)
|
||
{
|
||
CreditSystem.Pay(1, playerId);
|
||
CreditSystem.Pay(1, opponentManager.playerId);
|
||
}
|
||
else
|
||
{
|
||
opponentManager.paidFroFriend = true;
|
||
CreditSystem.Pay(2, opponentManager.playerId);
|
||
}
|
||
StartPlayerGame();
|
||
opponentManager.StartPlayerGame();
|
||
|
||
}
|
||
|
||
public void DeclineInvite()
|
||
{
|
||
uiManager.HideInvite();
|
||
}
|
||
public void StartPlayerGame()
|
||
{
|
||
PrepareNewGame();
|
||
Debug.Log("Начинаем игру с игроком");
|
||
gameMode = GameMode.PlayerVsPlayer;
|
||
|
||
if (playerId == 1)
|
||
{
|
||
SoundManager.Instance?.SetPvPMode(true);
|
||
}
|
||
|
||
SetState(GameState.ShipPlacement);
|
||
SetInputMode(InputMode.UI);
|
||
|
||
uiManager.ShowOverlay("PlacementChoice", true, hideOtherOverlays: true);
|
||
SetInputMode(InputMode.UI);
|
||
|
||
fortInitializer.FortSwitch(3);
|
||
|
||
enemyManager.SetEnemyPlayer();
|
||
}
|
||
|
||
public void StartBotGame()
|
||
{
|
||
// Если есть оппонент, который ждёт в главном меню - закрываем его приглашение
|
||
if (opponentManager != null &&
|
||
opponentManager.currentState == GameState.MainMenu)
|
||
{
|
||
opponentManager.DeclineInvite();
|
||
}
|
||
|
||
CreditSystem.Pay(1, playerId);
|
||
PrepareNewGame();
|
||
Debug.Log("Начинаем игру с ботом");
|
||
gameMode = GameMode.PlayerVsBot;
|
||
|
||
if (playerId == 1)
|
||
SoundManager.Instance?.SetPvPMode(false);
|
||
|
||
SetState(GameState.ShipPlacement);
|
||
SetInputMode(InputMode.UI);
|
||
|
||
// Затем показать overlay выбора расстановки
|
||
uiManager.ShowOverlay("PlacementChoice", true, hideOtherOverlays: true);
|
||
|
||
InitBot();
|
||
}
|
||
|
||
//==========================================================================================
|
||
|
||
private void InitBot()
|
||
{
|
||
BotDifficulty selectedDifficulty = GetDifficultyFromLevel();
|
||
Debug.Log("Выбран бот: " + selectedDifficulty);
|
||
|
||
switch (selectedDifficulty)
|
||
{
|
||
case BotDifficulty.Level1:
|
||
bot = new EasyBotAI();
|
||
enemyManager.SetEnemy(0);
|
||
fortInitializer.FortSwitch(0);
|
||
break;
|
||
|
||
case BotDifficulty.Level2:
|
||
bot = new NormalBotAI();
|
||
enemyManager.SetEnemy(1);
|
||
fortInitializer.FortSwitch(1);
|
||
break;
|
||
|
||
case BotDifficulty.Level3:
|
||
bot = new HardBotAI();
|
||
enemyManager.SetEnemy(2);
|
||
fortInitializer.FortSwitch(2);
|
||
break;
|
||
|
||
case BotDifficulty.Level4:
|
||
bot = new VeryHardBotAI();
|
||
enemyManager.SetEnemy(3);
|
||
fortInitializer.FortSwitch(3);
|
||
|
||
break;
|
||
|
||
case BotDifficulty.Level5:
|
||
bot = new CrazyBotAI();
|
||
enemyManager.SetEnemy(4);
|
||
fortInitializer.FortSwitch(4);
|
||
break;
|
||
|
||
case BotDifficulty.Level6:
|
||
bot = new UltimateBotAI();
|
||
enemyManager.SetEnemy(4);
|
||
fortInitializer.FortSwitch(4);
|
||
break;
|
||
|
||
default:
|
||
bot = new EasyBotAI();
|
||
enemyManager.SetEnemy(0);
|
||
fortInitializer.FortSwitch(0);
|
||
break;
|
||
}
|
||
}
|
||
// ходы
|
||
|
||
public void StartPlayerTurn()
|
||
{
|
||
isPlayerTurn = true;
|
||
uiManager.ShowTimer(true);
|
||
if (targetCursorInstance != null)
|
||
targetCursorInstance.SetActive(true);
|
||
|
||
}
|
||
|
||
public void EndPlayerTurn()
|
||
{
|
||
isPlayerTurn = false;
|
||
uiManager.ShowTimer(false);
|
||
if (targetCursorInstance != null)
|
||
targetCursorInstance.SetActive(false);
|
||
|
||
if (gameMode == GameMode.PlayerVsPlayer)
|
||
{
|
||
opponentManager.StartPlayerTurn();
|
||
}
|
||
else
|
||
{
|
||
// enemyManager.ShowNextDialogue();
|
||
StartCoroutine(BotTurn());
|
||
}
|
||
|
||
}
|
||
|
||
public IEnumerator BotTurn()
|
||
{
|
||
bool hit;
|
||
|
||
do
|
||
{
|
||
yield return new WaitForSeconds(1f);
|
||
|
||
Vector2Int target = bot.MakeMove(playerField);
|
||
|
||
if (target.x < 0 || target.y < 0)
|
||
{
|
||
Debug.LogWarning("Боту нечего стрелять, пропускаем ход");
|
||
break; // или EndGame, если нет ходов
|
||
}
|
||
|
||
bool shotComplete = false;
|
||
hit = false;
|
||
|
||
enemyBattery.FireShot(playerField, target.x, target.y, (wasHit, wasShipDestroyed) =>
|
||
{
|
||
hit = wasHit;
|
||
shotComplete = true;
|
||
|
||
ProcessShotResult(wasHit,false, wasShipDestroyed);
|
||
|
||
// if (hit) SoundManager.Instance.PlayBotHit(playerId);
|
||
// else SoundManager.Instance.PlayBotMiss(playerId);
|
||
|
||
// if(wasShipDestroyed) SoundManager.Instance.PlayPlayerShipDestroyed(playerId);
|
||
});
|
||
|
||
yield return new WaitUntil(() => shotComplete);
|
||
|
||
} while (hit);
|
||
|
||
StartPlayerTurn();
|
||
}
|
||
|
||
|
||
public void MoveCameraTo(Transform target)
|
||
{
|
||
if (playerCamera != null && target != null)
|
||
{
|
||
StopAllCoroutines();
|
||
StartCoroutine(MoveCameraSmoothly(target));
|
||
}
|
||
}
|
||
|
||
|
||
private IEnumerator MoveCameraSmoothly(Transform target)
|
||
{
|
||
Transform cam = playerCamera.transform;
|
||
|
||
// Отсоединяем камеру от пивота на время перемещения —
|
||
// иначе поворот пивота кнопками во время полёта камеры сдвигает её конечную позицию
|
||
cam.SetParent(null);
|
||
|
||
Vector3 startPos = cam.position;
|
||
Quaternion startRot = cam.rotation;
|
||
|
||
Vector3 endPos = target.position;
|
||
Quaternion endRot = target.rotation;
|
||
|
||
float elapsed = 0f;
|
||
|
||
while (elapsed < cameraMoveDuration)
|
||
{
|
||
float t = elapsed / cameraMoveDuration;
|
||
cam.position = Vector3.Lerp(startPos, endPos, t);
|
||
cam.rotation = Quaternion.Slerp(startRot, endRot, t);
|
||
elapsed += Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
|
||
cam.position = endPos;
|
||
cam.rotation = endRot;
|
||
|
||
// Сбрасываем пивот и возвращаем камеру обратно как дочерний объект
|
||
if (cameraPivot != null)
|
||
{
|
||
cameraPivot.rotation = Quaternion.identity;
|
||
// worldPositionStays: true — локальные координаты пересчитаются под новый пивот
|
||
cam.SetParent(cameraPivot, true);
|
||
|
||
// Фиксируем новый "дом" и синхронизируем квадрант курсора
|
||
var camCtrl = cameraPivot.GetComponent<CameraPivotController>();
|
||
if (camCtrl != null)
|
||
{
|
||
camCtrl.CaptureHomeNow();
|
||
camCtrl.TargetCursor?.SwitchButton(cameraPivot.rotation.eulerAngles);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Сбрасывает игровое состояние - очищает поля, удаляет курсор, сбрасывает переменные
|
||
/// </summary>
|
||
private void ResetGameState()
|
||
{
|
||
Debug.Log("Сброс состояния игры...");
|
||
|
||
// 1. Сбрасываем игровые поля
|
||
if (playerField != null)
|
||
{
|
||
playerField.ClearPole(); // очистка своего поля (удаляем корабли и сбрасываем массивы)
|
||
}
|
||
|
||
if (enemyField != null)
|
||
{
|
||
enemyField.ClearPole(); // очистка вражеского поля
|
||
}
|
||
|
||
// 2. Удаляем курсор
|
||
if (targetCursorInstance != null)
|
||
{
|
||
Destroy(targetCursorInstance);
|
||
targetCursorInstance = null;
|
||
}
|
||
|
||
// 3. Сбрасываем переменные
|
||
playerShips = 0;
|
||
enemyShips = 0;
|
||
SetPlayerReady(false);
|
||
isPlayerTurn = false;
|
||
SetInputMode(InputMode.UI);
|
||
autoStartBattlePending = false;
|
||
shipPlacementTimer?.StopTimer();
|
||
|
||
Debug.Log("Сброс завершён");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Подготовка к новой игре - сбрасывает состояние и переводит в состояние расстановки
|
||
/// </summary>
|
||
private void PrepareNewGame()
|
||
{
|
||
ResetGameState();
|
||
// Состояние будет установлено в вызывающем методе (StartPlayerGame или StartBotGame)
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возврат в главное меню - сбрасывает состояние и показывает главное меню
|
||
/// </summary>
|
||
public void ReturnToMainMenu()
|
||
{
|
||
paidFroFriend = false;
|
||
currentBotLevel = 0;
|
||
ResetGameState();
|
||
|
||
if (playerId == 1)
|
||
SoundManager.Instance?.SetPvPMode(false);
|
||
|
||
idleVideoRequested = false;
|
||
SetState(GameState.MainMenu);
|
||
}
|
||
|
||
private void HandleShipPlacementTimeout()
|
||
{
|
||
autoStartBattlePending = true;
|
||
|
||
uiManager.HideAllOverlays();
|
||
|
||
if (playerShips != 10)
|
||
{
|
||
playerField.ArrangeShip();
|
||
playerShips = 10;
|
||
}
|
||
|
||
SetPlayerReady(true);
|
||
TryStartBattleAfterPlacementTimeout();
|
||
}
|
||
|
||
private void TryStartBattleAfterPlacementTimeout()
|
||
{
|
||
if (!autoStartBattlePending || currentState != GameState.ShipPlacement || !isReady)
|
||
return;
|
||
|
||
if (gameMode == GameMode.PlayerVsPlayer)
|
||
{
|
||
if (opponentManager == null || !opponentManager.isReady)
|
||
return;
|
||
|
||
autoStartBattlePending = false;
|
||
opponentManager.autoStartBattlePending = false;
|
||
StartBattle();
|
||
return;
|
||
}
|
||
|
||
autoStartBattlePending = false;
|
||
StartBattle();
|
||
}
|
||
}
|