using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Boss;
using BaseGames.Combat;
using BaseGames.Core.Events;
using BaseGames.Parry;
namespace BaseGames.Enemies
{
///
/// Boss 敌人基类。扩展 以支持多阶段切换、技能执行与战斗结束广播。
/// 具体 Boss 继承此类并重写 。
///
public class BossBase : EnemyBase
{
[Header("Boss 配置")]
[SerializeField] private string _bossId;
[SerializeField] private BoolEventChannelSO _onBossFightEnded;
[SerializeField] private BossPhaseEventChannelSO _onBossPhaseChanged;
[Header("技能执行器")]
[SerializeField] private BossSkillExecutor _skillExecutor;
[Header("资源组件(可选)")]
[SerializeField] private BossResource _bossResource;
[Header("玩家反制事件(可选)")]
[Tooltip("订阅此频道以响应玩家弹反成功事件")]
[SerializeField] private ParryInfoEventChannelSO _onParrySuccess;
public string BossId => _bossId;
/// 当前是否有 Boss 技能正在执行(BD_UseBossSkill 轮询此值)。
public bool IsBossSkillExecuting => _skillExecutor != null && _skillExecutor.IsExecuting;
protected int _currentPhase = 0;
/// 当前 Boss 阶段索引(BD Task 可直接查询)。
public int CurrentPhase => _currentPhase;
private Coroutine _counterStaggerCoroutine;
// 缓存加权候选列表,避免 UseBossSkillWeighted() 每次 new List → GC 分配
private readonly List<(BossSkillSO skill, float w)> _weightedCandidates = new(8);
// 单元素缓冲数组,供 ApplyCounterResponse 缓存当前技能,避免 new[] 分配
private readonly BossSkillSO[] _singleSkillBuf = new BossSkillSO[1];
protected override void Awake()
{
base.Awake();
// includeInactive:true 确保禁用状态的子组件也能被发现(如分阶段按需启用的执行器)
if (_skillExecutor == null) _skillExecutor = GetComponentInChildren(true);
if (_bossResource == null) _bossResource = GetComponentInChildren(true);
}
protected override void OnEnable()
{
base.OnEnable();
_onParrySuccess?.Subscribe(HandleParrySuccess).AddTo(_subs);
}
///
/// 阶段过渡期间完全无敌( 的 IsInvincible 检查由此路由)。
///
public override bool IsInvincible => IsPhaseTransitioning || base.IsInvincible;
///
/// 上一次成功执行的技能 ID。 对其施加权重惩罚,防止相同技能连续重复。
///
public string LastUsedSkillId { get; private set; }
// ── 技能执行(BD Task 调用入口)─────────────────────────────────────
///
/// 通过技能 ID 执行 Boss 技能。
/// 若技能未找到、执行器忙或冷却中则返回 false,否则返回 true。
///
public bool UseBossSkill(string skillId)
{
if (_skillExecutor == null || string.IsNullOrEmpty(skillId)) return false;
if (IsPhaseTransitioning) return false;
var skill = _skillExecutor.FindSkill(skillId);
if (skill == null)
{
Debug.LogWarning($"[BossBase] 未找到技能 '{skillId}'(Boss: {_bossId})", this);
return false;
}
if (!_skillExecutor.CanUseSkill(skillId))
return false;
if (!CheckResourceCost(skill))
return false;
_skillExecutor.ExecuteSkill(skill);
_bossResource?.OnBossUseSkill();
return true;
}
///
/// 在当前阶段可用且冷却就绪的技能中,按 加权随机选择一个并执行。
/// 若上一次已使用某技能,则对该技能施加 0.3× 权重惩罚,降低连续重复的概率。
/// 若无可用技能或执行器忙则返回 false。
///
public bool UseBossSkillWeighted()
{
if (_skillExecutor == null || _skillExecutor.IsExecuting) return false;
if (IsPhaseTransitioning) return false;
var skills = _skillExecutor.Skills;
if (skills == null || skills.Length == 0) return false;
// 筛选:在当前阶段可用 + 冷却就绪 + weight > 0
_weightedCandidates.Clear();
float totalWeight = 0f;
foreach (var s in skills)
{
if (s == null || s.weight <= 0f) continue;
if (!_skillExecutor.CanUseSkill(s.skillId)) continue;
if (!IsSkillAvailableInPhase(s)) continue;
// 防重复:上一个技能权重打折
float w = s.skillId == LastUsedSkillId ? s.weight * 0.3f : s.weight;
_weightedCandidates.Add((s, w));
totalWeight += w;
}
if (_weightedCandidates.Count == 0 || totalWeight <= 0f) return false;
// 加权随机抽取
float roll = UnityEngine.Random.Range(0f, totalWeight);
BossSkillSO selected = null;
float accum = 0f;
foreach (var (skill, w) in _weightedCandidates)
{
accum += w;
if (roll <= accum) { selected = skill; break; }
}
selected ??= _weightedCandidates[_weightedCandidates.Count - 1].skill;
if (!CheckResourceCost(selected)) return false;
_skillExecutor.ExecuteSkill(selected);
LastUsedSkillId = selected.skillId;
_bossResource?.OnBossUseSkill();
return true;
}
/// 检查技能的 availablePhaseIndices 是否包含当前阶段(空数组 = 全阶段可用)。
private bool IsSkillAvailableInPhase(BossSkillSO skill)
{
if (skill.availablePhaseIndices == null || skill.availablePhaseIndices.Length == 0)
return true;
foreach (int p in skill.availablePhaseIndices)
if (p == _currentPhase) return true;
return false;
}
///
/// 检查 Boss 资源是否满足技能的 minRequired 门槛。
/// 未配置资源组件或 minRequired <= 0 时视为通过。
///
private bool CheckResourceCost(BossSkillSO skill)
{
if (_bossResource == null) return true;
float min = skill.resourceCost.minRequired;
if (min <= 0f) return true;
return _bossResource.CurrentValue >= min;
}
// ── 阶段 ──────────────────────────────────────────────────────────────
/// 当前是否处于阶段过渡(无敌帧 + 过渡演出)期间。
public bool IsPhaseTransitioning { get; private set; }
private Coroutine _phaseTransitionCoroutine;
///
/// 进入指定阶段。自动打断当前执行中的技能,广播 供 UI / 音乐系统响应。
/// 子类可重写以添加额外过渡逻辑(动画、无敌帧等)。
///
public virtual void EnterPhase(int phase)
{
// 阶段切换必须先打断正在执行的技能,确保原子性
_skillExecutor?.InterruptCurrentSkill();
_currentPhase = phase;
LastUsedSkillId = null; // 新阶段重置权重惩罚,防止跨阶段漂移
_onBossPhaseChanged?.Raise(new BossPhaseEvent
{
BossId = _bossId,
Phase = phase,
});
}
///
/// 启动阶段过渡演出:无敌帧 + 可选定格时间,结束后自动调用 。
/// BD_BossPhaseTransition 检查 来等待过渡完成。
///
/// 过渡目标阶段索引。
/// 无敌帧持续时间(秒)。
public void BeginPhaseTransition(int targetPhase, float invincibleDuration = 1.5f)
{
if (IsPhaseTransitioning)
{
Debug.LogWarning(
$"[BossBase] '{_bossId}' 已在阶段过渡中(当前阶段 {_currentPhase})," +
$"忽略跳转至阶段 {targetPhase} 的请求。请检查行为树逻辑是否重复触发阶段切换。",
this);
return;
}
if (_phaseTransitionCoroutine != null) StopCoroutine(_phaseTransitionCoroutine);
_phaseTransitionCoroutine = StartCoroutine(PhaseTransitionCoroutine(targetPhase, invincibleDuration));
}
private IEnumerator PhaseTransitionCoroutine(int targetPhase, float duration)
{
IsPhaseTransitioning = true;
// 打断技能 + 停止移动
_skillExecutor?.InterruptCurrentSkill();
StopMovement();
// 无敌帧期间接受的伤害由 IsInvincible 属性屏蔽(子类重写 IsInvincible 或在此处理)
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
yield return null;
}
EnterPhase(targetPhase);
IsPhaseTransitioning = false;
_phaseTransitionCoroutine = null;
}
///
/// 立即终止阶段过渡协程并清除标志位。
/// 死亡时调用,防止 IsPhaseTransitioning 永久为 true 影响对象池复用。
///
private void AbortPhaseTransition()
{
if (_phaseTransitionCoroutine != null)
{
StopCoroutine(_phaseTransitionCoroutine);
_phaseTransitionCoroutine = null;
}
IsPhaseTransitioning = false;
}
/// 检查当前 HP 是否低于指定百分比(0~1)。
public bool IsHPBelow(float ratio)
{
if (_stats == null || _stats.MaxHP <= 0) return false;
return (float)_stats.CurrentHP / _stats.MaxHP < ratio;
}
protected override void OnDamageTaken(DamageInfo info)
{
_bossResource?.OnBossTakeDamage();
}
protected override void Die()
{
// 死亡时立即中止阶段过渡,防止 IsPhaseTransitioning 标志永久锁死(影响对象池复用)
AbortPhaseTransition();
base.Die();
_onBossFightEnded?.Raise(true);
}
// ── 玩家反制响应 ──────────────────────────────────────────────────────
private void HandleParrySuccess(ParryInfo info)
{
if (!IsAlive) return;
var counterType = info.IsPerfect ? CounterType.PerfectParry : CounterType.Parry;
ApplyCounterResponse(counterType, string.Empty);
}
///
/// 根据 counterType 查找当前技能(或所有技能)的 PlayerCounterResponse 并应用效果。
/// 可由外部系统(闪避穿越、弱点命中等)直接调用。
///
public void ApplyCounterResponse(CounterType counterType, string requiredSkillId)
{
if (_skillExecutor == null) return;
// 优先检查当前正在执行的技能的反制规则
BossSkillSO activeSkill = _skillExecutor.IsExecuting
? _skillExecutor.FindCurrentSkill()
: null;
BossSkillSO[] candidates;
if (activeSkill != null)
{
_singleSkillBuf[0] = activeSkill;
candidates = _singleSkillBuf;
}
else
{
candidates = _skillExecutor.Skills;
}
if (candidates == null) return;
foreach (var skill in candidates)
{
if (skill?.counterResponses == null) continue;
foreach (var resp in skill.counterResponses)
{
if (resp.counterType != counterType) continue;
if (!string.IsNullOrEmpty(resp.requiredSkillId) &&
!string.IsNullOrEmpty(requiredSkillId) &&
resp.requiredSkillId != requiredSkillId)
continue;
ExecuteCounterEffect(resp);
return; // 每次反制只触发第一条匹配规则
}
}
}
private void ExecuteCounterEffect(in PlayerCounterResponse resp)
{
if (resp.interruptSkill)
_skillExecutor?.InterruptCurrentSkill();
if (resp.bossStaggerDuration > 0f)
{
if (_counterStaggerCoroutine != null)
StopCoroutine(_counterStaggerCoroutine);
_counterStaggerCoroutine = StartCoroutine(CounterStaggerCoroutine(resp.bossStaggerDuration));
}
if (resp.openVulnWindow)
{
float duration = Mathf.Max(resp.bossStaggerDuration, 1f);
float multiplier = 1f + resp.bossDamageBonus;
_skillExecutor?.OpenVulnerabilityWindow(duration, multiplier);
}
resp.counterFeedback?.Play();
}
private IEnumerator CounterStaggerCoroutine(float duration)
{
ForceState(EnemyStateType.Stagger);
// 时长固定且较短,直接 new WFY 即可;若需优化可接入 WFS 缓存
yield return new WaitForSeconds(duration);
if (IsAlive && CurrentState == EnemyStateType.Stagger)
ForceState(EnemyStateType.Controlled);
_counterStaggerCoroutine = null;
}
public override void OnSpawn()
{
base.OnSpawn();
LastUsedSkillId = null;
_currentPhase = 0;
_skillExecutor?.ResetAllCooldowns();
}
}
}