using System.Collections;
using UnityEngine;
using UnityEngine.AI;
///
/// Искусственный интеллект уникального Босса 2-го уровня («Тип-0: Альфа-Мутант / Патриарх»).
/// Механики:
/// 1. Мощная рукопашная атака (40 урона) вблизи.
/// 2. Дальняя атака: кислотный плевок с созданием волны эхолокации при ударе и ядовитой лужи.
/// 3. Акустическое ослепление (Blackout Screech): оглушающий крик, полностью блокирующий эхолокацию на 4.5с.
/// 4. Изолированная комната-арена с карантинной блокировкой дверей до победы над боссом.
///
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(MutantHealth))]
public class TitanBossAI : MonoBehaviour
{
[Header("Идентификация босса")]
public string bossDisplayName = "ТИП-0: АЛЬФА-МУТАНТ (ПАТРИАРХ)";
[Header("Параметры движения")]
public float walkSpeed = 2.8f;
public float runSpeed = 4.6f;
public float stoppingDistance = 2.0f;
[Header("Ближний бой")]
public float meleeRange = 2.4f;
public float meleeDamage = 18f;
public float meleeCooldown = 2.2f;
private float nextMeleeTime = 0f;
[Header("Дальний бой (Кислотный плевок)")]
public float spitMinDistance = 5.0f;
public float spitCooldown = 8.5f;
public float spitDamage = 14f;
private float nextSpitTime = 0f;
[Header("Акустическое ослепление (Крик слепоты)")]
public float screechCooldown = 17f;
public float blindnessDuration = 4.5f;
private float nextScreechTime = 0f;
private bool hasEnragedBelowHalf = false;
[Header("Ссылки на компоненты")]
public Transform mouthSpawnPoint;
public BossArenaController arenaController;
private NavMeshAgent agent;
private Animator animator;
private MutantHealth health;
private Transform player;
private PlayerHealth playerHealth;
public enum BossState { Dormant, Roaring, Combat, Screeching, Spitting, Dead }
public BossState CurrentState { get; private set; } = BossState.Dormant;
private void Awake()
{
agent = GetComponent();
animator = GetComponentInChildren();
health = GetComponent();
// Увеличиваем здоровье босса (200 HP)
health.maxHealth = 200f;
}
private void Start()
{
// Игрок
GameObject pObj = GameObject.FindWithTag("Player") ?? GameObject.Find("Player");
if (pObj != null)
{
player = pObj.transform;
playerHealth = pObj.GetComponent();
}
if (agent != null)
{
agent.speed = walkSpeed;
agent.stoppingDistance = stoppingDistance;
agent.isStopped = true;
if (!agent.isOnNavMesh)
{
if (NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 5.0f, NavMesh.AllAreas))
{
agent.Warp(hit.position);
}
}
}
// Подписываемся на события здоровья
if (health != null)
{
health.OnHealthChanged += HandleHealthChanged;
health.OnDied += HandleDeath;
}
// Назначаем точку рта для плевка прямо в пасти головы монстра
if (mouthSpawnPoint == null)
{
Transform headBone = null;
foreach (var t in GetComponentsInChildren())
{
if (t.name == "head") { headBone = t; break; }
}
GameObject mouth = new GameObject("MouthPoint");
if (headBone != null)
{
mouth.transform.SetParent(headBone, false);
// Смещение в пасть монстра относительно кости головы
mouth.transform.localPosition = new Vector3(-0.08f, 0.25f, 0.32f);
}
else
{
mouth.transform.SetParent(transform, false);
mouth.transform.localPosition = new Vector3(0f, 2.75f, 0.55f);
}
mouthSpawnPoint = mouth.transform;
}
nextSpitTime = Time.time + 4f;
nextScreechTime = Time.time + 12f;
}
///
/// Вызывается триггером комнаты, когда игрок заходит на арену и двери блокируются
///
public void WakeUp()
{
if (CurrentState != BossState.Dormant) return;
StartCoroutine(RoutineWakeUpRoar());
}
private IEnumerator RoutineWakeUpRoar()
{
CurrentState = BossState.Roaring;
// Поворачиваемся к игроку
if (player != null)
{
Vector3 lookDir = (player.position - transform.position);
lookDir.y = 0;
if (lookDir.sqrMagnitude > 0.01f) transform.rotation = Quaternion.LookRotation(lookDir);
}
// Рев пробуждения
GameAudioSynthesizer.PlayBossRoar();
// Отображаем здоровье на экране
if (BossHealthBarUI.Instance != null && health != null)
{
BossHealthBarUI.Instance.ShowBoss(bossDisplayName, health.CurrentHealth, health.maxHealth);
}
// Создаем мощную волну эхолокации от рева
if (EchoTrigger.Instance != null)
{
EchoTrigger.Instance.TriggerExternalWave(transform.position, 28f, 3.5f);
}
yield return new WaitForSeconds(1.8f);
if (CurrentState != BossState.Dead)
{
CurrentState = BossState.Combat;
if (agent != null && agent.isOnNavMesh) agent.isStopped = false;
}
}
private void Update()
{
if (CurrentState == BossState.Dormant || CurrentState == BossState.Dead)
{
UpdateAnimationSpeed(0f);
return;
}
if (CurrentState == BossState.Roaring || CurrentState == BossState.Screeching || CurrentState == BossState.Spitting)
{
UpdateAnimationSpeed(0f);
return;
}
if (player == null || playerHealth == null || playerHealth.IsDead)
{
if (agent != null && agent.isOnNavMesh) agent.isStopped = true;
UpdateAnimationSpeed(0f);
return;
}
float dist = Vector3.Distance(transform.position, player.position);
// 1. Проверка на фазовый крик ослепления (Acoustic Blackout Screech)
if (Time.time >= nextScreechTime)
{
StartCoroutine(RoutineAcousticScreech());
return;
}
// 2. Ближний бой (если подошли в упор)
if (dist <= meleeRange)
{
if (agent != null && agent.isOnNavMesh) agent.isStopped = true;
UpdateAnimationSpeed(0f);
// Поворот к игроку
FaceTarget(player.position);
if (Time.time >= nextMeleeTime)
{
PerformMeleeAttack();
}
return;
}
// 3. Дальний бой (Кислотный плевок)
if (dist >= spitMinDistance && Time.time >= nextSpitTime)
{
StartCoroutine(RoutineSpitAttack());
return;
}
// 4. Погоня за игроком внутри комнаты
if (agent != null && agent.isOnNavMesh)
{
agent.isStopped = false;
agent.speed = runSpeed;
agent.SetDestination(player.position);
UpdateAnimationSpeed(agent.velocity.magnitude);
}
}
private void PerformMeleeAttack()
{
nextMeleeTime = Time.time + meleeCooldown;
if (animator != null)
{
animator.SetTrigger("Attack");
}
StartCoroutine(RoutineMeleeDamageCheck());
}
private IEnumerator RoutineMeleeDamageCheck()
{
yield return new WaitForSeconds(0.45f);
if (CurrentState == BossState.Dead) yield break;
if (player != null && playerHealth != null && !playerHealth.IsDead)
{
float dist = Vector3.Distance(transform.position, player.position);
if (dist <= meleeRange + 0.8f)
{
playerHealth.TakeDamage(meleeDamage);
Debug.Log($"[Босс] Сокрушительный удар вблизи! Нанесено {meleeDamage} урона.");
// Мощный глухой удар
GameAudioSynthesizer.PlayErrorCode();
// Волна от удара о землю
if (EchoTrigger.Instance != null)
{
EchoTrigger.Instance.TriggerExternalWave(transform.position + transform.forward * 1.2f, 15f, 2.0f);
}
}
}
}
public Vector3 GetMouthPosition()
{
if (mouthSpawnPoint != null) return mouthSpawnPoint.position;
Transform headBone = null;
foreach (var t in GetComponentsInChildren())
{
if (t.name == "head") { headBone = t; break; }
}
if (headBone != null)
{
return headBone.position + transform.forward * 0.45f - Vector3.up * 0.12f;
}
return transform.position + Vector3.up * 2.75f + transform.forward * 0.55f;
}
private IEnumerator RoutineSpitAttack()
{
CurrentState = BossState.Spitting;
nextSpitTime = Time.time + spitCooldown;
if (agent != null && agent.isOnNavMesh) agent.isStopped = true;
// Поворот к цели
FaceTarget(player.position);
if (animator != null)
{
animator.SetTrigger("Attack");
}
// Звук клокотания в горле перед извержением слюны
GameAudioSynthesizer.PlayAcidHiss();
yield return new WaitForSeconds(0.35f);
if (CurrentState == BossState.Dead) yield break;
// Звук сочного хлёсткого плевка изо рта
GameAudioSynthesizer.PlayAcidSpitSound();
// Спавним очередь брызг слюны прямо из пасти босса
Vector3 target = player != null ? player.position + Vector3.up * 1.1f : transform.position + transform.forward * 10f;
// 1. Основной тяжелый сгусток слюны
Vector3 spawn1 = GetMouthPosition();
AcidProjectile.Spawn(spawn1, target, projSpeed: 19f, damage: spitDamage * 0.7f, isMain: true, spreadAngle: 0f);
// 2. Вторая капля слюны с легким естественным разлетом
yield return new WaitForSeconds(0.06f);
if (CurrentState == BossState.Dead) yield break;
Vector3 spawn2 = GetMouthPosition();
AcidProjectile.Spawn(spawn2, target, projSpeed: 17.5f, damage: spitDamage * 0.2f, isMain: false, spreadAngle: 3f);
// 3. Третья мелкая брызга слюны
yield return new WaitForSeconds(0.05f);
if (CurrentState == BossState.Dead) yield break;
Vector3 spawn3 = GetMouthPosition();
AcidProjectile.Spawn(spawn3, target, projSpeed: 16.5f, damage: spitDamage * 0.1f, isMain: false, spreadAngle: 5f);
yield return new WaitForSeconds(0.4f);
if (CurrentState != BossState.Dead)
{
CurrentState = BossState.Combat;
if (agent != null && agent.isOnNavMesh) agent.isStopped = false;
}
}
private IEnumerator RoutineAcousticScreech()
{
CurrentState = BossState.Screeching;
nextScreechTime = Time.time + screechCooldown;
if (agent != null && agent.isOnNavMesh) agent.isStopped = true;
FaceTarget(player.position);
Debug.Log("[Босс] АКУСТИЧЕСКИЙ КРИК: ПОЛНОЕ ОСЛЕПЛЕНИЕ ПРОСТРАНСТВА!");
// Оглушительный крик
GameAudioSynthesizer.PlayAcousticScreech();
// Активируем полную слепоту в эхолокаторе (эхолокация заблокирована)
if (EchoTrigger.Instance != null)
{
EchoTrigger.Instance.ApplyBlindness(blindnessDuration);
}
yield return new WaitForSeconds(1.2f);
if (CurrentState != BossState.Dead)
{
CurrentState = BossState.Combat;
// Во время слепоты босс яростно бежит на игрока!
if (agent != null && agent.isOnNavMesh)
{
agent.isStopped = false;
agent.speed = runSpeed * 1.15f; // Ускоренный рывок в темноте!
if (player != null) agent.SetDestination(player.position);
}
}
}
private void HandleHealthChanged(float current, float max)
{
if (BossHealthBarUI.Instance != null)
{
BossHealthBarUI.Instance.UpdateHealth(current, max);
}
// Ярость при падении ниже 50% HP: внеочередной крик ослепления
if (!hasEnragedBelowHalf && current <= max * 0.5f)
{
hasEnragedBelowHalf = true;
nextScreechTime = Time.time + 0.5f; // Немедленный крик ярости!
}
}
private void HandleDeath()
{
CurrentState = BossState.Dead;
if (agent != null && agent.isOnNavMesh)
{
agent.isStopped = true;
agent.enabled = false;
}
if (animator != null)
{
animator.SetBool("IsDead", true);
animator.SetTrigger("Die");
}
// Скрываем полосу здоровья
if (BossHealthBarUI.Instance != null)
{
BossHealthBarUI.Instance.HideBoss(false);
}
// Сообщаем контроллеру арены о победе (открытие дверей)
if (arenaController != null)
{
arenaController.OnBossDefeated();
}
// Финальная победная волна рассеивания
if (EchoTrigger.Instance != null)
{
EchoTrigger.Instance.TriggerExternalWave(transform.position, 35f, 4.0f);
}
GameAudioSynthesizer.PlaySuccessChime();
Debug.Log("[Босс] БОСС ПОВЕРЖЕН! Карантинная блокировка снята, шлюз открыт.");
}
private void FaceTarget(Vector3 targetPos)
{
Vector3 dir = (targetPos - transform.position);
dir.y = 0;
if (dir.sqrMagnitude > 0.001f)
{
Quaternion rot = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.Slerp(transform.rotation, rot, 10f * Time.deltaTime);
}
}
private void UpdateAnimationSpeed(float speedVal)
{
if (animator != null)
{
animator.SetFloat("Speed", speedVal);
}
}
}