Firstborn/Assets/RPG Creation Kit/Scripts/AI/AI Scripts/AITalkative.cs

523 lines
19 KiB
C#
Raw Permalink Normal View History

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPGCreationKit;
using RPGCreationKit.DialogueSystem;
using XNode;
namespace RPGCreationKit.AI
{
public class AITalkative : AIStatus, IDialoguable
{
public bool dialogueSystemEnabled = true;
public IDialoguable speakingTo;
public AILookAt aiLookAt;
public DialogueGraph currentDialogueGraph;
[HideInInspector] public DialogueGraph previousDialogueGraph;
public DialogueGraph defaultDialogueGraph;
// Variables to update the NPC state
[HideInInspector] public bool isInConversation = false;
[HideInInspector] public bool isTalking = false;
[HideInInspector] public bool isListening = false;
// Setting this in the consequences will allow NPC to follow and speak to the player
[HideInInspector] public bool mustSpeakToPlayer = false;
[HideInInspector] public bool mustSpeakToEntity = false;
public int speakerIndex = -1;
IEnumerator dialogueCoroutine = null;
public void ChangeDialogueGraph(DialogueGraph _newDialogueGraph)
{
previousDialogueGraph = currentDialogueGraph;
currentDialogueGraph = _newDialogueGraph;
}
public void ChangeDialogueGraph(string newDialogueID)
{
DialogueGraph newDialogueGraph = DialoguesDatabase.GetItem(newDialogueID);
previousDialogueGraph = currentDialogueGraph;
currentDialogueGraph = newDialogueGraph;
}
[AIInvokable]
public void SpeakToAI(string _speakToID)
{
// Get the RckAI if possible
RckAI sTo = null;
CellsSystem.CellInformation.TryToGetAI(_speakToID, out sTo);
if(sTo != null)
{
IDialoguable[] ppl = { this, sTo };
DialogueLogic(ppl, currentDialogueGraph);
}
}
[AIInvokable]
public void SetSpeakerIndexToAI(string _rckAI, int _index)
{
// Get the RckAI if possible
RckAI sTo = null;
CellsSystem.CellInformation.TryToGetAI(_rckAI, out sTo);
if (sTo != null)
{
sTo.SetSpeakerIndex(_index);
}
}
public void DialogueLogic(IDialoguable[] entities, DialogueGraph dialogue)
{
dialogueCoroutine = (ExecuteDialogueNode(dialogue.GetEntryNode(), entities));
StartCoroutine(dialogueCoroutine);
}
[SerializeField] public IDialoguable[] entitiesTalkingWith;
public Node currentNode;
public IEnumerator ExecuteDialogueNode(Node _node, IDialoguable[] _entities)
{
// Trigger Events and Script
DialogueNode globalNode = (DialogueNode)_node;
RCKFunctions.ExecuteEvents(globalNode.events);
if (!string.IsNullOrEmpty(globalNode.resultScript))
RCKFunctions.ExecuteScript(globalNode.resultScript);
currentNode = _node;
entitiesTalkingWith = _entities;
for (int i = 0; i < _entities.Length; i++)
{
_entities[i].OnDialogueStarts(null);
}
if (_node is EntryNode)
{
EntryNode thisNode = (EntryNode)_node;
dialogueCoroutine = (ExecuteDialogueNode(thisNode.GetOutputPort("firstNode").Connection.node, _entities));
StartCoroutine(dialogueCoroutine);
}
else if (_node is ConditionsNode)
{
ConditionsNode thisNode = (ConditionsNode)_node;
bool conditionsResult = RCKFunctions.VerifyConditions(thisNode.conditions);
if (conditionsResult)
{
dialogueCoroutine = (ExecuteDialogueNode(thisNode.GetOutputPort("resultTrue").Connection.node, _entities));
StartCoroutine(dialogueCoroutine);
}
else
{
dialogueCoroutine = (ExecuteDialogueNode(thisNode.GetOutputPort("resultFalse").Connection.node, _entities));
StartCoroutine(dialogueCoroutine);
}
}
else if(_node is NPCDialogueLineNode)
{
NPCDialogueLineNode thisNode = (NPCDialogueLineNode)_node;
int speakerID = -1;
// reset anim
for (int i = 0; i < _entities.Length; i++)
{
if (thisNode.speakerID == _entities[i].GetSpeakerIndex())
{
speakerID = _entities[i].GetSpeakerIndex();
}
_entities[i].GetAnimator().SetTrigger("CancelDialogueAnimation");
}
for (int i = 0; i < _entities.Length; i++)
{
if (thisNode.speakerID == _entities[i].GetSpeakerIndex())
{
// Set look at
AILookAt lookAt = _entities[i].GetEntityGameObject().GetComponent<AILookAt>();
if (lookAt != null)
lookAt.ForceToLookAtTarget(_entities[thisNode.lookAtEntityID].GetEntityLookAtPos());
_entities[i].GetAnimator().ResetTrigger("CancelDialogueAnimation");
// We found who have to speak:
_entities[i].OnSpeakALine(thisNode);
// Play talking animation if choosen
if (!string.IsNullOrEmpty(thisNode.dialogueAnimationStr))
{
_entities[i].GetAnimator().CrossFade(thisNode.dialogueAnimationStr, .1f);
}
else
_entities[i].GetAnimator().SetTrigger("CancelDialogueAnimation");
// if player is close enough
if (!isInOfflineMode && !Player.RckPlayer.instance.isInConversation && Vector3.Distance(Player.RckPlayer.instance.transform.position, _entities[i].GetEntityGameObject().transform.position) <= RCKSettings.PLAYER_HEARS_NPC_DIALOGUES_DISTANCE)
RCKFunctions.DisplayHeardLine(thisNode.line, thisNode.lineTime);
// Play the audio if exists
if (thisNode.audioClip != null)
{
_entities[i].PlayAudioClip(thisNode.audioClip);
}
// Check for the timing of the line
bool outOfTime = false;
float startTime = Time.time;
// To wait until the line ends
while (!outOfTime)
{
// If the time expires
if (!thisNode.useLenghtOfClip)
{
if (Time.time - startTime >= thisNode.lineTime)
outOfTime = true;
}
else
{
if (Time.time - startTime >= thisNode.audioClip.length)
outOfTime = true;
}
yield return null;
}
_entities[i].StopAudio();
// Check what we have to do next
switch (thisNode.afterLine)
{
case AfterLine.NPC_DialogueLine:
// If we have to trigger another dialogue line, we just re-start this courutine with the new line
dialogueCoroutine = (ExecuteDialogueNode(thisNode.GetOutputPort("nextLine").Connection.node, _entities));
StartCoroutine(dialogueCoroutine);
yield break;
case AfterLine.PlayerQuestions:
/*
// Play listening animation if choosen
if (!string.IsNullOrEmpty(thisNode.dialogueAnimationListeningStr))
{
speakingTo.GetAnimator().CrossFade(thisNode.dialogueAnimationListeningStr, .1f);
}
if (thisNode.removePreviousQuestions)
{
foreach (Transform t in uiManager.playerQuestionsContent)
Destroy(t.gameObject);
}
else if (thisNode.questionsToRemove.Length > 0)
{
List<GameObject> toDelete = new List<GameObject>();
foreach (Transform t in uiManager.playerQuestionsContent)
{
for (int i = 0; i < thisNode.questionsToRemove.Length; i++)
{
if (t.GetComponent<PlayerQuestionUI>().question.qID == thisNode.questionsToRemove[i])
toDelete.Add(t.gameObject);
}
}
foreach (GameObject go in toDelete)
{
Destroy(go);
}
}
List<PlayerQuestionUI> questions = new List<PlayerQuestionUI>();
// Check if we have to add some new question
for (int i = 0; i < thisNode.playerQuestions.Count; i++)
{
int tempPosition = thisNode.playerQuestions[i].Position;
// In case, add them
GameObject newQuestion = Instantiate(uiManager.playerQuestionPrefab, uiManager.playerQuestionsContent);
if (tempPosition == 0)
tempPosition = i;
questions.Add(newQuestion.GetComponent<PlayerQuestionUI>());
newQuestion.GetComponent<PlayerQuestionUI>()
.Init(thisNode.playerQuestions[i], speakingTo,
(DialogueNode)thisNode.GetOutputPort("playerQuestions " + i).Connection.node,
thisNode.playerQuestions[i].Question, thisNode.playerQuestions[i].DeleteAfterAnswer,
tempPosition);
newQuestion.GetComponent<RectTransform>().SetSiblingIndex(tempPosition);
}
questions.Sort(SortByPosition);
for (int i = 0; i < questions.Count; i++)
{
questions[i].GetComponent<RectTransform>().SetSiblingIndex(questions[i].position);
}
// Set the UI to allow the player to ask questions
uiManager.npc_Line.gameObject.SetActive(false);
uiManager.playerQuestionsContainer.SetActive(true);
// Reset the scroll bar of the PlayerQuestionScrollView
if (uiManager.playerQuestionsContainer.GetComponentInChildren<Scrollbar>() != null)
uiManager.playerQuestionsContainer.GetComponentInChildren<Scrollbar>().value = 1f;
speakingTo.OnFinishedSpeakingALine();
// Sleect first for input system if gamepad
if (RckInput.isUsingGamepad)
questions[0].GetComponent<Button>().Select();
*/
yield break;
case AfterLine.EndDialogue:
_entities[i].OnDialogueEnds(this.gameObject);
// Reset the player status
isInConversation = false;
// Reset speaking to animator
_entities[i].GetAnimator().SetTrigger("CancelDialogueAnimation");
if (lookAt != null)
lookAt.StopForcingLookAtTarget();
speakingTo = null;
yield break;
case AfterLine.Continue:
dialogueCoroutine = (ExecuteDialogueNode(thisNode.GetOutputPort("output").Connection.node, _entities));
StartCoroutine(dialogueCoroutine);
break;
}
}
else
{
//AILookAt lookAt = _entities[i].GetEntityGameObject().GetComponent<AILookAt>();
//if (lookAt != null)
// lookAt.ForceToLookAtTarget(_entities[speakerID].GetEntityLookAtPos());
}
}
}
else if (_node is ChangeDialogueNode)
{
ChangeDialogueNode thisNode = (ChangeDialogueNode)_node;
if (!string.IsNullOrEmpty(thisNode.npcRef))
RCKFunctions.ChangeDialogueToRckAI(thisNode.npcRef, thisNode.newDialogue.ID);
StartCoroutine(ExecuteDialogueNode(thisNode.GetOutputPort("output").Connection.node, _entities));
}
else if(_node is EndNode)
{
for (int i = 0; i < _entities.Length; i++)
{
_entities[i].OnDialogueEnds(this.gameObject);
// Reset speaking to animator
_entities[i].GetAnimator().SetTrigger("CancelDialogueAnimation");
AILookAt lookAt = _entities[i].GetEntityGameObject().GetComponent<AILookAt>();
if (lookAt != null)
lookAt.StopForcingLookAtTarget();
}
entitiesTalkingWith = null;
}
yield return null;
}
[AIInvokable]
public void SetSpeakerIndex(int index)
{
speakerIndex = index;
}
public virtual void SpeakToEntity(IDialoguable target)
{
throw new System.NotImplementedException();
}
public bool CanDialogue()
{
return (dialogueSystemEnabled && isAlive && !isHostile && !isHostileAgainstPC && !isInCombat && !isInConversation && !isDrawingWeapon
&& (currentDialogueGraph != null || defaultDialogueGraph != null && isLoaded));
}
public string GetDialoguableName()
{
return entityName;
}
public virtual void OnDialogueStarts(GameObject target)
{
if(target != null)
speakingTo = target.GetComponent<IDialoguable>();
// Rotate the Npc to look at us
isInConversation = true;
if (target != null && aiLookAt != null)
aiLookAt.ForceToLookAtTarget(target.transform);
//npc.SetTarget(transform);
//npc.FaceTarget(true);
// Stop the agent
//npc.components.agent.isStopped = true;
}
public virtual void OnDialogueEnds(GameObject target)
{
isInConversation = false;
isTalking = false;
isListening = false;
speakingTo = null;
entitiesTalkingWith = null;
if (aiLookAt != null)
aiLookAt.StopForcingLookAtTarget();
UpdateConversationsAnimator();
m_Anim.SetTrigger("CancelDialogueAnimation");
// Reset the NPC state
//npcSpeaking.ResetStates();
if (!isHostile)
{
// Send the NPC to his path if he have got one
//if (npcSpeaking.PatrolPath != null)
// npcSpeaking.StartCoroutine("GoToPath");
}
}
public DialogueGraph GetCurrentDialogueGraph()
{
if (currentDialogueGraph != null)
return currentDialogueGraph;
else if(defaultDialogueGraph != null)
{
Debug.Log("AITalkative: " + this.gameObject.name + " has no currentDialogueGraph assigned, falling back to default");
return defaultDialogueGraph;
}
else
{
Debug.LogWarning("AITalkative: " + this.gameObject.name + " has no currentDialogueGraph or defaultDialogueGraph assigned.");
OnDialogueEnds(null);
return null;
}
}
public virtual void OnSpeakALine(NPCDialogueLineNode currentNode)
{
// Set the NPC state
isTalking = true;
isListening = false;
UpdateConversationsAnimator();
//npcSpeaking.state = NPC_State.Speaking;
}
public virtual void OnFinishedSpeakingALine()
{
// Set the NPC state
isTalking = false;
isListening = true;
UpdateConversationsAnimator();
}
public Transform GetEntityLookAtPos()
{
return entityFocusPart;
}
public void PlayAudioClip(AudioClip clip)
{
audioSource.PlayOneShot(clip);
}
public void StopAudio()
{
audioSource.Stop();
}
public override void Die()
{
base.Die();
}
public GameObject GetEntityGameObject()
{
return this.gameObject;
}
public bool IsTalking()
{
return isTalking;
}
public void UpdateConversationsAnimator()
{
if (!isAlive) return;
if (m_Anim != null)
{
m_Anim.SetBool("Talking", isTalking);
m_Anim.SetBool("Listening", isListening);
}
}
Animator IDialoguable.GetAnimator()
{
return m_Anim;
}
int IDialoguable.GetSpeakerIndex()
{
return speakerIndex;
}
public bool forceStopDialogue = false;
public void ForceToStopDialogue()
{
if(dialogueCoroutine != null)
StopCoroutine(dialogueCoroutine);
StopCoroutine(ExecuteDialogueNode(currentNode, entitiesTalkingWith));
isInConversation = false;
isTalking = false;
isListening = false;
speakingTo = null;
entitiesTalkingWith = null;
if (aiLookAt != null)
aiLookAt.StopForcingLookAtTarget();
UpdateConversationsAnimator();
m_Anim.SetTrigger("CancelDialogueAnimation");
OnDialogueEnds(null);
}
}
}