using System; using System.Collections.Generic; using OTGIntegrated.Core; using OTGIntegrated.Player; using OTGIntegrated.Quests; using OTGIntegrated.UI; using UnityEngine; namespace OTGIntegrated.Dialogue { public sealed class DialogueManager : MonoBehaviour { public DialogueUI dialogueUI; private QuestManager questManager; private UIManager uiManager; private PlayerController playerController; private NPCInteract currentNpc; private DialogueNode currentNode; public bool IsDialogueActive { get; private set; } public void Initialize(QuestManager questManager, UIManager uiManager, PlayerController playerController) { this.questManager = questManager; this.uiManager = uiManager; this.playerController = playerController; if (dialogueUI == null) { dialogueUI = FindObjectOfType(true); } } private void Update() { if (IsDialogueActive && Input.GetKeyDown(KeyCode.Escape)) { EndDialogue(); } } public void StartDialogue(NPCInteract npc) { if (npc == null || npc.startNode == null) { return; } currentNpc = npc; IsDialogueActive = true; questManager?.NotifyNpcTalked(npc.npcId); if (uiManager != null) { uiManager.OpenDialogue(); } else if (playerController != null) { playerController.SetInputEnabled(false); } Cursor.lockState = CursorLockMode.None; Cursor.visible = true; ShowNode(npc.startNode); } public void ShowNode(DialogueNode node) { if (node == null) { EndDialogue(); return; } currentNode = node; string speaker = !string.IsNullOrWhiteSpace(node.speakerName) ? node.speakerName : currentNpc != null ? currentNpc.displayName : "NPC"; List choices = BuildChoices(node); dialogueUI?.Show(speaker, node.npcLine, choices); } public void EndDialogue() { if (!IsDialogueActive) { return; } IsDialogueActive = false; currentNpc = null; currentNode = null; dialogueUI?.Hide(); if (uiManager != null) { uiManager.CloseDialogue(); } else if (playerController != null) { playerController.SetInputEnabled(true); Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } } private List BuildChoices(DialogueNode node) { List choices = new List(); if (currentNpc != null && currentNpc.offeredQuest != null && questManager != null) { QuestData quest = currentNpc.offeredQuest; if (!questManager.IsQuestActive(quest) && !questManager.IsQuestCompleted(quest)) { choices.Add(new DialogueChoice($"Взять квест: {quest.displayName}", () => { questManager.StartQuest(quest); EndDialogue(); })); } } if (currentNpc != null && currentNpc.completionQuest != null && questManager != null) { QuestData quest = currentNpc.completionQuest; if (questManager.IsQuestReady(quest)) { choices.Add(new DialogueChoice($"Завершить квест: {quest.displayName}", () => { questManager.TryCompleteQuest(quest, currentNpc.npcId); EndDialogue(); })); } } if (node.responses != null) { for (int i = 0; i < node.responses.Length; i++) { DialogueResponse response = node.responses[i]; if (response == null || string.IsNullOrWhiteSpace(response.responseText)) { continue; } choices.Add(new DialogueChoice(response.responseText, () => SelectResponse(response))); } } if (currentNpc != null && currentNpc.canOpenCrafting) { choices.Add(new DialogueChoice("Открыть крафт", () => { EndDialogue(); uiManager?.OpenCrafting(); })); } choices.Add(new DialogueChoice("Закончить разговор", EndDialogue)); return choices; } private void SelectResponse(DialogueResponse response) { if (response == null) { EndDialogue(); return; } if (response.questToStart != null && questManager != null) { questManager.StartQuest(response.questToStart); } if (response.questToComplete != null && currentNpc != null && questManager != null) { questManager.TryCompleteQuest(response.questToComplete, currentNpc.npcId); } if (response.openCrafting) { EndDialogue(); uiManager?.OpenCrafting(); return; } if (!response.endsDialogue && response.nextNode == null) { ShowInformationalFollowUp(); return; } if (response.endsDialogue || response.nextNode == null) { EndDialogue(); } else { ShowNode(response.nextNode); } } private void ShowInformationalFollowUp() { string speaker = currentNpc != null ? currentNpc.displayName : currentNode != null ? currentNode.speakerName : "NPC"; string text = GetInformationalText(); List choices = new List { new DialogueChoice("Назад", () => ShowNode(currentNode)), new DialogueChoice("Закончить разговор", EndDialogue) }; dialogueUI?.Show(speaker, text, choices); } private string GetInformationalText() { string npcId = currentNpc != null ? currentNpc.npcId : string.Empty; switch (npcId) { case "Elder": return "Нужна обычная древесина из леса. Собери 5 Wood, затем вернись ко мне, чтобы завершить квест."; case "Guard": return "Гоблины стоят в лагере на юго-востоке. Уничтожь 3 Goblin оружием или способностями и возвращайся за наградой."; case "Blacksmith": return "Для Iron Axe нужны Wood x2, Stone x2 и Iron Ore x1. Открой верстак через E рядом со столом или клавишей C."; case "Mage": return "Fireball на 1 тратит ману и наносит урон. Heal на 2 лечит. Blink на 3 переносит вперёд. Таланты открываются на K."; default: return currentNode != null ? currentNode.npcLine : "Подробностей пока нет."; } } } public sealed class DialogueChoice { public string Text { get; } public Action Callback { get; } public DialogueChoice(string text, Action callback) { Text = text; Callback = callback; } } }