Hi,
Thanks for using Love/Hate as well as Quest Machine! And thank you for the feedback, too. Quest Machine's procedural generation was in development for over three years, consulting with AI researchers who do this stuff at the university level, and this is about as simple as it gets to be able to provide this degree of flexibility. One simpler prototype was more like Mad Libs, with prewritten template structures (kind of like Skyrim's Radiant quest system), but it really limited the uniqueness of the quests.
That said, here are some pointers:
If you haven't watched the procedural generation tutorial video, you may find it helpful:
Procedural Quest Generation.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmWhat I have right now is a simple Procedural Scout mission that is generated by an entity being in a domain. I made a custom script for the player to send a message to the messaging system that a new QuestEntity has been spotted. I'm using this if anyone is curious, it works quite well:
[snipped (thanks for sharing the code)]
My problem then is how do I control other procedural quests? What I would like to do is have a progression where a Monster is first Scouted (Quest1) then if that procedural quest is completed, a quest to go fight the monster is spawned. Now, I can use the GenerateQuest() command from a script in the QuestGeneratorEntity to generate a new script, but how would I take into account my previous Scout quest is already completed?
It's easier if you view the quest from the QuestGeneratorEntity's perspective. To reduce typing, I'll refer to the QuestGeneratorEntity as the "Questgiver."
When the Questgiver generates a quest, it doesn't look at what's actually in the world (i.e., the Unity scene). It works with an abstract representation called a world model. The world model has a list of entity types, which are abstract ideas of entities in the world. To generate the first quest, you want the Monster to be scoutable, so the world model should say that there's a scoutable monster in the domain. To generate the second quest, you want the questgiver to see the monster as attackable, so the world model should say that there's an attackable monster.
To implement this, define two EntityTypes: ScoutableMonster and AttackableMonster. ScoutableMonster should have a Scout action, and AttackableMonster should have an Attack action.
At design time, assign ScoutableMonster to the QuestEntity GameObject. When the player scouts the monster, change the QuestEntity's entity type to AttackableMonster. Do it in the same section of code you shared above. Example:
Code: Select all
qe.entityType = AttackableMonster; // Assumes you have a reference to the AttackableMonster EntityType asset.
What you're really doing is not changing the actual game world, but rather how the Questgiver perceives the world. That's the key to working with procedural generation.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmAlso what is the preferred way to generate a new procedural quest once one has been completed?
Start dialogue by calling the Questgiver's QuestGeneratorEntity.StartDialogueWithPlayer() method. It's like QuestGiver.StartDialogueWithPlayer() but generates a new quest first if needed.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmAlso, is there a way to add more specificity to quest conditions for the Procedural Quests. Although sometimes using the faction relations and all that stuff is cool it would be nice if there was a simpler way to filter it. I'm thinking of like "RedPirate was Scouted" as a condition.
Questgivers use two types of conditions.
First, they use urgency functions to choose which entity type to generate a quest about. The demo uses the Threat Urgency Function, which checks faction values. But you're welcome to use different urgency functions. Questgivers don't care how the functions work; just want a return value so they can choose the entity type with the highest value.
For example, another built-in urgency function is the Drive Alignment Urgency Function. Let's say you're making an art heist game. You could define drives such as Price, Impressionism, and Realism. Maybe one questgiver only cares about Price, while another loves Impressionism and hates Realism. If you assign drive values to the questgivers and the paintings to be stolen, the questgivers will choose different targets based on how well the drives align. Quest Machine's Templates folder has a starter template script if you want to define your own urgency functions.
The second type of condition questgivers use is checking whether certain entity types are in or out of the world model. This is defined in the Action asset's Requirements section. (Actions technically also support custom requirement code, too, but it's not exposed in the editor yet.) Going back to the art heist example, you could make the Steal Painting action require that the painting is in the museum domain -- or, better yet,
not in the questgiver's personal domain -- since it wouldn't make sense for the questgiver to ask the player to steal a painting from the questgiver's own domain. But you can also define abstract domains to represent additional information in the world model. I'll skip the details because this wall of text is probably already visible from space.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmAlthough I see what you're doing with this package, and I really want to make it work, I am finding it very confusing to do simple things. There also seems to be a gap between quests that are linear and pre-built and quests that are totally procedural built up from entities internal states. Is there a way to make a quest template? Like "Scout one of three given options, when that is completed, go fight that monster chosen in step 1". Something that would allow me to use some quest structure but have more control over what is getting triggered?
That's actually on the roadmap. It's not available yet, though.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmAlso, just as a way of feedback, I find the heavy reliance on the messaging system for simple things (eg collect a coin) to be somewhat error prone and difficult to debug,. It would also be nice to be able to set a DEBUG message flag for a single entity rather then the whole system at once.
Great idea! I'll try to get that into the next release.
dylandev wrote: ↑Sat Dec 15, 2018 6:24 pmThanks in advance, I've been following the development of Love/Hate for a long time and am looking forward to this new package adding additional functionality!
Hang in there. It takes a while to grok it all, but that's because it does something that no other commercial systems do right now.