Page 1 of 1
Show a different Dialogue UI if conversation has only one line
Posted: Fri Feb 25, 2022 7:13 am
by OddMan2
Hi again,
i am trying to achieve this behavior:
- if a conversation has more than one line, use the standard ui
- if a conversation has only one subtitle, (something like "i can't speak now.") use the bark ui or a different dialogue ui with speech bubbles in world space.
what is the best way to achieve this?
I saw the extra sequencer command to switch ui, but the demo is outdated and is broken
Thank you!
Re: Show a different Dialogue UI if conversation has only one line
Posted: Fri Feb 25, 2022 8:42 am
by Tony Li
Hi,
You'll first need to determine whether there's one line or multiple:
Code: Select all
bool HasMoreThanOneLine(string conversation, Transform actor, Transform conversant)
{
var conversationModel = new ConversationModel(DialogueManager.masterDatabase, conversation, actor, conversant, false, null);
var startNode = conversationModel.firstState;
if (!startNode.hasAnyResponses)
{
return false; // The conversation has *no* lines.
}
else
{
var firstTextNode = conversationModel.GetState(startNode.firstNPCResponse.destinationEntry);
if (firstTextNode.hasAnyResponses)
{
return true; // The conversation has more than one line.
}
else
{
return false; // The conversation has only one line.
}
}
}
[EDIT: Fixed a whole bunch of typos.]
Then you can bark or start a conversation based on that info:
Code: Select all
if (HasMoreThanOneLine(conversation, actor, conversant))
{
DialogueManager.StartConversation(conversation, actor, conversant);
}
else
{
DialogueManager.Bark(conversation, conversant);
}
Re: Show a different Dialogue UI if conversation has only one line
Posted: Fri Feb 25, 2022 12:18 pm
by OddMan2
Thank you!
I tried it and it works, but for some reason the HasMoreThanOneLine check always returns false, i don't understand why.
maybe you can help understand where the error is ?
i made a subclass of DialogueSystemTriggerInteractableTarget (i am using opsive UCC)
here's the code:
Code: Select all
using UnityEngine;
using Opsive.UltimateCharacterController.Traits;
using Opsive.UltimateCharacterController.Character;
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.Networking;
#endif
namespace PixelCrushers.DialogueSystem.OpsiveUCCSupport
{
/// <summary>
/// This is a Dialogue System Trigger that serves as a UCC Interactable target.
/// </summary>
public class CustomDialogueSystemTriggerInteractableTarget : DialogueSystemTriggerInteractableTarget, IInteractableTarget, IInteractableMessage
{
bool HasMoreThanOneLine(string conversation, Transform actor, Transform conversant)
{
var conversationModel = new ConversationModel(DialogueManager.masterDatabase, conversation, actor, conversant, false, null);
var startNode = conversationModel.firstState;
if (startNode.hasAnyResponses)
{
Debug.Log("no lines");
return false; // The conversation has *no* lines.
}
else
{
var firstTextNode = conversationModel.GetState(startNode.firstNPCResponse.destinationEntry);
if (firstTextNode.hasAnyResponses)
{
Debug.Log("first line: " + firstTextNode.firstNPCResponse);
return true; // The conversation has more than one line.
}
else
{
Debug.Log("first line: " + firstTextNode.firstNPCResponse);
return false; // The conversation has only one line.
}
}
}
protected override void DoConversationAction(Transform actor)
{
if (string.IsNullOrEmpty(conversation)) return;
if (replace && DialogueManager.isConversationActive)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Stopping current active conversation " + DialogueManager.lastConversationStarted + " and starting " + conversation + ".", this);
DialogueManager.StopConversation();
}
if (exclusive && DialogueManager.isConversationActive)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Conversation triggered on " + name + " but skipping because another conversation is active.", this);
}
else
{
var actorTransform = Tools.Select(conversationActor, actor);
var conversantTransform = conversationConversant;
if (conversantTransform == null)
{
var conversationAsset = DialogueManager.MasterDatabase.GetConversation(conversation);
var conversationConversantActor = (conversationAsset != null) ? DialogueManager.MasterDatabase.GetActor(conversationAsset.ConversantID) : null;
var registeredTransform = (conversationConversantActor != null) ? CharacterInfo.GetRegisteredActorTransform(conversationConversantActor.Name) : null;
conversantTransform = (registeredTransform != null) ? registeredTransform : this.transform;
}
if (skipIfNoValidEntries && !DialogueManager.ConversationHasValidEntry(conversation, actorTransform, conversantTransform, startConversationEntryID))
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Conversation triggered on " + name + " but skipping because no entries are currently valid.", this);
}
else
{
if (stopConversationIfTooFar || showCursorDuringConversation || pauseGameDuringConversation)
{ // Trigger may not be on actor or conversant, so we need to hook into these events:
DialogueManager.instance.conversationStarted += OnConversationStartAnywhere;
DialogueManager.instance.conversationEnded += OnConversationEndAnywhere;
}
if (HasMoreThanOneLine(conversation, actorTransform, conversantTransform))
{
Debug.Log("Conversation has more than one line, start conversation");
DialogueManager.StartConversation(conversation, actorTransform, conversantTransform, startConversationEntryID);
}
else
{
Debug.Log("Conversation has only one line, barking");
DialogueManager.Bark(conversation, conversantTransform);
}
earliestTimeToAllowTriggerExit = Time.time + MarginToAllowTriggerExit;
if (stopConversationIfTooFar)
{
monitorDistanceCoroutine = StartCoroutine(MonitorDistance(DialogueManager.currentActor));
}
}
}
}
// These methods run even if this DialogueSystemTrigger isn't on the actor or conversant.
// They handle monitoring distance, showCursorDuringConversation and pauseGameDuringConversation.
private void OnConversationStartAnywhere(Transform actor)
{
DialogueManager.instance.conversationStarted -= OnConversationStartAnywhere;
if (showCursorDuringConversation)
{
wasCursorVisible = Cursor.visible;
savedLockState = Cursor.lockState;
StartCoroutine(ShowCursorAfterOneFrame());
}
if (pauseGameDuringConversation && string.Equals(DialogueManager.lastConversationStarted, conversation))
{
didIPause = true;
preConversationTimeScale = Time.timeScale;
Time.timeScale = 0;
}
}
private void OnConversationEndAnywhere(Transform actor)
{
DialogueManager.instance.conversationEnded -= OnConversationEndAnywhere;
StopMonitoringConversationDistance();
if (showCursorDuringConversation)
{
Cursor.visible = wasCursorVisible;
Cursor.lockState = savedLockState;
}
if (pauseGameDuringConversation && didIPause)
{
didIPause = false;
Time.timeScale = preConversationTimeScale;
}
}
}
}
Re: Show a different Dialogue UI if conversation has only one line
Posted: Fri Feb 25, 2022 3:57 pm
by Tony Li
Wow, I think I just broke a record for number of typos in a single code blurb. Sorry about that. I fixed the typos in the HasMoreThanOneLine() method in my post above.
Re: Show a different Dialogue UI if conversation has only one line
Posted: Sat Feb 26, 2022 9:46 am
by OddMan2
Thank you, now it correctly falls back to the bark ui.
i have to stop working on this things late at night, i always miss very obvious typos!
If i can make a suggestion, i think it would be nice to add this behavior as a checkbox on the default dialogue system trigger's start conversation action
here's the full code in case someone reads this and wants to use it
Code: Select all
using UnityEngine;
using Opsive.UltimateCharacterController.Traits;
using Opsive.UltimateCharacterController.Character;
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.Networking;
#endif
namespace PixelCrushers.DialogueSystem.OpsiveUCCSupport
{
/// <summary>
/// This is a Dialogue System Trigger that serves as a UCC Interactable target.
/// </summary>
public class CustomDialogueSystemTriggerInteractableTarget : DialogueSystemTriggerInteractableTarget, IInteractableTarget, IInteractableMessage
{
bool HasMoreThanOneLine(string conversation, Transform actor, Transform conversant)
{
var conversationModel = new ConversationModel(DialogueManager.masterDatabase, conversation, actor, conversant, false, null);
var startNode = conversationModel.firstState;
if (!startNode.hasAnyResponses)
{
return false; // The conversation has *no* lines.
}
else
{
var firstTextNode = conversationModel.GetState(startNode.firstNPCResponse.destinationEntry);
if (firstTextNode.hasAnyResponses)
{
return true; // The conversation has more than one line.
}
else
{
return false; // The conversation has only one line.
}
}
}
protected override void DoConversationAction(Transform actor)
{
if (string.IsNullOrEmpty(conversation)) return;
if (replace && DialogueManager.isConversationActive)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Stopping current active conversation " + DialogueManager.lastConversationStarted + " and starting " + conversation + ".", this);
DialogueManager.StopConversation();
}
if (exclusive && DialogueManager.isConversationActive)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Conversation triggered on " + name + " but skipping because another conversation is active.", this);
}
else
{
var actorTransform = Tools.Select(conversationActor, actor);
var conversantTransform = conversationConversant;
if (conversantTransform == null)
{
var conversationAsset = DialogueManager.MasterDatabase.GetConversation(conversation);
var conversationConversantActor = (conversationAsset != null) ? DialogueManager.MasterDatabase.GetActor(conversationAsset.ConversantID) : null;
var registeredTransform = (conversationConversantActor != null) ? CharacterInfo.GetRegisteredActorTransform(conversationConversantActor.Name) : null;
conversantTransform = (registeredTransform != null) ? registeredTransform : this.transform;
}
if (skipIfNoValidEntries && !DialogueManager.ConversationHasValidEntry(conversation, actorTransform, conversantTransform, startConversationEntryID))
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Conversation triggered on " + name + " but skipping because no entries are currently valid.", this);
}
else
{
if (stopConversationIfTooFar || showCursorDuringConversation || pauseGameDuringConversation)
{ // Trigger may not be on actor or conversant, so we need to hook into these events:
DialogueManager.instance.conversationStarted += OnConversationStartAnywhere;
DialogueManager.instance.conversationEnded += OnConversationEndAnywhere;
}
if (HasMoreThanOneLine(conversation, actorTransform, conversantTransform))
{
Debug.Log("Conversation has more than one line, start conversation");
DialogueManager.StartConversation(conversation, actorTransform, conversantTransform, startConversationEntryID);
}
else
{
Debug.Log("Conversation has only one line, barking");
DialogueManager.Bark(conversation, conversantTransform);
}
earliestTimeToAllowTriggerExit = Time.time + MarginToAllowTriggerExit;
if (stopConversationIfTooFar)
{
monitorDistanceCoroutine = StartCoroutine(MonitorDistance(DialogueManager.currentActor));
}
}
}
}
// These methods run even if this DialogueSystemTrigger isn't on the actor or conversant.
// They handle monitoring distance, showCursorDuringConversation and pauseGameDuringConversation.
private void OnConversationStartAnywhere(Transform actor)
{
DialogueManager.instance.conversationStarted -= OnConversationStartAnywhere;
if (showCursorDuringConversation)
{
wasCursorVisible = Cursor.visible;
savedLockState = Cursor.lockState;
StartCoroutine(ShowCursorAfterOneFrame());
}
if (pauseGameDuringConversation && string.Equals(DialogueManager.lastConversationStarted, conversation))
{
didIPause = true;
preConversationTimeScale = Time.timeScale;
Time.timeScale = 0;
}
}
private void OnConversationEndAnywhere(Transform actor)
{
DialogueManager.instance.conversationEnded -= OnConversationEndAnywhere;
StopMonitoringConversationDistance();
if (showCursorDuringConversation)
{
Cursor.visible = wasCursorVisible;
Cursor.lockState = savedLockState;
}
if (pauseGameDuringConversation && didIPause)
{
didIPause = false;
Time.timeScale = preConversationTimeScale;
}
}
}
}
Re: Show a different Dialogue UI if conversation has only one line
Posted: Sat Feb 26, 2022 11:04 am
by Tony Li
Thanks for sharing the code! It may be a bit of an edge case for the basic Dialogue System Trigger, so I'll direct people here if anyone wants to do the same in the future.