Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Announcements, support questions, and discussion for Quest Machine.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by Tony Li »

I just PM'ed you the beta version of 1.1.0. Please import it or the patch above. This is almost certainly the bug I mentioned above. After importing, check your Quest Machine GameObject. Make sure Generator Settings > Default Player Domain Type is assigned a value. It should default to the asset Plugins / Pixel Crushers / Quest Machine / Data / Domains / PlayerDomain.
GorkaGames
Posts: 178
Joined: Fri Sep 21, 2018 8:38 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by GorkaGames »

ok, solved, I eliminated the polimorfism action, as I didn't set up anything for that, and the giver choose the kill quest
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by Tony Li »

With the patch or 1.1.0b1, the polymorph action should work again.
GorkaGames
Posts: 178
Joined: Fri Sep 21, 2018 8:38 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by GorkaGames »

Starting to create procedural quests....

I'm a bit lost trying to figure out how to design the elements () for getting a treasure in a chest in a wreck.
I have set up the entities, domain, etc... but not sure how to set up the Urgency, drives (wealth?), factions, etc....
Thanks,
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by Tony Li »

Hi,

Procedural quests are a little complicated to get started with. I added an example to the tutorial assets:

QuestMachineTutorialAssets_WithProceduralChestQuest.unitypackage

To play it, you must also import some free assets from the Asset Store:
The files in are Quest Machine Tutorials / 05 Procedural Quest. The scene is Supplemental Chest Example.

The quest giver will generate a quest to bring him the chest of gold from the mysterious circle.

It uses these assets:
  • DomainType_Circle: Represents the mysterious circle.
  • EntityType_Chest: Represents a chest of gold.
  • Faction_Chest: Represents the chest's faction.
  • Action_Retrieve: The action to move the chest from its current domain to the player's inventory domain.
  • EntityType_QuestGiver: Represents the quest giver.
  • Greed: Drive type.
The first step of procedural quest generation is to make a list of the entities that the NPC knows about. In this case, the NPC watches the Mysterious Circle domain, which contains a chest. So the NPC knows about the chest.

The second step is to run urgency functions on all of the entities. The NPC's faction relationship to the chest is -100. The chest has a Threat urgency function. You can think of it like this: The fact that the chest is out there in the world, and not in the NPC's possession, is a "threat" to the NPC's happiness. So the NPC will choose to make a quest about the chest.

The third step is to choose an action. The NPC will choose the Retrieve action, which removes the chest from the world -- that is, it removes the "threat" to his happiness.

Quest Machine doesn't have an inventory system, so the example action is simplified. In your game, you could define a new action to actually give the chest to the NPC. The action could listen for a message like "GaveToNPC"+"Chest".

The quest giver's Greed drive is +100. Action_Retrieve has a Motive whose Greed is +100. The quest giver will choose this motive because it's similar to his Greed drive.

The last step is to make the plan. The Retrieve action has no requirements, so the plan is only one step.

Once you get the basic quest working, you can make it more complicated. For example, maybe the Retrieve action only works if there is an open chest. To change from a closed chest to an open chest, the player must complete a "Cast Spell" action. To cast the spell, the player must first get the spell scroll. To get the spell scroll, the player must defeat a wizard. Then the plan might consist of these actions:
  • Defeat: Wizard (Effect: adds scroll to world)
  • Get: Scroll (Requirement: scroll is in world. Effect: adds scroll to player)
  • Cast: Scroll (Requirement: player has scroll. Effect: remove closed chest; add open chest)
  • Retrieve: Chest
GorkaGames
Posts: 178
Joined: Fri Sep 21, 2018 8:38 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by GorkaGames »

Thanks very much for the detailed explanation and demo!!! I'll start to study it
PS: I sent you an PM this afternoon related to the save system, please tell me if you received it, as I saw it on the outbox for long time before leaving to sent messages.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by Tony Li »

Hi,

I forgot to mention that "threat" isn't the only way to compute urgency. You can make a copy of UrgencyFunctionTemplate.cs and define your own urgency function. For example, it could return the value of the item multiplied by the NPC's Greed drive value.
GorkaGames wrote: Wed Nov 21, 2018 7:30 pmPS: I sent you an PM this afternoon related to the save system, please tell me if you received it, as I saw it on the outbox for long time before leaving to sent messages.
I think it was related to saving Invector inventory. Did you get this reply?

"If you’re using an Invector controller that has an inventory, such as the Shooter Template, define the scripting symbol USE_INVECTOR_INVENTORY. To do this, select Edit > Project Settings > Player and scroll down to Other Settings.


This will make it available. Not all Invector templates have inventory, so it has to be enabled like this or it could cause compiler errors for other customers."
GorkaGames
Posts: 178
Joined: Fri Sep 21, 2018 8:38 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by GorkaGames »

Yes I did, but I replayed again :). I'll put here the message:

OK, everything works fine and the Invector inventory saves and loads fine...
But related to saving and loading the procedural states.....

--------------------------------------------------------------------------------------------

I get this error when anytime I have saved any procedural quest with this code You gave me one month ago to save automatically the quest states: (At the end of the message)

And once the scene restarts and loads, i get the following error: and whats worst, I lose all the quest on my journal (I guess is because it loads empty or wrong because this error)

