250 lines
8.2 KiB
C#
250 lines
8.2 KiB
C#
|
|
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<DialogueUI>(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<DialogueChoice> 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<DialogueChoice> BuildChoices(DialogueNode node)
|
||
|
|
{
|
||
|
|
List<DialogueChoice> choices = new List<DialogueChoice>();
|
||
|
|
|
||
|
|
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<DialogueChoice> choices = new List<DialogueChoice>
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|