sea-battle/Assets/Scripts/UI/Enemy/EnemyManager.cs

300 lines
9.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
[Header("Ñïèñîê âðàãîâ")]
public EnemyData[] enemies;
[Header("UI êîíòðîëëåð êàðòî÷êè")]
public EnemyCardController cardController;
[Header("Settings")]
public float dialogueHoldTime = 1f;
private int currentIndex = 0;
private int playerId;
private Coroutine currentDialogueCoroutine;
private bool isDialoguePlaying = false;
// Îòñëåæèâàíèå èñïîëüçîâàííûõ ðåïëèê äëÿ êàæäîãî òèïà ñîáûòèÿ
private Dictionary<DialogueEventType, List<int>> usedDialogueIndices = new Dictionary<DialogueEventType, List<int>>();
private void Awake()
{
FetchPlayerId();
}
private void FetchPlayerId()
{
if (playerId != 0) return; // óæå óñòàíîâëåí
var player = gameObject.GetComponentInParent<Player>(includeInactive: true);
if (player != null)
{
playerId = player.PlayerId;
Debug.Log($"[EnemyManager {name}] FetchPlayerId — playerId = {playerId}");
}
else
Debug.LogWarning($"[{name}] Player íå íàéäåí â ðîäèòåëÿõ!");
}
public void SetEnemy(int index)
{
if (enemies == null || index < 0 || index >= enemies.Length)
{
Debug.LogWarning($"[{name}] SetEnemy: invalid index {index}");
return;
}
if (!cardController.gameObject.activeSelf)
cardController.gameObject.SetActive(true);
currentIndex = index;
cardController.SetEnemy(enemies[index]);
isDialoguePlaying = false;
// Ñáðàñûâàåì èñòîðèþ èñïîëüçîâàííûõ ðåïëèê ïðè ñìåíå âðàãà
usedDialogueIndices.Clear();
}
public void SetEnemyPlayer()
{
// Ãàðàíòèðóåì ÷òî playerId óñòàíîâëåí — Awake ìîã íå ñðàáîòàòü åñëè îáúåêò áûë ñêðûò
FetchPlayerId();
// Ïðîôèëè èãðîêîâ - ýòî ïîñëåäíèå 2 ýëåìåíòà â ìàññèâå enemies
// playerId = 1 -> enemies[Length-2], playerId = 2 -> enemies[Length-1]
if (enemies == null || enemies.Length < 2)
{
Debug.LogWarning($"[{name}] SetEnemyPlayer: íåäîñòàòî÷íî âðàãîâ â ìàññèâå äëÿ ïðîôèëåé èãðîêîâ!");
cardController.gameObject.SetActive(false);
return;
}
int playerProfileIndex = enemies.Length - (3 - playerId);
Debug.Log($"[EnemyManager {name}] SetEnemyPlayer — playerId={playerId}, enemies.Length={enemies.Length}, playerProfileIndex={playerProfileIndex}");
if (playerProfileIndex < 0 || playerProfileIndex >= enemies.Length)
{
Debug.LogWarning($"[{name}] SetEnemyPlayer: íåêîððåêòíûé èíäåêñ ïðîôèëÿ èãðîêà {playerProfileIndex}");
cardController.gameObject.SetActive(false);
return;
}
currentIndex = playerProfileIndex;
// Ñêðûâàåì êàðòî÷êó (èãðîê íå ïîêàçûâàåò UI)
cardController.gameObject.SetActive(false);
isDialoguePlaying = false;
// Ñáðàñûâàåì èñòîðèþ èñïîëüçîâàííûõ ðåïëèê
usedDialogueIndices.Clear();
}
/// <summary>
/// Ïîêàçûâàåò äèàëîã ñ êàðòî÷êîé: îòêðûâàåò ? ãîâîðèò ? çàêðûâàåò
/// Åñëè êàðòî÷êà íåàêòèâíà - ïðîñòî èãðàåò çâóê
/// </summary>
public void ShowDialogueWithCard(DialogueLine line)
{
// Åñëè êàðòî÷êà íåàêòèâíà - ïðîñòî èãðàåì çâóê
if (cardController == null || !cardController.gameObject.activeInHierarchy)
{
PlayVoiceOnly(line.voiceClip);
return;
}
if (currentDialogueCoroutine != null)
StopCoroutine(currentDialogueCoroutine);
currentDialogueCoroutine = StartCoroutine(DialogueWithCardSequence(line));
}
/// <summary>
/// Ïðîèãðûâàåò òîëüêî çâóê áåç êàðòî÷êè
/// </summary>
public void PlayVoiceOnly(AudioClip clip)
{
if (clip == null || SoundManager.Instance == null) return;
SoundManager.Instance.PlayVoice(playerId, clip);
// Åñëè êàðòî÷êà ñêðûòà (PvP) — isDialoguePlaying ñáðàñûâàåì ïî äëèíå êëèïà,
// èíà÷å îí îñòàëñÿ áû true íàâñåãäà è ñëåäóþùàÿ ðåïëèêà íèêîãäà íå ñûãðàëà
if (cardController == null || !cardController.gameObject.activeInHierarchy)
{
if (gameObject.activeInHierarchy)
StartCoroutine(ResetDialogueAfter(clip.length));
else
isDialoguePlaying = false; // îáúåêò íåàêòèâåí — ñáðàñûâàåì ôëàã ñðàçó
}
}
private IEnumerator ResetDialogueAfter(float duration)
{
yield return new WaitForSeconds(duration);
isDialoguePlaying = false;
}
/// <summary>
/// Ïîêàçûâàåò òåêñò íà óæå îòêðûòîé êàðòî÷êå (áåç àíèìàöèè îòêðûòèÿ/çàêðûòèÿ)
/// </summary>
public void ShowTextOnly(string text, string emotion = null)
{
if (!string.IsNullOrEmpty(emotion))
cardController.SetEmotion(emotion);
cardController.TypeText(text);
}
private IEnumerator DialogueWithCardSequence(DialogueLine line)
{
isDialoguePlaying = true;
// 1. Ïîäãîòàâëèâàåì ðàçìåð òåêñòà ÄÎ îòêðûòèÿ ïàíåëè (÷òîáû íå áûëî "áëèêà")
yield return cardController.PrepareTextSizeAsync(line.text);
// 2. Îòêðûâàåì êàðòî÷êó ñ ýìîöèåé ïåðåõîäà
bool cardOpened = false;
cardController.ShowCard(line.animationName.ToStateName(), () => cardOpened = true);
// Æä¸ì, ïîêà êàðòî÷êà îòêðîåòñÿ
yield return new WaitUntil(() => cardOpened);
// 3. Èãðàåì çâóê
if (line.voiceClip != null && SoundManager.Instance != null)
{
SoundManager.Instance.PlayVoice(playerId, line.voiceClip);
}
// 4. Ïå÷àòàåì òåêñò (ðàçìåð óæå ïîäãîòîâëåí)
bool textComplete = false;
cardController.TypeText(line.text, () => textComplete = true, skipSizePreparation: true);
// Æä¸ì, ïîêà òåêñò íàïå÷àòàåòñÿ
yield return new WaitUntil(() => textComplete);
// 4. Äåðæèì òåêñò íåìíîãî
yield return new WaitForSeconds(dialogueHoldTime);
// 5. Çàêðûâàåì êàðòî÷êó
bool cardClosed = false;
cardController.HideCard(() => cardClosed = true);
yield return new WaitUntil(() => cardClosed);
isDialoguePlaying = false;
}
/// <summary>
/// Âûçûâàåò äèàëîã ðåàêöèè íà ñîáûòèå (ñ êàðòî÷êîé)
/// Âûáèðàåò ðåïëèêó êîòîðàÿ åù¸ íå èñïîëüçîâàëàñü, ïîêà âñå íå êîí÷àòñÿ
/// </summary>
public void TriggerEventReaction(DialogueEventType eventType)
{
if (enemies == null || currentIndex < 0 || currentIndex >= enemies.Length)
return;
if(isDialoguePlaying) return;
var enemy = enemies[currentIndex];
DialogueLine? line = GetNonRepeatingDialogue(enemy, eventType);
if (line.HasValue)
{
ShowDialogueWithCard(line.Value);
}
}
/// <summary>
/// Ïîëó÷àåò ñëó÷àéíóþ ðåïëèêó êîòîðàÿ åù¸ íå èñïîëüçîâàëàñü äëÿ äàííîãî òèïà ñîáûòèÿ
/// </summary>
private DialogueLine? GetNonRepeatingDialogue(EnemyData enemy, DialogueEventType eventType)
{
if (enemy == null)
return null;
// Ïîëó÷àåì íóæíûé ìàññèâ ðåïëèê ïî òèïó ñîáûòèÿ
DialogueLine[] sourceArray = null;
switch (eventType)
{
case DialogueEventType.PlayerHit: sourceArray = enemy.onPlayerHit; break;
case DialogueEventType.PlayerMiss: sourceArray = enemy.onPlayerMiss; break;
case DialogueEventType.BotHit: sourceArray = enemy.onBotHit; break;
case DialogueEventType.BotMiss: sourceArray = enemy.onBotMiss; break;
case DialogueEventType.PlayerShipDestroyed: sourceArray = enemy.onPlayerShipDestroyed; break;
case DialogueEventType.BotShipDestroyed: sourceArray = enemy.onBotShipDestroyed; break;
}
if (sourceArray == null || sourceArray.Length == 0)
return null;
// Èíèöèàëèçèðóåì ñïèñîê èñïîëüçîâàííûõ ðåïëèê äëÿ ýòîãî òèïà ñîáûòèÿ åñëè íóæíî
if (!usedDialogueIndices.ContainsKey(eventType))
{
usedDialogueIndices[eventType] = new List<int>();
}
var usedList = usedDialogueIndices[eventType];
// Ñîçäà¸ì ñïèñîê íåèñïîëüçîâàííûõ èíäåêñîâ
var unusedIndices = new List<int>();
for (int i = 0; i < sourceArray.Length; i++)
{
if (!usedList.Contains(i))
unusedIndices.Add(i);
}
// Åñëè âñå ðåïëèêè èñïîëüçîâàíû - ñáðàñûâàåì è íà÷èíàåì çàíîâî
if (unusedIndices.Count == 0)
{
usedList.Clear();
for (int i = 0; i < sourceArray.Length; i++)
{
unusedIndices.Add(i);
}
}
// Âûáèðàåì ñëó÷àéíûé íåèñïîëüçîâàííûé èíäåêñ
int randomIndex = unusedIndices[Random.Range(0, unusedIndices.Count)];
usedList.Add(randomIndex);
return sourceArray[randomIndex];
}
/// <summary>
/// Ðåàêöèÿ íà êîíåö èãðû (òîëüêî çâóê, áåç êàðòî÷êè)
/// </summary>
public void TriggerEndGameReaction(bool playerWon)
{
if (enemies == null || enemies.Length == 0) return;
if (currentIndex < 0 || currentIndex >= enemies.Length) return;
isDialoguePlaying = true;
var enemy = enemies[currentIndex];
var clips = playerWon ? enemy.playerVictory : enemy.playerDefeat;
if (clips == null || clips.Length == 0) return;
// Îñòàíàâëèâàåì ãîëîñîâîé êàíàë òåêóùåãî èãðîêà, çàòåì ïðîèãðûâàåì ôèíàëüíóþ ôðàçó
if (SoundManager.Instance != null)
{
SoundManager.Instance.StopVoice(playerId);
}
Debug.Log(clips[0].name);
PlayVoiceOnly(clips[Random.Range(0, clips.Length)]);
}
public EnemyData GetCurrentEnemy()
{
if (enemies == null || currentIndex < 0 || currentIndex >= enemies.Length)
return null;
return enemies[currentIndex];
}
}