The Problem
I am currently making a 2D top-down RPG game in which player can accept quests from NPC, I need my quest to have some kind of reference to the NPC who gave player the quest, so player can return to when quest is completed and perform some interaction whit the NPC, the reference should be easy to save and load when needed. I am currently want to save all my quests into csv file for easy editing. So I am looking for advice on what to choose as a reference.
My Thoughts
-
Using a reference to the NPC node
In this way I can easily access to NPCs build-in functions to do something when quest is completed. But saving a node to file, it seems I can only use Resource to do the job, and it just don`t feel good to do it this way.
-
Using NPCs name which is a String as a reference
In this way saving the quest data will be easier but harder to access to the NPC node, I will have to build another system to get access to the node itself which does
not make it easier.
-
Using a quest list that is local to each NPC
In this case saving and loading the quests could be done along with saving and loading the NPC itself when changing game levels, when player interact with a specific NPC it can access the quests that is specific to that NPC thus achieve reference in a âsoftâ way.
Looking for any advice
I hope I express my thoughts clear enough, any advice will be helpful.
1 Like
You could implement it by adding a node to Autoload for handling the nodes you want.
And you could also call functions (letâs say for example, adding a quest to the player characterâs journal or for mark certain quest completed) or changing values to variables anywhere you want because of this.
(eg.: get_node(/root/TheNode).add_quest("Quest name") or something)
Doesnât this go in the help category?
I would do the following:
- Create an autoload to handle all of the quest system
- Saving the NPCâs id (instead of name) as a string
- When the game loads, each NPC can make a call to the quest system, and register itself
What does the register do? it passes the id and reference to itself, so it can ârebuildâ the id-node dictionary, helping you have the references in a âdecoupledâ way.
The id-registration approach (@huevoquilmes) is the right direction, but there are a few traps worth knowing since we built exactly this:
Use a stable string ID, not the node name. Node names change and collide. Give each NPC a quest_giver_id: String that never changes â thatâs what you serialize, in both CSV (quest definitions) and your save file (quest progress).
Separate two layers â the original post mixes them:
- Quest definitions (what quests exist, giver id, objectives) â static data, CSV is fine
- Quest progress (accepted/completed, counters) â runtime state, save as JSON per slot
Never serialize node references. At runtime, keep a registry instead:
# QuestManager (autoload)
var givers := {} # id -> node
func register_giver(id: String, node: Node) -> void:
givers[id] = node
func unregister_giver(id: String) -> void:
givers.erase(id)
Traps the existing replies skip:
- NPC
_ready() order isnât guaranteed â if you restore quest state before NPCs register, lookups fail. Restore progress after the scene is up, or queue lookups and resolve deferred.
- NPCs must
unregister in _exit_tree(), or a re-entered scene double-registers and you hold stale references.
- If a quest is completed but its giver isnât in the tree (different level), the âreturn to NPCâ interaction must survive that â store
turn_in_id in progress and resolve it whenever the NPC registers.
This is exactly the design we ended up with in a quest plugin I built for Godot 4 (.NET) â LiteQuest does the id-registry + JSON progress save part out of the box. But even rolling your own, the three traps above are the ones that bite in week 2.