Procedural generation based on data and not presence?

Announcements, support questions, and discussion for Quest Machine.
darkmajki
Posts: 18
Joined: Sat Apr 13, 2019 7:30 am

Re: Procedural generation based on data and not presence?

Post by darkmajki »

Great news and thank you once again for all the support. Good luck in your ludum dare :) .
darkmajki
Posts: 18
Joined: Sat Apr 13, 2019 7:30 am

Re: Procedural generation based on data and not presence?

Post by darkmajki »

Hey It's me again :D.

I was waiting for you to post the update for the questbuilder to be able to create a questbuilder from a quest(although I thought you needed to do something more complex I wouldn't have waited for just a set constructor :) ) anyways I came to the conclusion that using quest builder for most of my quests is the best option and not just for the branching quests, I was doing a test and it was really a fast and dirty test to see how it will work step by step and can't seem to find what my problem is. Here is the main code.

Code: Select all

private void OnQuestGenerated(Quest quest)
    {
        QuestBuilder questbuilder = new QuestBuilder(quest);
        if (quest.title.value.StartsWith("Polymorph"))
        {
            
            QuestNode nodeWhereToAddFrom = quest.nodeList[quest.nodeList.Count/2];
            
            var counter = questbuilder.AddCounter("stuffs", 0, 0, 5, false, QuestCounterUpdateMode.Messages);
            var conditionNode = questbuilder.AddConditionNode(nodeWhereToAddFrom, "ID11", "NAME11", ConditionCountMode.All);
            
            
            questbuilder.AddCounterCondition(conditionNode, "Find it", CounterValueConditionMode.AtLeast, 5);
            var counterMessageEvent = new QuestCounterMessageEvent(null, new StringField("Find it"), new StringField("stuff"), QuestCounterMessageEvent.Operation.ModifyByLiteralValue, 1);
            counter.messageEventList.Add(counterMessageEvent);
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.Dialogue), questbuilder.CreateBodyContent("DIALOGUE"));
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.Journal), questbuilder.CreateBodyContent("DIALOGUE"));
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.HUD), questbuilder.CreateBodyContent("DIALOGUE"));
        }
        Debug.Log(quest.nodeList.Count);
        quest = questbuilder.ToQuest();
        //questGenerators[1].gameObject.GetComponent<QuestGiver>().AddQuest(quest);
        // And add it to the QuestGiver:
        //GetComponent<QuestGiver>().AddQuest(myQuest);
    }
    
Now my problem is that the node is added to the quest but the node isn't present in the Quest Editor window nor does it make the quest stop( because there isn't really anything to collect really that would satisfy the node condition, maybe this has something to do with the problem?) it just goes to the success node. I am testing currently on the demo scene and your quest builder example works fine. I've tried adding the quest to the quest giver but that doesn't fix the problem. I've just tested it with the exact same code from the Quest builder and it's still the same: The text and probably the node is added where is supposed to but also the text of the last(return to giver node) and going to the giver is finishing the quest although there is supposed to be another node that needs to be finished. So how would I be able to both add the node visually to the graph and also fix my problem?
User avatar
Tony Li
Posts: 22107
Joined: Thu Jul 18, 2013 1:27 pm

Re: Procedural generation based on data and not presence?

Post by Tony Li »

Hi,

I'll check this today and reply by back the end of the day.
User avatar
Tony Li
Posts: 22107
Joined: Thu Jul 18, 2013 1:27 pm

Re: Procedural generation based on data and not presence?

Post by Tony Li »

What versions of Unity and Quest Machine are you using?

Can you please try Quest Machine 1.1.8, which released on May 17?

Here's a slightly modified version that works fine with Quest Machine 1.1.8 in Unity 2019.1:
ExtraNodeTest.cs

Code: Select all

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PixelCrushers;
using PixelCrushers.QuestMachine;

public class ExtraNodeTest : MonoBehaviour
{
    private void Start()
    {
        GetComponent<QuestGeneratorEntity>().generatedQuest += OnQuestGenerated;
    }