ArgumentNullException: Value cannot be null.
Parameter name: key
System.Collections.Generic.Dictionary`2[TKey,TValue].FindEntry (TKey key) (at <f2e6809acb14476a81f399aeb800f8f2>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].ContainsKey (TKey key) (at <f2e6809acb14476a81f399aeb800f8f2>:0)
PixelCrushers.QuestMachine.QuestMachine.GetImage (System.String imageName) (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest Machine/QuestMachine.cs:503)
PixelCrushers.QuestMachine.IconQuestContent.OnAfterProxyDeserialization () (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Subasset/Quest Content/IconQuestContent.cs:82)
PixelCrushers.QuestMachine.QuestContentProxy.CreateList (PixelCrushers.QuestMachine.QuestContentProxy[] contentListProxy) (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Serialization/QuestProxy.cs:518)
PixelCrushers.QuestMachine.QuestProxy.CopyTo (PixelCrushers.QuestMachine.Quest quest) (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest/Quest Serialization/QuestProxy.cs:114)
PixelCrushers.QuestMachine.QuestListContainer.ApplyData (System.String data) (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest MonoBehaviours/Quest List/QuestListContainer.cs:332)
PixelCrushers.QuestMachine.QuestJournal.ApplyData (System.String data) (at Assets/Plugins/Pixel Crushers/Quest Machine/Scripts/Quest MonoBehaviours/Quest List/QuestJournal.cs:128)
PixelCrushers.SaveSystem.ApplySavedGameData (PixelCrushers.SavedGameData savedGameData) (at Assets/Plugins/Pixel Crushers/Common/Scripts/Save System/SaveSystem.cs:497)
UnityEngine.Debug:LogException(Exception)
PixelCrushers.SaveSystem:ApplySavedGameData(SavedGameData) (at Assets/Plugins/Pixel Crushers/Common/Scripts/Save System/SaveSystem.cs:502)
PixelCrushers.<LoadSceneCoroutine>c__Iterator4:MoveNext() (at Assets/Plugins/Pixel Crushers/Common/Scripts/Save System/SaveSystem.cs:599)


--------------------------------------------- code -------------------

using UnityEngine;
using PixelCrushers;
using PixelCrushers.QuestMachine;

public class QuestNodeControllerSaver : MonoBehaviour, PixelCrushers.IMessageHandler
{
public int Slot = 0;

void OnEnable()
{ // Let me know when quest states change.
MessageSystem.AddListener(this, QuestMachineMessages.QuestStateChangedMessage, string.Empty);
}

void OnDisable()
{ // Unregister when disabling script.
MessageSystem.RemoveListener(this);
}

public void OnMessage(MessageArgs messageArgs)
{

//Recoge Cambio en el estado de una Quest
//QuestState state = (QuestState)messageArgs.values[1];
//Recoge Cambio en el estado del nodo de una Quest
QuestNodeState state = (QuestNodeState)messageArgs.values[1];

StringField nodeID = messageArgs.values[0] as StringField;
if (nodeID == null)
{
return; // Is main quest.
}
//Comprueba si es activa la quest
//if (state == QuestState.Active)
//Comprueba si es activa el nodo de la quest
if (state == QuestNodeState.Active)
{ // Quest Node became active. Save game.
//Guardamos en el slot 0, que lo reservamos para guardar los estados de cambios de Nodos / quests
int SlotPrincipal = 0;
PlayerPrefs.SetString("slot_saveName_" + SlotPrincipal, System.DateTime.Now.ToString());
PlayerPrefs.SetInt("slot_" + SlotPrincipal, SlotPrincipal);
PlayerPrefs.SetString("slot_sceneName_" + SlotPrincipal, "CrazyPiratesOpenWorld");
//Save
SaveSystem.SaveToSlot(SlotPrincipal);

//Y además Grabación de BackUp:

Slot +=1; // Use 5 slots, wrapping around back to 1.
if (Slot > 5) Slot = 1;
//Pone la fecha
PlayerPrefs.SetString("slot_saveName_" + Slot, System.DateTime.Now.ToString());
//POne el numero de slot
PlayerPrefs.SetInt("slot_" + Slot, Slot);
//Nombre de escena
PlayerPrefs.SetString("slot_sceneName_" + Slot, "CrazyPiratesOpenWorld");
//Save
SaveSystem.SaveToSlot(Slot);

Debug.Log("Save Quest Node");
if (Invector.vCharacterController.vHUDController.instance)
Invector.vCharacterController.vHUDController.instance.ShowText("Save Quest Node");
}
}
}

UPDATE:
After some research.....
- The error fires always when I REload the scene, so I think is not the origin of the issue.
- We may need to filter the nodeID not to save when is a Procedural Quest, as when I load the game its empty, but I don't know how to do it. Can you help me to filter it?
Should be on the above code somehow.
User avatar
Tony Li
Posts: 22104
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by Tony Li »

Hi,

This is a bug. I will try to have it fixed by tomorrow.

In the meantime, this should prevent the error: QM109_Patch2018-11-21.unitypackage
GorkaGames
Posts: 178
Joined: Fri Sep 21, 2018 8:38 pm

Re: Quest Machine Tutorials: Dialogue System Integration, Procedural Quests

Post by GorkaGames »

Tony Li wrote: Wed Nov 21, 2018 9:58 pm Hi,

This is a bug. I will try to have it fixed by tomorrow.

In the meantime, this should prevent the error: QM109_Patch2018-11-21.unitypackage
Ok, I'll wait till the fix, please let me know when is done to test it.
Post Reply