Quest Generation - Domain outside of quest giver scene

Announcements, support questions, and discussion for Quest Machine.
Post Reply
c166
Posts: 38
Joined: Fri Oct 14, 2022 11:08 pm

Quest Generation - Domain outside of quest giver scene

Post by c166 »

Hey Tony,

I've had a crack at interpreting the code for the quest generator entity, and just want to confirm a few things to make sure that I've got it right to make sure that I'm going in the right direction.

My end goal is:
  • Quests generated in town scene
  • Quest urgency based on scenes that are not the town scene (e.g. dungeon scene)
  • Multiple world states of interest to be considered by the quest giver (e.g. state of town, dungeon, forest)
After above is sorted next steps would be:
  • Urgency changes based on time since last quest of the same entity type has been completed (i.e. prioritize quests that haven't been done before).
Now my interpretation of QM functionality (let me know if I've misinterpreted anything):
The QM Quest Generator Entity determines what quest gets generated based on a series of inputs including the world model. The world model, based on my read of it is limited to the current scene and searches within the domain area to get a count (to make sure that it doesn't ask you to kill more than what exists). So if I have a quest giver in town, and then I want to quests to be generated based on the number of enemies in a different scene (dungeon); that isn't possible out of the box.

I can see that you're able to set the min, but the max seems to be programmatically determined via that world model for Quest Generator Entities (with no manual override option -> e.g. randomize between a min and a max, independent of the world). You ARE able to set a random number between min/ max using QuestBuilder though.

I am thinking that it may be possible to "hack" the Quest Generator Entities calculations via referencing a dictionary (string/ count for enemy_type/ #) that I'll save in the dungeon scene and then "load" it into the town scene which tracks the monster/ enemy count. Defaulting to a min/ max independent of the world state if the other scene hasn't been loaded yet (such that the saved dictionary would be blank). I.e. manipulate the "Fact" data so that the urgency is based on a "modified" world model (i.e. world model from outside the scene).

I know that the there is a QuestBuilder class, but I actually want most of the functionality of the Quest Generator Entity (count + urgency based on world state in another scene), am I better off trying to work out how to "hack" the world state? Or am I better off starting from the QuestBuilder? Let me know if I'm missing some other functionality that would suit as well.

Best Regards,
C
User avatar
Tony Li
Posts: 22001
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by Tony Li »

Hi,

>So if I have a quest giver in town, and then I want to quests to be generated based on the number of enemies in a different scene (dungeon); that isn't possible out of the box.

If the quest giver is in town, it can generate quests based on entities in a different scene. However, this requires some coding.

Your quest giver will have a QuestGeneratorEntity component in addition to a QuestGiver component. When the QuestGeneratorEntity generates a quest, it first creates a WorldModel by calling its BuildWorldModelFromDomains() method, which adds the entities that are in the current scene's domains. (But only those domains that are assigned to the QuestGeneratorEntity to observe.)

You can also assign your own C# method to QuestGeneratorEntity.updateWorldModel. The QuestGeneratorEntity will call this C# method after running BuildWorldModelFromDomains(). In your C# method, you can add or remove entities from the WorldModel -- for example, adding entities that are in the dungeon.

How you keep track of which entities are in the dungeon is up to you. Some games have a separate data structure, independent from scenes, that keeps track of what's in each scene. When a scene is loaded, this data structure instantiates objects into the scene. Alternatively, you could record the list of entities that are in a scene just prior to leaving the scene, so that you can reference that list from other scenes.

Side note: QuestGeneratorEntity.BuildWorldModel() and BuildWorldModelFromDomains() are both virtual, so you can create a subclass to override their behavior if you want. But the usual way to accomplish what you want is to simply assign a method to updateWorldModel.
c166
Posts: 38
Joined: Fri Oct 14, 2022 11:08 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by c166 »

Hey Tony,

Thanks for that - good to know that the intent of modifying the Worldmodel is a reasonable way to approach it & better that there is already a place where I can add an additional method in `updateWorldModel`. It'll likely take me a while to work out how to actually implement it in practice, but knowing that the direction is right is good.

On a semi-related matter; when I was setting up the generated quests; I found that the Icon Image update for the quest breaks after leaving the scene and then returning to the scene. Note that I'm using the InventoryEngine + EasySave3 integration if that matters.

From my digging, the icon gets updated when the quest is generated via InventoryEngineRewardSystem.DetermineReward() which modifies the quest contents by setting the itemIcon.image to the rewardItem.item.Icon (Inventory Engine). As the QM instance (which persists between scenes) would hold the Quest information, I would have expected the Icon to still exist between scenes as that's "saved" inside the Quest data (and the rest of the quest information IS saved).

The quest continues to track as expected, and the rewards are issued as expected (i.e. after I leave the scene, I can do the quest, and the journal updates + the quest generator doesn't give me a new quest) -> so it just seems that the Icon update isn't saved to that Quest object. Am wondering whether I'm missing a step? (e.g. QM needs to explicitly "load" the item icons like it does the EntityType icons?)

Steps:
  • Get the generated quest (domains etc all set-up fine)
icon_exists.PNG
icon_exists.PNG (43.39 KiB) Viewed 1753 times
  • Reward Icon previews as expected
journal_icon_exists.PNG
journal_icon_exists.PNG (23.77 KiB) Viewed 1753 times
  • Journal Icons as expected
After leaving the scene:
  • Icon not in journal
missing_journal.PNG
missing_journal.PNG (36 KiB) Viewed 1753 times
  • Icon missing on completion
quest_completion_missing_icons.PNG
quest_completion_missing_icons.PNG (13.26 KiB) Viewed 1753 times
Item appears in inventory with icon after quest completion
  • Icons appear in inventory
item_icon_appears_inventory.PNG
item_icon_appears_inventory.PNG (11.34 KiB) Viewed 1753 times
Best Regards,
C
User avatar
Tony Li
Posts: 22001
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by Tony Li »

Hi,

Assign your icon images to your quest database:

qdbImages.png
qdbImages.png (40.29 KiB) Viewed 1705 times

It works this way so Quest Machine can reload a saved game from scratch that contains procedurally-generated quests.
c166
Posts: 38
Joined: Fri Oct 14, 2022 11:08 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by c166 »

Hey Tony,

TLDR theory: there are two quest databases, the entity type image files are being added into the correct one; while the manually added images are being added to the wrong one. This may be due to one of the integration systems (suspect dialogue system hijacking QM). The entity type images load between scenes, so it seems that information has been saved somewhere (unknown). The "Town Quest" Database contains the manually added image references but is suspiciously short and the save times don't match when additional entity type has been added (i.e. doesn't seem to be getting auto-updated). Assume that QM uses that if it is standalone but one of the integrations has ported the entity_type image data to another Quest Database (which correctly ports when it's used as expected - i.e. without the manual additions/ just for entity_type icons).

Much longer discovery + images below:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I have assigned my sprites to the entity type images section, but it still loads up as blank once I exit the scene. The other images, which have been picked up by the scan entity type instead of being manually placed there are showing up as expected after switching scenes and back (i.e. the quest giver sprite).
QM_with_images.PNG
QM_with_images.PNG (32.08 KiB) Viewed 1682 times
Also once I reload Unity (close unity instance and re-open), the entity type sprites disappear from the town quest image list. But the manually placed sprites do not (i.e. they remain in the list). The knight sprite (quest giver)/ knight entity type continues to load as expected after switching scenes even though it's not on the list. Possible that is intended behavior, i.e. once an image has been added to the quest database, the image drops from the list automatically -> which may imply that the manually placed sprites are NOT being added to the database for some reason (since they're still on the list).
reloaded_scene.PNG
reloaded_scene.PNG (30 KiB) Viewed 1682 times
I decided to then check the actual "Town Quests" asset and it is suspiciously empty.
town_quest_text.PNG
town_quest_text.PNG (32.15 KiB) Viewed 1682 times
Looking at name of the files inside that file based on the asset database guid; I got manually added sprite names. So it seems that it IS being saved to the "Town Quests" assets -> HOWEVER, that is not the location from which QM actually reads the data from. I am not sure what that file is, since there isn't another obvious candidate in Assets/ExtraAssets where the Town Quests.asset file is in my editor. It MAY be due to the dialogue system integration hijacking quest machine and using a different file/ asset that's stored in a different location?? (any clues where that may be?)
manual_image_debug.PNG
manual_image_debug.PNG (9.3 KiB) Viewed 1682 times
In addition, the save times don't match up with when I added a new entity type and loaded it into Quest Machine (this also works as expected and now I have 4 entity types). The time of the "Town Quests" asset doesn't update and seems to be the timestamp pf when I manually added those images the first time which seems to support that theory.
town_quest_asset_file.PNG
town_quest_asset_file.PNG (3.95 KiB) Viewed 1682 times
If the above isn't enough to provide more clues for exploration (or don't match what you know), I can try to replicate it in a standalone version of QM with the same integrations that I've got loaded, though that may take a while.

Best Regards,
C
User avatar
Tony Li
Posts: 22001
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by Tony Li »

Hi,

Are you using the "Scan Entity Types..." button? If so, this may be due to a bug in Unity's Undo system. It's addressed in the upcoming version 1.2.48. Here's a patch in the meantime:

QM_QuestDatabaseEditorPatch_2024-08-11.unitypackage
c166
Posts: 38
Joined: Fri Oct 14, 2022 11:08 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by c166 »

Hey Tony,

Thanks for the patch, that has stopped the icons from disappearing between loads. On a positive note, I did manage to get the quest generator to create quests based on entities from different scenes via a save/ load system (probably a much neater way to do it than what I did, -> I saved to a dictionary<string, dictionary<string, int>> so I could serialize the save data) and then created functions to convert that to a Fact format (also required modifying the Fact file to have a blank fact that didn't require constructors -> due to my lack of understanding here). I also had a persistent object that would build the world state for ALL entities/ domains OnSceneEnable (to then save into that dictionary).

The other issue doesn't appear affected though, and after tinkering some more, it seems that it may have to do with the inventory engine integration. I've created a standalone project and have been able to replicate that behavior using only quest machine and inventory engine components (Dialogue system + easy save + integrations were imported as well but not used). I have added the icons into the Quest Machine quest database.

I've sent you an email with a link to the google drive with the zipped project, along with two videos + more detail.

I've also discovered additional behaviour where it looks like the inventory engine reward is only provided to the first quest after adding code to generate a quest manually. In the first video, the icons seem to generate twice as it doesn't recognize the first quest being in the database after exiting/ re-entering the scene (though the first quest's icon's are NULL, the details still exist). In the second video (manual generation via button down), only the first quest has the inventory engine designated rewards. This only seems to be an issue when there are multiple reward systems (not an issue in my own standalone game where I ONLY use the inventory reward system). This has no impact on my use-case but I'm just flagging it.

Best Regards,
C
User avatar
Tony Li
Posts: 22001
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by Tony Li »

Thanks for sending the repro project. To summarize our email thread, for the icon issue I provided a patch containing a fix that will be in QM version 1.2.48. For rewards, when a generated quest chooses a reward from the Inventory Engine reward script, it removes the reward from the list. You can increase the number of items in the list or their point values so the first quest doesn't use up all of the rewards. And you can customize/subclass the script to make other changes such as not removing items from the list when they're offered as rewards.
c166
Posts: 38
Joined: Fri Oct 14, 2022 11:08 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by c166 »

Hey Tony,

Yup, thanks for that - and apologies for the late reply here. Thanks again for your help, the patch that you sent worked fine on my end - and the reward preview icons in the quest journal/ quest giver are preserved between scenes now. It's good to see that you're adding it to the updated version of QM, so hopefully it'll be useful to others as well.

And can confirm that the second issue was on my end, and me not understanding the intent of the code. To clarify for future readers, I was using the inventory engine integration (awesome stuff). The rewards list for items from inventory engine is a limited reward set, and it's a randomized deduction from that list (points get deducted until all rewards get used up). The rewards from the inbuilt QM (exp and coins) are not limited in the same fashion (they use a different mechanism).

I personally wanted the rewards to refresh after a certain period - and so my intention is to adjust the code in the integration script so that it takes a COPY of the original to draw rewards, and then reset the rewards after that period. I haven't gotten around to it yet though, but I'll post the code here when I do (assuming I remember -> knee deep on a different problem atm :? ).

Best Regards,
C
User avatar
Tony Li
Posts: 22001
Joined: Thu Jul 18, 2013 1:27 pm

Re: Quest Generation - Domain outside of quest giver scene

Post by Tony Li »

Glad to help! I imagine restocking the rewards is probably somewhat project-specific, but it'll be welcome if you want to share your code with other Inventory Engine users.
Post Reply