    private void OnQuestGenerated(Quest quest)
    {
        QuestBuilder questbuilder = new QuestBuilder(quest);
        if (quest.title.value.StartsWith("Polymorph"))
        {

            QuestNode nodeWhereToAddFrom = quest.nodeList[2]; // [TL] quest.nodeList[quest.nodeList.Count / 2];

            var counter = questbuilder.AddCounter("stuffs", 0, 0, 5, false, QuestCounterUpdateMode.Messages);
            var conditionNode = questbuilder.AddConditionNode(nodeWhereToAddFrom, "ID11", "NAME11", ConditionCountMode.All);

            //[TL] Move node to the right so it doesn't overlap an existing node:
            conditionNode.canvasRect = new Rect(conditionNode.canvasRect.x + QuestNode.DefaultNodeWidth + 20, conditionNode.canvasRect.y, QuestNode.DefaultNodeWidth, QuestNode.DefaultNodeHeight);

            //[TL] You don't have to manually create a message event object. This is how to add a counter condition:
            //questbuilder.AddCounterCondition(conditionNode, "Find it", CounterValueConditionMode.AtLeast, 5);
            questbuilder.AddCounterCondition(conditionNode, "stuffs", CounterValueConditionMode.AtLeast, 5);
            questbuilder.AddCounterMessageEvent("stuffs", string.Empty, "Got", "Stuffs", QuestCounterMessageEvent.Operation.ModifyByLiteralValue, 1);
            //var counterMessageEvent = new QuestCounterMessageEvent(null, new StringField("Find it"), new StringField("stuff"), QuestCounterMessageEvent.Operation.ModifyByLiteralValue, 1);
            //counter.messageEventList.Add(counterMessageEvent);
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.Dialogue), questbuilder.CreateBodyContent("DIALOGUE Stuffs")); //[TL]
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.Journal), questbuilder.CreateBodyContent("JOURNAL Stuffs"));
            questbuilder.AddContents(conditionNode.GetStateInfo(QuestNodeState.Active).GetContentList(QuestContentCategory.HUD), questbuilder.CreateBodyContent("HUD Get Stuffs"));

            //[TL] Link conditionNode to success:
            var successNodeIndex = quest.nodeList.FindIndex(node => StringField.Equals(node.id, "success"));
            Debug.Log("successNodeIndex=" + successNodeIndex);
            conditionNode.childIndexList.Add(successNodeIndex);
        }
        Debug.Log(quest.nodeList.Count);
        quest = questbuilder.ToQuest();
        //questGenerators[1].gameObject.GetComponent<QuestGiver>().AddQuest(quest);
        // And add it to the QuestGiver:
        //GetComponent<QuestGiver>().AddQuest(myQuest);
    }
}
I can put it in an example scene with an earlier version of Unity if you'd like to download a fully running example.
darkmajki
Posts: 18
Joined: Sat Apr 13, 2019 7:30 am

Re: Procedural generation based on data and not presence?

Post by darkmajki »

I am working on the latest version and it works now as it should. Thank you for your help.
User avatar
Tony Li
Posts: 22107
Joined: Thu Jul 18, 2013 1:27 pm

Re: Procedural generation based on data and not presence?

Post by Tony Li »

Glad to help!
darkmajki
Posts: 18
Joined: Sat Apr 13, 2019 7:30 am

Re: Procedural generation based on data and not presence?

Post by darkmajki »

Hey,

As I am developing the quests system off and on sorry if it's hard for you to follow. But I am having problems right now and don't know whats the best way to approach them. Basically I have couple of towns procedurally generated(including the citizens living in them). And well let's say that there is a doctor in there, which has some domains that he cares about, which a doctor in another city wouldn't care about(i.e. a medicine shortage in one town doesn't interest a doctor living in another town). Now the whole thing that's making this difficult for me is the procedural nature of this npcs and towns so there is no way for me to know beforehand. So what would you suggest in order for me to handle this? Is creating an instance of Scriptable Object of Entity type for the npc and domain for the town setting it's values through code than saving/loading it in json would be the best way to go about this or is there a way to do it within quest machine?
User avatar
Tony Li
Posts: 22107
Joined: Thu Jul 18, 2013 1:27 pm

Re: Procedural generation based on data and not presence?

Post by Tony Li »

Hi,

You can do that, but managing ScriptableObject instances is a bit of a headache because you need to remember to destroy them. You might find it more convenient to predefine a pool of EntityType and DomainType assets. As you generate towns, grab unused assets from the pool.
darkmajki
Posts: 18
Joined: Sat Apr 13, 2019 7:30 am

Re: Procedural generation based on data and not presence?

Post by darkmajki »

Regarding the more convenient way, what exactly do you mean by having a pool of entity/domain objects? Do you mean like creating duplicates at runtime from a base entity, or creating towntype1,towntype2...n in the inspector and then choosing them at random? As I see it the first idea might be problematic when saving/loading and the second just will be more error-prone or would be time-consuming and require like a 100 entities(which is like the max npc + cities I expect the game to have) defined beforehand. Or did you had another idea in mind?
User avatar
Tony Li
Posts: 22107
Joined: Thu Jul 18, 2013 1:27 pm

Re: Procedural generation based on data and not presence?

Post by Tony Li »

I was thinking of the second: predefine 50 EntityType assets and 50 DomainType assets. That's the time-consuming part, but you only need to do it once to create the assets. You could write a short editor script to create them.

Then write a short pooling script with two methods: Get(), which returns an unused asset and marks it as being used, and Release(), which marks the asset as no longer being used. When you want to set up a new NPC, call the script to get an unused EntityType asset and DomainType asset. When you dispose of the NPC, release both assets back to the script.

It's just a suggestion. You can instantiate new ScriptableObjects at runtime if you prefer.
Post Reply