using System;
using System.Collections.Generic;
using Cielonos.Core.Interaction;
using Cielonos.MainGame.Narrative;
using Sirenix.OdinInspector;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.Narrative;
using UnityEngine;
namespace Cielonos.MainGame.Interactions
{
///
/// NPC 交互基类。
/// 场景中的 NPC 挂载此脚本,交互时会自动将自身的 storyId 投递给 StoryDirector。
///
public class NpcBase : InteractableObjectBase, IFuncAnimExecutor
{
#region Fields & Properties
[SerializeField]
protected CharacterData characterData;
[TitleGroup("Story Settings", "剧情与对话路由配置", Alignment = TitleAlignments.Centered)]
[SerializeField]
[Tooltip("对应 NarrativeEntry 剧情路由表中的 storyId (如 'OldMan')")]
protected string storyId;
/// NPC 的唯一故事 ID。
public string StoryId => storyId;
[TitleGroup("Components & References", "组件与动作数据引用", Alignment = TitleAlignments.Centered)]
public Animator animator;
public AnimatorOverrideController animatorOverride;
public FuncAnimDataCollection fullBodyFuncAnims;
public VFXData vfxData;
/// NPC 专属动画播放子模块
[HideInInspector]
public NpcFuncAnimSubmodule funcAnimSm;
/// 全局活跃 NPC 查找注册表 (通过 StoryId 和 GameObject 名字进行双重映射查找)
#endregion
#region IFuncAnimExecutor Implementation
public Transform Transform => transform;
public Vector3 CenterPosition => transform.position;
public Animator Animator => animator;
#endregion
#region Lifecycle Callbacks
protected virtual void OnEnable()
{
StoryDirector.ActiveNpcs[characterData.nameKey] = this;
}
protected virtual void OnDisable()
{
StoryDirector.ActiveNpcs.Remove(characterData.nameKey);
}
private void Start()
{
funcAnimSm = new NpcFuncAnimSubmodule(this);
if (fullBodyFuncAnims != null && fullBodyFuncAnims.animDataList != null)
{
foreach (FuncAnimData animData in fullBodyFuncAnims.animDataList)
{
funcAnimSm.Add(animData);
}
}
}
protected virtual void Update()
{
// 推进时间、检测非循环动作结束以及执行重置
funcAnimSm?.Update(Time.deltaTime);
}
protected virtual void LateUpdate()
{
// 在物理表现计算完毕后分发每帧的特效/音效等事件
funcAnimSm?.UpdateEvents();
}
#endregion
#region Interaction Logic
protected override void InitializeChoices()
{
choices.Add(new InteractionChoice("Talk", Talk));
}
///
/// 触发对话。NPC 并不感知具体播放哪个 Yarn 节点,完全委托给 StoryDirector 进行状态评估。
///
public virtual void Talk()
{
if (string.IsNullOrEmpty(storyId))
{
Debug.LogWarning($"[NpcBase] {gameObject.name} 未配置 storyId,无法启动对话。");
return;
}
if (StoryDirector.Instance == null)
{
Debug.LogError("[NpcBase] 启动对话失败:场景中未找到 StoryDirector 实例!");
return;
}
StoryDirector.Instance.PlayStory(storyId);
}
#endregion
}
}