Hi,
BaddyDan wrote:1) An auto button, which triggers a flag of sorts, telling the dialogue system to continue the text automatically based on the voice acting audio length of each dialogue node. For nodes where there are no voice acting, I want it to continue to the next node automatically based on the text length of the current node.
I'll offer a couple ideas (mostly based on the good advice Arcanor already offered) that you can play around with to best fit your needs.
The easiest workflow is to set the Dialogue Manager's
Default Sequence to:
Code: Select all
AudioWait(entrytag); Delay({{end}})
If your dialogue entry nodes don't define their own sequences in their
Sequence fields, they'll use this Default Sequence.
Both commands,
AudioWait and
Delay, run in parallel as soon as the dialogue entry is shown, since neither has an "@
time" bit at the end. (If you wanted to play an explosion sound at the 1-second mark, for example, you could use the command Audio(Explosion)@1.)
The Delay command waits for a duration specified by the special keyword '{{end}}'. The Dialogue System computes the value of the '{{end}}' keyword based on the text length and the Dialogue Manager's Subtitle Settings.
The AudioWait command waits until the audio clip is done. If you're using lipsync, this might be a different command such as
SALSA, depending on how you're doing lipsync.
The keyword 'entrytag' is special. Every dialogue entry has a unique
entrytag. If you name each voice acting file according to its entrytag, the Default Sequence above will automatically find it. This way you don't have to manually enter a different filename in each dialogue entry's Sequence field.
Voice acting almost always runs longer than the value of '{{end}}', so I think it's fine to include both commands (AudioWait and Delay) in the same sequence. If AudioWait doesn't find a corresponding audio clip (i.e., no voice acting available), it will log a warning to the console and do nothing. The duration will then fall to the Delay command.
If you don't want to use entrytag, you can always set each one manually in the dialogue entry node's Sequence field.
BaddyDan wrote:2) A skip button, which triggers the dialogue system to automatically (and immediately) click through the nodes if they have been previously read at any point of the game (regardless of save file). The skip button will untrigger as soon as it reaches a node that has not been previously read.
"Regardless of save file" may be the hard part. I'll get to that in a bit.
One approach is to use
SimStatus and set nodes'
False Condition Action to
Passthrough.
SimStatus records an extra piece of information for every dialogue entry node. It increases the memory footprint of the Lua environment and the size of saved games, so it's something to keep in mind for really huge dialogue databases. The Dialogue System's data structure is based on Chat Mapper. SimStatus comes from Chat Mapper and is best documented in the
Chat Mapper manual. Expand
Scripting with Lua and click on
Conditions and Scripts.
The SimStatus for every dialogue entry node starts as 'Untouched'. If the node has been read, its SimStatus is marked 'WasDisplayed'. If the node was offered in a response menu but not selected yet, its SimStatus is marked 'WasOffered'.
You can set the nodes'
Conditions fields to check the SimStatus value, such as:
Code: Select all
Dialog[4].SimStatus ~= 'WasDisplayed'
This means, "this node is only true if it
hasn't been read yet." Since this is an advanced feature, the Lua wizard doesn't include a drop-down for it. You'll have to type it manually. The '4' is the dialogue entry node's ID, which is shown in the inspector.
Then set the
False Condition Action to
Passthrough. By default, it's set to
Block, which stops evaluation. When it's
Passthrough, the conversation will skip through the links until it finds a node whose Conditions are true (i.e., not read yet).
There are two things to consider with this:
1. SimStatus is included in saved game files. If you use the Dialogue System's save system, when you load an older game it will reset SimStatus to the values in that older game.
2. It may be a bit of work to set this up, since you need to specify the dialogue entry node's ID in each Conditions field.
An as alternative, you could add a short script to the Dialogue Manager that has an
OnConversationLine method. The Dialogue System calls this method before showing each line. In your method, you could:
1. Check if the dialogue entry has already been read. If so, set the sequence to 'None()', which skips the line.
2. Otherwise mark the entry as read.
Here's a rough sketch of the code. You'll have to provide your own implementation of HasRead() and MarkAsRead(). You can record this info to some kind of permanent storage that's independent of saved games.
Code: Select all
using UnityEngine;
using PixelCrushers.DialogueSystem;
public class MyScript : MonoBehaviour {
public void OnConversationLine(Subtitle subtitle) {
if (HasRead(subtitle.dialogueEntry)) {
subtitle.sequence = "None()"; // Already read, so skip.
} else {
MarkAsRead(subtitle.dialogueEntry);
}
}
}