using UnityEngine; using BaseGames.Core; using BaseGames.Dialogue; using BaseGames.Player; using QuestStateEnum = BaseGames.Core.Events.QuestState; using SL = BaseGames.Core.ServiceLocator; namespace BaseGames.Quest { /// /// 可发布/完成任务的 NPC(架构 22_QuestChallengeModule §6)。 /// 继承 InteractableNPC,根据任务状态切换对话版本,在交互时处理任务接收/完成。 /// public class QuestGiver : InteractableNPC { [Header("任务")] [Tooltip("该 NPC 可提供的所有任务,按优先级从高到低排列。\n" + "交互时从列表头部找到第一个 Available 或 Active 状态的任务作为当前任务;\n" + "若全部已完成,显示最后一个已完成任务的 completedDialogue。")] [SerializeField] private QuestSO[] _offeredQuests; [Header("对话版本(根据任务状态切换)")] [Tooltip("任务尚未接取(QuestState.Available)时播放。通常是 NPC 发布任务、介绍背景的对话。")] [SerializeField] private DialogueSequenceSO _availableDialogue; [Tooltip("任务已接取、目标尚未全部完成(QuestState.Active)时播放。通常是 NPC 催促或加油打气的对话。")] [SerializeField] private DialogueSequenceSO _activeDialogue; [Tooltip("全部非可选目标已达成、任务可以交付时播放(IsReadyToComplete = true)。\n" + "通常是 NPC 感谢、确认收取物品的对话,播放后执行 CompleteQuest 逻辑。")] [SerializeField] private DialogueSequenceSO _readyDialogue; [Tooltip("任务已完成(QuestState.Completed)后再次交互时播放。通常是 NPC 闲聊或后续剧情的对话。")] [SerializeField] private DialogueSequenceSO _completedDialogue; // ── InteractableNPC 覆盖 ────────────────────────────────────────────── public override string InteractPrompt { get { var qm = SL.GetOrDefault(); var quest = GetCurrentOrCompletedQuest(qm); if (quest == null || qm == null) return base.InteractPrompt; return qm.GetState(quest.questId) switch { QuestStateEnum.Available => "接受任务", QuestStateEnum.Active => qm.IsReadyToComplete(quest.questId) ? "提交任务" : "进行中…", QuestStateEnum.Paused => "暂停中…", QuestStateEnum.Completed => "对话", _ => base.InteractPrompt, }; } } protected override void Interact_Internal(Transform player) { var qm = SL.GetOrDefault(); var quest = GetCurrentOrCompletedQuest(qm); if (quest == null || qm == null) return; var state = qm.GetState(quest.questId); if (state == QuestStateEnum.Available) { qm.AcceptQuest(quest.questId); } else if (state == QuestStateEnum.Active && qm.IsReadyToComplete(quest.questId)) { // 直接从 player 获取 PlayerStats,避免对 PlayerController 的程序集依赖 var stats = player.GetComponentInParent(); qm.CompleteQuest(quest.questId, stats); } } protected override DialogueSequenceSO GetCurrentDialogue() { var qm = SL.GetOrDefault(); var quest = GetCurrentOrCompletedQuest(qm); if (quest == null || qm == null) return base.GetCurrentDialogue(); var state = qm.GetState(quest.questId); return state switch { QuestStateEnum.Available => _availableDialogue, QuestStateEnum.Active => qm.IsReadyToComplete(quest.questId) ? _readyDialogue : _activeDialogue, QuestStateEnum.Paused => _activeDialogue, // 暂停中显示"催促"对话,不触发任何状态推进 QuestStateEnum.Completed => _completedDialogue, _ => base.GetCurrentDialogue(), }; } // ── 私有辅助 ───────────────────────────────────────────────────────── /// /// 返回当前处于 Available 或 Active 状态的第一个任务; /// 若全部已完成,返回最后一个已完成任务(用于显示 completedDialogue)。 /// private QuestSO GetCurrentOrCompletedQuest(IQuestManager qm = null) { if (_offeredQuests == null) return null; qm ??= SL.GetOrDefault(); if (qm == null) return null; QuestSO lastCompleted = null; foreach (var q in _offeredQuests) { if (q == null) continue; var s = qm.GetState(q.questId); if (s == QuestStateEnum.Available || s == QuestStateEnum.Active || s == QuestStateEnum.Paused) return q; if (s == QuestStateEnum.Completed) lastCompleted = q; } return lastCompleted; } } }