Page 1 of 1

Best way to keep track of played Conversations?

Posted: Wed Nov 01, 2023 8:41 am
by 2linescrossed
Hi! There's two things I want to create in particular, but I'll describe the first one first.

I'm currently building a game that has two primary means of displaying NPC conversations - through randomly playing conversations at a table, and conversations elsewhere which are reminiscent of the Fire Emblem 'Supports', being like miniature cutscenes that show two characters interacting.

I want to be able to save which conversations that the player has seen, and in the latter case, create a menu where players can re-view 'supports' that have played out. In the case of the supports involving player characters - I would also like to save choices made by the player so that re-viewing the cutscene does not let them change their decisions.

I imagine that the best way to handle this is through the usage of the Dialog Database's own variables, but I would like to know what the most efficient way of doing this would be. My previous solution is primitive and unrefined - being a second list keeping track of which conversations have been played.

In the case of the prior, I would also like to make it so that if a conversation is marked as 'seen', then it is less likely to appear again. I imagine I could do this easily if I mark the conversation with a variable, but I'm unsure where to put that variable specifically. Currently, the way I handle conversations is with the manager having a list of every conversation/Dialog in the game as scriptable objects, before narrowing it down to characters currently present in the scene.

Thanks in advance for suggestions.

Re: Best way to keep track of played Conversations?

Posted: Wed Nov 01, 2023 9:47 am
by Tony Li
Hi,

This custom functionality will require some scripting, but not too much script.

The approach that requires the least effort (at the expense of slightly larger saved game files) is to:

1. Tick the Dialogue Manager GameObject's Other Settings > Include SimStatus.

2. To check if a conversation has been played, check DialogueLua.GetSimStatus(conversationID, 0), such as:

Code: Select all

public bool HasConversationPlayed(string conversationTitle)
{
    var conversation = DialogueManager.masterDatabase.GetConversation(conversationTitle);
    if (conversation == null) return false; // (Invalid conversation title.)
    return DialogueLua.GetSimStatus(conversation.id, 0) == DialogueLua.WasDisplayed;
}

To give priority to conversations that haven't been played before, you could do something like this:

Code: Select all

public string ChooseConversation()
{
    var unplayed = new List<string>();
    var played = new List<string>();
    foreach (Conversation conversation in DialogueManager.masterDatabase.conversations)
    {
        if (conversation.Title.StartsWith("Support/")) continue; // (Ignore support conversations.)
        if (HasConversationPlayed(conversation.Title))
        {
            played.Add(conversation.Title);
        }
        else
        {
            unplayed.Add(conversation.Title);
        }
    }
    // Return a random unplayed conversation. If no unplayed, return a random already-played conversation.
    if (unplayed.Count > 0) return unplayed[Random.Range(0, unplayed.Count)];
    if (played.Count > 0) return played[Random.Range(0, played.Count)];
    return string.Empty; // (No available conversations.)
}

It's possible to track support conversations to replay them, but it's a little more work. Make a subclass of StandardUISubtitlePanel and override OnClick() [called when the player clicks a response] and ShowResponses(). Something like:

Code: Select all

// Dictionary keyed by conversation title.
// Each value is a conversation's dictionary where key is
// preceding subtitle entry's id and value is response entry's id.
private Dictionary<string, Dictionary<int, int>> choices = new Dictionary<string, Dictionary<int, int>>();

private Dictionary<int, int> GetCurrentConversationChoices()
{
    // Get current conversation's dictionary of conversation choices:
    Dictionary<int, int> conversationChoices;
    if (!choices.TryGetValue(DialogueManager.lastConversationStarted, out conversationChoices))
    {
        conversationChoices = new Dictionary<int, int>();
        choices[DialogueManager.lastConversationStarted] = conversationChoices;
    }
    return conversationChoices;
}

public override void OnClick(object data)
{
    var conversationChoices = GetCurrentConversationChoices();

    // Record response ID:
    var precedingID = DialogueManager.currentConversationState.subtitle.dialogueEntry.id;
    var responseID = (data as Response).destinationEntry.id;
    conversationChoices[precedingID] = responseID;

    base.OnClick(data);
}

public override void ShowResponses(Subtitle subtitle, Response[] responses, float timeout)
{
    // If we've recorded a response, "click" it instead of showing response menu:
    var conversationChoices = GetCurrentConversationChoices();
    var precedingID = DialogueManager.currentConversationState.subtitle.dialogueEntry.id;
    int responseID;
    if (conversationChoices.TryGetValue(precedingID, out responseID))
    {
        foreach (Response response in responses)
        {
            if (response.destinationEntry.id == responseID)
            {
                OnClick(response);
                return;
            }
        }
    }
    base.ShowResponses(subtitle, responses, timeout);
}